IQ.Pilot Release Commit @ 2b39aa6
This commit is contained in:
@@ -198,7 +198,7 @@ def get_checksum_state(dbc_name: str) -> ChecksumState | None:
|
||||
return ChecksumState(8, -1, 7, -1, False, SignalType.FCA_GIORGIO_CHECKSUM, fca_giorgio_checksum)
|
||||
elif dbc_name.startswith("comma_body"):
|
||||
return ChecksumState(8, 4, 7, 3, False, SignalType.BODY_CHECKSUM, body_checksum)
|
||||
elif dbc_name.startswith("tesla_model3_party"):
|
||||
elif dbc_name.startswith(("tesla_model3_party", "tesla_model3_vehicle")):
|
||||
return ChecksumState(8, -1, 0, -1, True, SignalType.TESLA_CHECKSUM, tesla_checksum, tesla_setup_signal)
|
||||
elif dbc_name.startswith("psa_"):
|
||||
return ChecksumState(4, 4, 7, 3, False, SignalType.PSA_CHECKSUM, psa_checksum)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import math
|
||||
import numbers
|
||||
import time
|
||||
from collections import defaultdict, deque
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
@@ -154,7 +155,7 @@ class CANParser:
|
||||
self.last_nonempty_nanos: int = 0
|
||||
self._last_update_nanos: int = 0
|
||||
|
||||
def _add_message(self, name_or_addr: str | int, freq: int | None = None) -> None:
|
||||
def _add_message(self, name_or_addr: str | int, freq: int | None = None, ignore_counter: bool = False) -> None:
|
||||
if isinstance(name_or_addr, numbers.Number):
|
||||
msg = self.dbc.addr_to_msg.get(int(name_or_addr))
|
||||
else:
|
||||
@@ -171,16 +172,15 @@ class CANParser:
|
||||
self.vl_all[msg.name] = self.vl_all[msg.address]
|
||||
self.ts_nanos[msg.address] = {s: 0 for s in signal_names}
|
||||
self.ts_nanos[msg.name] = self.ts_nanos[msg.address]
|
||||
self.dat[msg.address] = b""
|
||||
self.dat[msg.name] = b""
|
||||
|
||||
state = MessageState(
|
||||
address=msg.address,
|
||||
name=msg.name,
|
||||
size=msg.size,
|
||||
signals=list(msg.sigs.values()),
|
||||
ignore_alive=freq is not None and math.isnan(freq),
|
||||
ignore_counter=ignore_counter,
|
||||
)
|
||||
state.first_seen_nanos = time.monotonic_ns()
|
||||
if freq is not None and freq > 0:
|
||||
state.frequency = freq
|
||||
else:
|
||||
|
||||
@@ -67,6 +67,32 @@ class TestCanParserPacker:
|
||||
parser.update([t, [msg]])
|
||||
assert parser.can_valid
|
||||
|
||||
def test_lazy_add_not_ignore_alive(self):
|
||||
"""
|
||||
Accessing an undeclared message via parser.vl[...] lazily adds it via
|
||||
_add_message(key) with the default freq=None, which is NOT the same as
|
||||
declaring it with math.nan (ignore_alive=True). It's treated as "assume
|
||||
~1Hz, must be seen within ~10s" — so if that message is never fed, the
|
||||
parser is permanently invalid. Declaring an optional/rarely-sent message
|
||||
with math.nan (or gating the .vl[...] read entirely) is required to avoid
|
||||
this; see iqdbc/car/volkswagen/carstate.py's Diagnose_1/EPB_1 bugs.
|
||||
"""
|
||||
parser = CANParser(TEST_DBC, [], 0)
|
||||
assert parser.can_valid
|
||||
|
||||
# lazily add STEERING_CONTROL by reading it, without ever declaring it
|
||||
# or feeding any CAN data for it
|
||||
_ = parser.vl["STEERING_CONTROL"]
|
||||
state = parser.message_states[parser.dbc.name_to_msg["STEERING_CONTROL"].address]
|
||||
assert not state.ignore_alive
|
||||
|
||||
# never becomes valid again, no matter how many times it's checked
|
||||
# (can_valid debounces over MAX_BAD_COUNTER reads before flipping false)
|
||||
for _ in range(MAX_BAD_COUNTER):
|
||||
parser.can_valid
|
||||
for _ in range(20):
|
||||
assert not parser.can_valid
|
||||
|
||||
def test_parser_updated_list(self):
|
||||
msgs = [("CAN_FD_MESSAGE", 10), ]
|
||||
parser = CANParser(TEST_DBC, msgs, 0)
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
||||
|
||||
# Support Information for {{all_car_docs | length}} Known Cars
|
||||
|
||||
|{{ExtraCarsColumn | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}|
|
||||
|---|---|---|{% for _ in range((ExtraCarsColumn | length) - 3) %}{{':---:|'}}{% endfor +%}
|
||||
{% for car_docs in all_car_docs %}
|
||||
|{% for column in ExtraCarsColumn %}{{car_docs.get_extra_cars_column(column)}}|{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
# Types of Support
|
||||
|
||||
**iqdbc 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!
|
||||
|
||||
## Upstream
|
||||
|
||||
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.
|
||||
|
||||
## Under Review
|
||||
|
||||
A vehicle under review is one for which software support has been merged into upstream openpilot, but hasn't yet been
|
||||
tested for drive quality and conformance with [comma safety guidelines](https://github.com/commaai/openpilot/blob/master/docs/SAFETY.md).
|
||||
This is a normal part of the development and quality assurance process. This vehicle will not work when upstream
|
||||
openpilot is installed, but custom forks may allow their use.
|
||||
|
||||
## Custom
|
||||
|
||||
Vehicles in this category are not considered plug-and-play. Software support is included in upstream openpilot, but
|
||||
these vehicles might not have a harness in the comma store, or the physical install might be at an unusual or cumbersome
|
||||
location, or they might need unusual configuration after install. These vehicles will not work with release builds of
|
||||
openpilot, but depending on the situation, development builds or custom forks may allow their use.
|
||||
|
||||
### SecOC cars with recoverable keys
|
||||
|
||||
For a small subset of SecOC-protected vehicles, tools may be available in the community to recover the SecOC keys. These
|
||||
tools, and the recovery process, are not part of openpilot. If supplied with a valid SecOC key, development builds or
|
||||
custom forks may work with these vehicles. Release builds of openpilot don't support SecOC.
|
||||
|
||||
## Dashcam
|
||||
|
||||
Dashcam vehicles have software support in upstream openpilot, but will go into "dashcam mode" at startup and will not
|
||||
engage. This may be due to known issues with driving safety or quality, or it may be a work in progress that isn't yet
|
||||
ready for safety and quality review.
|
||||
|
||||
## Community
|
||||
|
||||
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/).
|
||||
|
||||
Some notable works-in-progress:
|
||||
* Honda
|
||||
* 2022-24 Acura RDX, commaai/iqdbc#1967
|
||||
* Camera ACC stability improvements, commaai/iqdbc#2192
|
||||
* Alpha longitudinal stability improvements, commaai/iqdbc#2347 and commaai/iqdbc#2165
|
||||
|
||||
## Incompatible
|
||||
|
||||
### CAN Bus Security
|
||||
|
||||
Vehicles with CAN security measures, such as AUTOSAR Secure Onboard Communication (SecOC) are not usable with openpilot
|
||||
unless the owner can recover the message signing key and implement CAN message signing. Examples include certain newer
|
||||
Toyota, and the GM Global B platform.
|
||||
|
||||
### 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.
|
||||
@@ -238,6 +238,42 @@ struct CarState {
|
||||
fuelTankLevelL @63 :Float32; # raw fuel tank level in liters (konn3kt: VW PQ Kombi_1.Tankinhalt)
|
||||
batteryDetails @65 :BatteryDetails;
|
||||
|
||||
# carrotpilot HKG extension state
|
||||
vCluRatio @68 :Float32;
|
||||
logCarrot @69 :Text;
|
||||
softHoldActive @70 :Int16;
|
||||
activateCruise @71 :Int16;
|
||||
latEnabled @72 :Bool;
|
||||
pcmCruiseGap @73 :Int16;
|
||||
speedLimit @74 :Float32;
|
||||
speedLimitDistance @75 :Float32;
|
||||
gearStep @76 :Int16;
|
||||
tpms @77 :Tpms;
|
||||
useLaneLineSpeed @78 :Float32;
|
||||
leftLatDist @79 :Float32;
|
||||
rightLatDist @80 :Float32;
|
||||
leftLongDist @81 :Float32;
|
||||
rightLongDist @82 :Float32;
|
||||
carrotCruise @83 :Int16;
|
||||
leftLaneLine @84 :Int16;
|
||||
rightLaneLine @85 :Int16;
|
||||
datetime @86 :UInt64;
|
||||
leftRearLongDist @87 :Float32;
|
||||
rightRearLongDist @88 :Float32;
|
||||
leftRearLatDist @89 :Float32;
|
||||
rightRearLatDist @90 :Float32;
|
||||
trailerConnected @91 :Bool;
|
||||
ureaGauge @92 :Float32;
|
||||
evModeActive @93 :Bool;
|
||||
evModeValid @94 :Bool;
|
||||
|
||||
struct Tpms {
|
||||
fl @0 :Float32;
|
||||
fr @1 :Float32;
|
||||
rl @2 :Float32;
|
||||
rr @3 :Float32;
|
||||
}
|
||||
|
||||
struct BatteryDetails {
|
||||
capacity @0 :Float32;
|
||||
charge @1 :Float32;
|
||||
@@ -310,8 +346,8 @@ struct CarState {
|
||||
|
||||
# deprecated
|
||||
errorsDEPRECATED @0 :List(OnroadEventDEPRECATED.EventName);
|
||||
gasDEPRECATED @3 :Float32; # this is user pedal only
|
||||
brakeLightsDEPRECATED @19 :Bool;
|
||||
gas @3 :Float32; # this is user pedal only
|
||||
brakeLights @19 :Bool;
|
||||
steeringRateLimitedDEPRECATED @29 :Bool;
|
||||
canMonoTimesDEPRECATED @12: List(UInt64);
|
||||
canRcvTimeoutDEPRECATED @49 :Bool;
|
||||
@@ -349,6 +385,18 @@ struct RadarData @0x888ad6581cf0aacb {
|
||||
|
||||
# some radars flag measurements VS estimates
|
||||
measured @6 :Bool;
|
||||
|
||||
vLead @7 :Float32; # m/s
|
||||
aLead @8 :Float32; # m/s^2
|
||||
jLead @9 :Float32; # m/s^3
|
||||
radarSource @10 :RadarSource;
|
||||
|
||||
enum RadarSource {
|
||||
frontRadar @0;
|
||||
scc @1;
|
||||
corner235 @2;
|
||||
corner180 @3;
|
||||
}
|
||||
}
|
||||
|
||||
enum ErrorDEPRECATED {
|
||||
@@ -404,6 +452,8 @@ struct CarControl {
|
||||
brake @1: Float32; # [0.0, 1.0]
|
||||
torqueOutputCan @8: Float32; # value sent over can to the car
|
||||
speed @6: Float32; # m/s
|
||||
jerk @9: Float32; # m/s^3
|
||||
aTarget @10: Float32; # m/s^2
|
||||
|
||||
enum LongControlState @0xe40f3a917d908282{
|
||||
off @0;
|
||||
@@ -439,6 +489,12 @@ struct CarControl {
|
||||
leadFollowTime @11: Float32;
|
||||
leadDistance @12: Float32;
|
||||
driverUnresponsive @13: Bool;
|
||||
activeCarrot @14: Int16;
|
||||
leadRelSpeed @15: Float32;
|
||||
leadDPath @16: Float32;
|
||||
leadRadar @17: Int16;
|
||||
modelDesire @18: Int16;
|
||||
atcDistance @19: Float32;
|
||||
|
||||
# not used with the dash, TODO: separate structs for dash UI and device UI
|
||||
audibleAlert @5: AudibleAlert;
|
||||
@@ -502,6 +558,7 @@ struct CarParams {
|
||||
enableBsm @56 :Bool; # blind spot monitoring
|
||||
flags @64 :UInt32; # flags for car specific quirks
|
||||
alphaLongitudinalAvailable @71 :Bool;
|
||||
extFlags @79 :UInt32; # carrotpilot HKG extension flags
|
||||
|
||||
minEnableSpeed @7 :Float32;
|
||||
minSteerSpeed @8 :Float32;
|
||||
@@ -538,14 +595,9 @@ struct CarParams {
|
||||
steerLimitAlert @28 :Bool;
|
||||
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
|
||||
|
||||
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
|
||||
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
|
||||
steerControlType @34 :SteerControlType;
|
||||
radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out
|
||||
stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary
|
||||
stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop
|
||||
startAccel @32 :Float32; # Required acceleration to get car moving
|
||||
startingState @70 :Bool; # Does this car make use of special starting state
|
||||
|
||||
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
|
||||
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
|
||||
@@ -603,7 +655,7 @@ struct CarParams {
|
||||
kpV @1 :List(Float32);
|
||||
kiBP @2 :List(Float32);
|
||||
kiV @3 :List(Float32);
|
||||
kfDEPRECATED @6 :Float32;
|
||||
kf @6 :Float32;
|
||||
deadzoneBPDEPRECATED @4 :List(Float32);
|
||||
deadzoneVDEPRECATED @5 :List(Float32);
|
||||
}
|
||||
@@ -776,6 +828,11 @@ struct CarParams {
|
||||
maxSteeringAngleDegDEPRECATED @54 :Float32;
|
||||
longitudinalActuatorDelayLowerBoundDEPRECATED @61 :Float32;
|
||||
stoppingControlDEPRECATED @31 :Bool; # Does the car allow full control even at lows speeds when stopping
|
||||
radarTimeStepDEPRECATED @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
|
||||
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
|
||||
enableDsuDEPRECATED @5 :Bool; # driving support unit
|
||||
vEgoStarting @59 :Float32;
|
||||
startAccel @32 :Float32;
|
||||
startingState @70 :Bool;
|
||||
vEgoStoppingDEPRECATED @29 :Float32;
|
||||
stoppingDecelRateDEPRECATED @52 :Float32;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
|
||||
cached_params: CarParamsT | None,
|
||||
fixed_fingerprint: str | None) -> tuple[str | None, dict, str, list[CarParams.CarFw], CarParams.FingerprintSource, bool]:
|
||||
fixed_fingerprint = fixed_fingerprint or os.environ.get('FINGERPRINT', "")
|
||||
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False)
|
||||
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) or bool(fixed_fingerprint)
|
||||
disable_fw_cache = os.environ.get('DISABLE_FW_CACHE', False)
|
||||
ecu_rx_addrs = set()
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@ from iqdbc.car.chrysler import chryslercan
|
||||
from iqdbc.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags, RAM_DT
|
||||
from iqdbc.car.interfaces import CarControllerBase
|
||||
|
||||
from iqdbc.lvbs.car.chrysler.carcontroller_ext import CarControllerExt
|
||||
from iqdbc.lvbs.car.chrysler.iq_carcontroller import IQCarController
|
||||
from iqdbc.lvbs.car.chrysler.aol import AolCarController
|
||||
from iqdbc.lvbs.car.chrysler.values_ext import ChryslerFlagsIQ
|
||||
from iqdbc.lvbs.car.chrysler.iq_values import ChryslerFlagsIQ
|
||||
|
||||
|
||||
class CarController(CarControllerBase, AolCarController, CarControllerExt):
|
||||
class CarController(CarControllerBase, AolCarController, IQCarController):
|
||||
def __init__(self, dbc_names, CP, CP_IQ):
|
||||
CarControllerBase.__init__(self, dbc_names, CP, CP_IQ)
|
||||
AolCarController.__init__(self)
|
||||
CarControllerExt.__init__(self, CP, CP_IQ)
|
||||
IQCarController.__init__(self, CP, CP_IQ)
|
||||
self.apply_torque_last = 0
|
||||
|
||||
self.hud_count = 0
|
||||
@@ -58,7 +58,7 @@ class CarController(CarControllerBase, AolCarController, CarControllerExt):
|
||||
# TODO: can we make this more sane? why is it different for all the cars?
|
||||
lkas_control_bit = self.lkas_control_bit_prev
|
||||
if self.CP_IQ.flags & ChryslerFlagsIQ.NO_MIN_STEERING_SPEED or self.CP.carFingerprint in RAM_DT:
|
||||
lkas_control_bit = CarControllerExt.get_lkas_control_bit(self, CS, CC, lkas_control_bit)
|
||||
lkas_control_bit = IQCarController.get_lkas_control_bit(self, CS, CC, lkas_control_bit)
|
||||
elif CS.out.vEgo > self.CP.minSteerSpeed:
|
||||
lkas_control_bit = True
|
||||
elif self.CP.flags & ChryslerFlags.HIGHER_MIN_STEERING_SPEED:
|
||||
|
||||
@@ -4,17 +4,17 @@ from iqdbc.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
|
||||
from iqdbc.lvbs.car.chrysler.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.chrysler.aol import AolCarState
|
||||
from iqdbc.lvbs.car.chrysler.iq_carstate import IQCarState
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarState(CarStateBase, AolCarState, CarStateExt):
|
||||
class CarState(CarStateBase, AolCarState, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
AolCarState.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
self.CP = CP
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
@@ -102,7 +102,7 @@ class CarState(CarStateBase, AolCarState, CarStateExt):
|
||||
self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"]
|
||||
|
||||
AolCarState.update_aol(self, ret, can_parsers)
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers)
|
||||
IQCarState.update(self, ret, ret_iq, can_parsers)
|
||||
|
||||
ret.buttonEvents = [
|
||||
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
|
||||
@@ -114,7 +114,10 @@ class CarState(CarStateBase, AolCarState, CarStateExt):
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers(CP, CP_IQ):
|
||||
pt_messages: list = []
|
||||
cam_messages: list = []
|
||||
AolCarState.get_parser(CP, pt_messages, cam_messages)
|
||||
return {
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, 0),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, 2),
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.chrysler.values import CAR
|
||||
from iqdbc.lvbs.car.iq_fingerprints import extend_fw_versions
|
||||
from iqdbc.lvbs.car.chrysler.iq_fingerprints import FW_VERSIONS_EXT
|
||||
|
||||
from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
|
||||
from iqdbc.lvbs.car.chrysler.fingerprints_ext import FW_VERSIONS_EXT
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
@@ -789,4 +789,6 @@ FW_VERSIONS = {
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
FW_VERSIONS = extend_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
|
||||
|
||||
@@ -5,7 +5,7 @@ from iqdbc.car.chrysler.carstate import CarState
|
||||
from iqdbc.car.chrysler.radar_interface import RadarInterface
|
||||
from iqdbc.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
from iqdbc.lvbs.car.chrysler.values_ext import ChryslerFlagsIQ
|
||||
from iqdbc.lvbs.car.chrysler.iq_values import ChryslerFlagsIQ
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@@ -100,9 +100,10 @@ class CarInterface(CarInterfaceBase):
|
||||
stock_cp.wheelbase = 3.79
|
||||
stock_cp.steerRatio = 19.
|
||||
|
||||
# LKAS heartbeat on bus 0 (msg 0x4FF) means the camera is on the ADAS bus and
|
||||
# IQ.Pilot can steer down to a standstill.
|
||||
if 0x4FF in fingerprint[0]:
|
||||
ret.flags |= ChryslerFlagsIQ.NO_MIN_STEERING_SPEED.value
|
||||
stock_cp.minSteerSpeed = 0.
|
||||
|
||||
|
||||
return ret
|
||||
|
||||
@@ -21,7 +21,6 @@ from iqdbc.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
|
||||
@@ -106,7 +105,6 @@ 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()
|
||||
|
||||
|
||||
@@ -5,17 +5,14 @@ from iqdbc.car.ford.fordcan import CanBus
|
||||
from iqdbc.car.ford.values import DBC, CarControllerParams, FordFlags
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
|
||||
from iqdbc.lvbs.car.ford.aol import AolCarState
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
TransmissionType = structs.CarParams.TransmissionType
|
||||
|
||||
|
||||
class CarState(CarStateBase, AolCarState):
|
||||
class CarState(CarStateBase):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
AolCarState.__init__(self, CP, CP_IQ)
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
if CP.transmissionType == TransmissionType.automatic:
|
||||
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
|
||||
@@ -112,8 +109,6 @@ class CarState(CarStateBase, AolCarState):
|
||||
self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"]
|
||||
self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"]
|
||||
|
||||
AolCarState.update_aol(self, ret, can_parsers)
|
||||
|
||||
ret.buttonEvents = [
|
||||
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
|
||||
*create_button_events(self.lc_button, prev_lc_button, {1: ButtonType.lkas}),
|
||||
|
||||
@@ -5,8 +5,8 @@ from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.gm.values import DBC, AccState, CruiseButtons, STEER_THRESHOLD, SDGM_CAR, ALT_ACCS
|
||||
|
||||
from iqdbc.lvbs.car.gm.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ
|
||||
from iqdbc.lvbs.car.gm.iq_carstate import IQCarState
|
||||
from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
TransmissionType = structs.CarParams.TransmissionType
|
||||
@@ -18,10 +18,10 @@ BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.D
|
||||
CruiseButtons.MAIN: ButtonType.mainCruise, CruiseButtons.CANCEL: ButtonType.cancel}
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"]
|
||||
self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2.
|
||||
@@ -163,7 +163,7 @@ class CarState(CarStateBase, CarStateExt):
|
||||
if ret.vEgo < self.CP.minSteerSpeed:
|
||||
ret.lowSpeedAlert = True
|
||||
|
||||
CarStateExt.update(self, ret, can_parsers)
|
||||
IQCarState.update(self, ret, can_parsers)
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# ruff: noqa: E501
|
||||
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
|
||||
from iqdbc.car.gm.values import CAR
|
||||
|
||||
from iqdbc.lvbs.car.fingerprints_ext import extend_fingerprints
|
||||
from iqdbc.lvbs.car.gm.fingerprints_ext import FINGERPRINTS_EXT
|
||||
from iqdbc.lvbs.car.iq_fingerprints import extend_fingerprints
|
||||
from iqdbc.lvbs.car.gm.iq_fingerprints import FINGERPRINTS_EXT
|
||||
|
||||
# Trailblazer also matches as a SILVERADO, TODO: split with fw versions
|
||||
# FIXME: There are Equinox users with different message lengths, specifically 304 and 320
|
||||
@@ -54,6 +53,9 @@ FINGERPRINTS = {
|
||||
}],
|
||||
CAR.CHEVROLET_SILVERADO: [{
|
||||
190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
|
||||
},
|
||||
{
|
||||
190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 3, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
|
||||
}],
|
||||
CAR.CHEVROLET_EQUINOX: [{
|
||||
190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 510: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
|
||||
@@ -78,4 +80,5 @@ FINGERPRINTS = {
|
||||
FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = {
|
||||
}
|
||||
|
||||
|
||||
FINGERPRINTS = extend_fingerprints(FINGERPRINTS, FINGERPRINTS_EXT)
|
||||
|
||||
@@ -10,13 +10,13 @@ from iqdbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG, CAMER
|
||||
from iqdbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags
|
||||
from iqdbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LateralAccelFromTorqueCallbackType
|
||||
|
||||
from iqdbc.lvbs.car.gm.interface_ext import CarInterfaceExt
|
||||
from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ, GMSafetyFlagsIQ
|
||||
from iqdbc.lvbs.car.gm.iq_interface import IQCarInterface
|
||||
from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ, GMSafetyFlagsIQ
|
||||
|
||||
TransmissionType = structs.CarParams.TransmissionType
|
||||
NetworkLocation = structs.CarParams.NetworkLocation
|
||||
|
||||
# iqpilot-specific torque parameters for Bolt cars that actually use the d parameter
|
||||
# Bolt Non-ACC uses the 4th (d) tune parameter; stock tunes zero it out.
|
||||
NON_LINEAR_TORQUE_PARAMS_IQ = {
|
||||
CAR.CHEVROLET_BOLT_NON_ACC: [2.24, 1.1, 0.28, -0.07],
|
||||
CAR.CHEVROLET_BOLT_NON_ACC_1ST_GEN: [1.8, 1.1, 0.3, -0.045],
|
||||
@@ -30,7 +30,7 @@ NON_LINEAR_TORQUE_PARAMS = {
|
||||
}
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase, CarInterfaceExt):
|
||||
class CarInterface(CarInterfaceBase, IQCarInterface):
|
||||
CarState = CarState
|
||||
CarController = CarController
|
||||
RadarInterface = RadarInterface
|
||||
@@ -40,7 +40,7 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
|
||||
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarInterfaceBase.__init__(self, CP, CP_IQ)
|
||||
CarInterfaceExt.__init__(self, CP, CarInterfaceBase)
|
||||
IQCarInterface.__init__(self, CP, CarInterfaceBase)
|
||||
|
||||
@staticmethod
|
||||
def get_pid_accel_limits(CP, CP_IQ, current_speed, cruise_speed):
|
||||
@@ -125,9 +125,6 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
|
||||
|
||||
# Tuning for experimental long
|
||||
ret.longitudinalTuning.kiV = [2.0, 1.5]
|
||||
ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.vEgoStarting = 0.25
|
||||
|
||||
if alpha_long:
|
||||
ret.pcmCruise = False
|
||||
@@ -244,11 +241,10 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
|
||||
CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN, CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN):
|
||||
stock_cp.steerActuatorDelay = 0.2
|
||||
CarInterfaceBase.configure_torque_tune(candidate, stock_cp.lateralTuning)
|
||||
|
||||
elif candidate in (CAR.CHEVROLET_EQUINOX_NON_ACC_3RD_GEN, ):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, stock_cp.lateralTuning)
|
||||
|
||||
# NON_ACC vehicles should use camera car speed thresholds
|
||||
# Non-ACC cars steer/long via the forward camera and pcmCruise, not the ASCM.
|
||||
if ret.flags & GMFlagsIQ.NON_ACC:
|
||||
stock_cp.dashcamOnly = False
|
||||
stock_cp.alphaLongitudinalAvailable = False
|
||||
@@ -257,13 +253,13 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
|
||||
stock_cp.pcmCruise = True
|
||||
stock_cp.safetyConfigs[0].safetyParam |= GMSafetyFlags.HW_CAM.value
|
||||
ret.iqSafetyFlags |= GMSafetyFlagsIQ.NON_ACC
|
||||
stock_cp.minEnableSpeed = 24 * CV.MPH_TO_MS # 24 mph
|
||||
stock_cp.minSteerSpeed = 3.0 # ~6 mph
|
||||
stock_cp.minEnableSpeed = 24 * CV.MPH_TO_MS
|
||||
stock_cp.minSteerSpeed = 3.0
|
||||
|
||||
# dashcamOnly platforms: untested platforms, need user validations
|
||||
# Untested Non-ACC platforms ship dashcam-only pending user validation.
|
||||
if candidate in (CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN, CAR.CHEVROLET_EQUINOX_NON_ACC_3RD_GEN,
|
||||
CAR.CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN, CAR.CADILLAC_CT6_NON_ACC_1ST_GEN, CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN,
|
||||
CAR.CADILLAC_XT5_NON_ACC_1ST_GEN):
|
||||
CAR.CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN, CAR.CADILLAC_CT6_NON_ACC_1ST_GEN,
|
||||
CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN, CAR.CADILLAC_XT5_NON_ACC_1ST_GEN):
|
||||
stock_cp.dashcamOnly = True
|
||||
|
||||
return ret
|
||||
|
||||
@@ -4,10 +4,9 @@ from enum import Enum, IntFlag
|
||||
from iqdbc.car import Bus, PlatformConfig, DbcDict, Platforms, CarSpecs
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column, SupportType
|
||||
from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ
|
||||
from iqdbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
|
||||
|
||||
from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
|
||||
@@ -88,13 +87,6 @@ class GMCarDocs(CarDocs):
|
||||
self.car_parts = CarParts.common([CarHarness.obd_ii])
|
||||
|
||||
|
||||
@dataclass
|
||||
class GMNonAccCarDocs(GMCarDocs):
|
||||
package: str = "No Adaptive Cruise Control (Non-ACC)"
|
||||
support_type: SupportType = SupportType.COMMUNITY
|
||||
support_link: str = "community"
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class GMCarSpecs(CarSpecs):
|
||||
tireStiffnessFactor: float = 0.444 # not optimized yet
|
||||
@@ -123,6 +115,13 @@ class GMSDGMPlatformConfig(GMPlatformConfig):
|
||||
self.car_docs = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class GMNonAccCarDocs(GMCarDocs):
|
||||
package: str = "No Adaptive Cruise Control (Non-ACC)"
|
||||
support_type: SupportType = SupportType.COMMUNITY
|
||||
support_link: str = "community"
|
||||
|
||||
|
||||
@dataclass
|
||||
class GMNonSccPlatformConfig(GMPlatformConfig):
|
||||
def init(self):
|
||||
@@ -209,13 +208,7 @@ class CAR(Platforms):
|
||||
GMCarSpecs(mass=2490, wheelbase=2.94, steerRatio=17.3, centerToFrontRatio=0.5, tireStiffnessFactor=1.0),
|
||||
)
|
||||
|
||||
# port extensions
|
||||
# Separate car def is required when there is no ASCM
|
||||
# (for now) unless there is a way to detect it when it has been unplugged...
|
||||
# CHEVROLET_VOLT_CC = GMNonSccPlatformConfig(
|
||||
# [GMNonAccCarDocs("Chevrolet Volt LT 2017-18")],
|
||||
# CHEVROLET_VOLT.specs,
|
||||
# )
|
||||
# IQ.Pilot Non-ACC camera-harness ports (no factory adaptive cruise).
|
||||
CHEVROLET_BOLT_NON_ACC = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2017")],
|
||||
CHEVROLET_BOLT_EUV.specs,
|
||||
@@ -333,7 +326,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
|
||||
# TODO: detect most of these sets live
|
||||
EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_BOLT_EUV,
|
||||
# port extensions, Non-ACC
|
||||
# Non-ACC EV ports
|
||||
CAR.CHEVROLET_BOLT_NON_ACC, CAR.CHEVROLET_BOLT_NON_ACC_1ST_GEN, CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN}
|
||||
|
||||
# We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness)
|
||||
|
||||
@@ -10,7 +10,7 @@ from iqdbc.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA
|
||||
HondaFlags, CruiseButtons, CruiseSettings, GearShifter, CarControllerParams
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
|
||||
from iqdbc.lvbs.car.honda.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.honda.iq_carstate import IQCarState
|
||||
|
||||
TransmissionType = structs.CarParams.TransmissionType
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
@@ -20,10 +20,10 @@ BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.D
|
||||
SETTINGS_BUTTONS_DICT = {CruiseSettings.DISTANCE: ButtonType.gapAdjustCruise, CruiseSettings.LKAS: ButtonType.lkas}
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
if CP.transmissionType != TransmissionType.manual:
|
||||
@@ -246,7 +246,7 @@ class CarState(CarStateBase, CarStateExt):
|
||||
*create_button_events(self.cruise_setting, prev_cruise_setting, SETTINGS_BUTTONS_DICT),
|
||||
]
|
||||
|
||||
CarStateExt.update(self, ret, can_parsers)
|
||||
IQCarState.update(self, ret, can_parsers)
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.honda.values import CAR
|
||||
|
||||
from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
|
||||
from iqdbc.lvbs.car.honda.fingerprints_ext import FW_VERSIONS_EXT
|
||||
from iqdbc.lvbs.car.iq_fingerprints import extend_fw_versions
|
||||
from iqdbc.lvbs.car.honda.iq_fingerprints import FW_VERSIONS_EXT
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
@@ -994,6 +994,7 @@ FW_VERSIONS = {
|
||||
b'8S102-T56-A070\x00\x00',
|
||||
b'8S102-T60-AA10\x00\x00',
|
||||
b'8S102-T64-A040\x00\x00',
|
||||
b'8S102-T64-A050\x00\x00',
|
||||
],
|
||||
(Ecu.vsa, 0x18da28f1, None): [
|
||||
b'57114-T20-AB40\x00\x00',
|
||||
|
||||
@@ -2,7 +2,7 @@ from iqdbc.car import CanBusBase
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS,
|
||||
HONDA_BOSCH_CANFD, CarControllerParams)
|
||||
from iqdbc.lvbs.car.honda.values_ext import HondaFlagsIQ
|
||||
from iqdbc.lvbs.car.honda.iq_values import HondaFlagsIQ
|
||||
|
||||
# CAN bus layout with relay
|
||||
# 0 = ACC-CAN - radar side
|
||||
|
||||
@@ -11,7 +11,7 @@ from iqdbc.car.honda.carstate import CarState
|
||||
from iqdbc.car.honda.radar_interface import RadarInterface
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
|
||||
from iqdbc.lvbs.car.honda.values_ext import HondaFlagsIQ, HondaSafetyFlagsIQ
|
||||
from iqdbc.lvbs.car.honda.iq_values import HondaFlagsIQ, HondaSafetyFlagsIQ
|
||||
|
||||
TransmissionType = structs.CarParams.TransmissionType
|
||||
|
||||
@@ -88,9 +88,11 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.steerActuatorDelay = 0.1
|
||||
|
||||
if candidate in HONDA_BOSCH:
|
||||
ret.longitudinalActuatorDelay = 0.5 # s
|
||||
if candidate in HONDA_BOSCH_RADARLESS:
|
||||
ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model
|
||||
ret.longitudinalActuatorDelay = 0.25 # s
|
||||
else:
|
||||
ret.longitudinalActuatorDelay = 0.5 # s
|
||||
else:
|
||||
# default longitudinal tuning for all hondas
|
||||
ret.longitudinalTuning.kiBP = [0., 5., 35.]
|
||||
@@ -335,6 +337,12 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
stock_cp.autoResumeSng = stock_cp.autoResumeSng or ret.enableGasInterceptor
|
||||
|
||||
if candidate == CAR.HONDA_CITY_7G:
|
||||
ret.longitudinalStoppingSpeedOverride = 2.0
|
||||
ret.stoppingDecelRateOverride = 0.3
|
||||
else:
|
||||
ret.longitudinalStoppingSpeedOverride = 0.5
|
||||
ret.stoppingDecelRateOverride = 0.1
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@@ -1,27 +1,47 @@
|
||||
import numpy as np
|
||||
from iqdbc.can import CANPacker
|
||||
from iqdbc.car import Bus, DT_CTRL, make_tester_present_msg, structs
|
||||
from iqdbc.car.lateral import apply_driver_steer_torque_limits, common_fault_avoidance
|
||||
from iqdbc.car.lateral import apply_driver_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.hyundai import hyundaicanfd, hyundaican
|
||||
from iqdbc.car.hyundai.carstate import CarState
|
||||
from iqdbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CAN_GEARS, HyundaiExtFlags
|
||||
from iqdbc.car.interfaces import CarControllerBase
|
||||
|
||||
from iqdbc.lvbs.car.hyundai.escc import EsccCarController
|
||||
from iqdbc.lvbs.car.hyundai.longitudinal.controller import LongitudinalController
|
||||
from iqdbc.lvbs.car.hyundai.lead_data_ext import LeadDataCarController
|
||||
from iqdbc.lvbs.car.hyundai.aol import AolCarController
|
||||
from iqdbc.car.vehicle_model import VehicleModel
|
||||
|
||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||
|
||||
|
||||
from openpilot.common.params import Params
|
||||
|
||||
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
|
||||
# All slightly below EPS thresholds to avoid fault
|
||||
MAX_ANGLE = 85
|
||||
MAX_ANGLE_FRAMES = 89
|
||||
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||
DRIVER_TORQUE_FILTER_TAU = 0.12
|
||||
PRE_OVERRIDE_PREDICTION_TIME = 0.15
|
||||
PRE_OVERRIDE_START_RATIO = 0.90
|
||||
PRE_OVERRIDE_FULL_RATIO = 1.05
|
||||
PRE_OVERRIDE_RAW_MIN_RATIO = 0.70
|
||||
PRE_OVERRIDE_FILTERED_MIN_RATIO = 0.65
|
||||
PRE_OVERRIDE_MIN_RATE_RATIO = 0.50
|
||||
PRE_OVERRIDE_CONFIRM_FRAMES = 2
|
||||
PRE_OVERRIDE_MAX_TORQUE_DELTA = -10.0
|
||||
LOW_SPEED_ANGLE_RATE_RAMP_SPEED = 15.0 * CV.KPH_TO_MS
|
||||
MID_SPEED_ANGLE_RATE_LIMIT_SPEED = 40.0 * CV.KPH_TO_MS
|
||||
|
||||
vibrate_intervals = [
|
||||
(0.0, 0.5),
|
||||
(1.0, 1.5),
|
||||
#(2.5, 3.0),
|
||||
#(3.5, 4.0),
|
||||
(5.0, 5.5),
|
||||
(6.0, 6.5),
|
||||
(7.5, 8.0),
|
||||
]
|
||||
|
||||
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||
@@ -46,14 +66,75 @@ def process_hud_alert(enabled, fingerprint, hud_control):
|
||||
|
||||
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||
|
||||
def rate_limit(x, x_last, lo, hi):
|
||||
return float(np.clip(x, x_last + lo, x_last + hi))
|
||||
|
||||
class CarController(CarControllerBase, EsccCarController, LeadDataCarController, LongitudinalController, AolCarController):
|
||||
def __init__(self, dbc_names, CP, CP_IQ):
|
||||
CarControllerBase.__init__(self, dbc_names, CP, CP_IQ)
|
||||
EsccCarController.__init__(self, CP, CP_IQ)
|
||||
AolCarController.__init__(self)
|
||||
LeadDataCarController.__init__(self, CP)
|
||||
LongitudinalController.__init__(self, CP, CP_IQ)
|
||||
def apply_steer_angle_limits_physics(desired_sw_deg: float,
|
||||
last_sw_deg: float,
|
||||
v_ego: float,
|
||||
steering_sw_deg: float,
|
||||
lat_active: bool,
|
||||
wheelbase_m: float,
|
||||
steer_ratio: float,
|
||||
steer_sw_max_deg: float,
|
||||
model_v2=None) -> float:
|
||||
max_lat_accel = 8.5 # m/s^2
|
||||
max_lat_jerk = 4.0 # m/s^3
|
||||
y_std_1s = 0.1
|
||||
if model_v2 is not None and len(model_v2.position.yStd) > 10:
|
||||
model_y_std_1s = float(model_v2.position.yStd[10])
|
||||
if np.isfinite(model_y_std_1s) and model_y_std_1s >= 0.0:
|
||||
y_std_1s = model_y_std_1s
|
||||
max_sw_rate_deg_per_tick = float(np.interp(y_std_1s, [0.1, 0.2, 0.4], [2.0, 1.5, 0.8]))
|
||||
v = max(float(v_ego), 1.0)
|
||||
|
||||
target_sw = float(np.clip(desired_sw_deg, -steer_sw_max_deg, steer_sw_max_deg))
|
||||
if v_ego < MID_SPEED_ANGLE_RATE_LIMIT_SPEED:
|
||||
# Keep low/mid-speed angle commands quieter without reducing LKAS_ANGLE_MAX_TORQUE.
|
||||
# Allow the angle, but slow the arrival: 0~15 kph ramps 0.8->1.1 deg/tick,
|
||||
# then 15~40 kph tapers 1.1->0.8 deg/tick. Above 40 kph, physics limits take over.
|
||||
low_mid_speed_cap = float(np.interp(v_ego,
|
||||
[0.0, LOW_SPEED_ANGLE_RATE_RAMP_SPEED, MID_SPEED_ANGLE_RATE_LIMIT_SPEED],
|
||||
[0.8, 1.1, 0.8]))
|
||||
max_sw_rate_deg_per_tick = min(max_sw_rate_deg_per_tick, low_mid_speed_cap)
|
||||
|
||||
target_rw = target_sw / steer_ratio
|
||||
last_rw = float(last_sw_deg) / steer_ratio
|
||||
|
||||
# --- accel limit ---
|
||||
rw_max_rad = np.arctan((max_lat_accel * wheelbase_m) / (v * v))
|
||||
rw_max = float(np.degrees(rw_max_rad))
|
||||
|
||||
# --- jerk -> rate limit ---
|
||||
sec2 = 1.2
|
||||
max_drw_dt = (max_lat_jerk * wheelbase_m) / (v * v * sec2) # rad/s
|
||||
max_drw_per_tick = max_drw_dt * DT_CTRL # rad/tick
|
||||
max_drw_per_tick_deg = float(np.degrees(max_drw_per_tick))
|
||||
|
||||
err = abs(target_sw - last_sw_deg)
|
||||
if err > 20.0:
|
||||
max_sw_rate_deg_per_tick = min(max_sw_rate_deg_per_tick, 1.0)
|
||||
|
||||
max_drw_per_tick_deg = min(
|
||||
max_drw_per_tick_deg,
|
||||
max_sw_rate_deg_per_tick / steer_ratio
|
||||
)
|
||||
|
||||
# --- rate limit ---
|
||||
cmd_rw = rate_limit(target_rw, last_rw, -max_drw_per_tick_deg, max_drw_per_tick_deg)
|
||||
|
||||
# --- accel clip ---
|
||||
cmd_rw = float(np.clip(cmd_rw, -rw_max, rw_max))
|
||||
|
||||
if not lat_active:
|
||||
cmd_rw = float(steering_sw_deg) / steer_ratio
|
||||
|
||||
cmd_sw = cmd_rw * steer_ratio
|
||||
return float(np.clip(cmd_sw, -steer_sw_max_deg, steer_sw_max_deg))
|
||||
|
||||
class CarController(CarControllerBase):
|
||||
def __init__(self, dbc_names, CP, CP_IQ=None):
|
||||
super().__init__(dbc_names, CP, CP_IQ or structs.IQCarParams())
|
||||
self.CAN = CanBus(CP)
|
||||
self.params = CarControllerParams(CP)
|
||||
self.packer = CANPacker(dbc_names[Bus.pt])
|
||||
@@ -64,56 +145,302 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
|
||||
self.car_fingerprint = CP.carFingerprint
|
||||
self.last_button_frame = 0
|
||||
|
||||
self.hyundai_jerk = HyundaiJerk()
|
||||
self.speedCameraHapticEndFrame = 0
|
||||
self.hapticFeedbackWhenSpeedCamera = 0
|
||||
self.max_angle_frames = MAX_ANGLE_FRAMES
|
||||
self.blinking_signal = False # 1Hz
|
||||
self.blinking_frame = int(1.0 / DT_CTRL)
|
||||
self.soft_hold_mode = 2
|
||||
|
||||
self.activateCruise = 0
|
||||
self.button_wait = 12
|
||||
self.cruise_buttons_msg_values = None
|
||||
self.cruise_buttons_msg_cnt = 0
|
||||
self.button_spamming_count = 0
|
||||
self.prev_clu_speed = 0
|
||||
self.button_spam1 = 8
|
||||
self.button_spam2 = 30
|
||||
self.button_spam3 = 1
|
||||
|
||||
self.apply_angle_last = 0
|
||||
self.lkas_max_torque = 0
|
||||
self.angle_max_torque = 250
|
||||
self.steering_pressed_prev = False
|
||||
self.recovering_from_override = False
|
||||
self.full_recovery_frames = 0
|
||||
self.repeated_override_count = 0
|
||||
self.override_latched = False
|
||||
self.override_release_frames = 0
|
||||
self.driver_torque_filtered = 0.0
|
||||
self.driver_torque_filtered_prev = 0.0
|
||||
self.pre_override_frames = 0
|
||||
|
||||
self.lkas11_active = False
|
||||
|
||||
self.canfd_debug = 0
|
||||
self.MainMode_ACC_trigger = 0
|
||||
self.LFA_trigger = 0
|
||||
|
||||
self.activeCarrot = 0
|
||||
self.camera_scc_params = Params().get_int("HyundaiCameraSCC")
|
||||
self.is_ldws_car = Params().get_bool("IsLdwsCar")
|
||||
self.enable_corner_radar = 0
|
||||
|
||||
self.steerDeltaUpOrg = self.steerDeltaUp = self.steerDeltaUpLC = self.params.STEER_DELTA_UP
|
||||
self.steerDeltaDownOrg = self.steerDeltaDown = self.steerDeltaDownLC = self.params.STEER_DELTA_DOWN
|
||||
|
||||
def update(self, CC, CC_IQ, CS, now_nanos):
|
||||
EsccCarController.update(self, CS)
|
||||
LeadDataCarController.update(self, CC_IQ)
|
||||
AolCarController.update(self, self.CP, CC, CC_IQ, self.frame)
|
||||
if self.frame % 2 == 0:
|
||||
LongitudinalController.update(self, CC, CS)
|
||||
|
||||
if self.frame % 50 == 0:
|
||||
params = Params()
|
||||
self.max_angle_frames = params.get_int("MaxAngleFrames")
|
||||
steerMax = params.get_int("CustomSteerMax")
|
||||
steerDeltaUp = params.get_int("CustomSteerDeltaUp")
|
||||
steerDeltaDown = params.get_int("CustomSteerDeltaDown")
|
||||
steerDeltaUpLC = params.get_int("CustomSteerDeltaUpLC")
|
||||
steerDeltaDownLC = params.get_int("CustomSteerDeltaDownLC")
|
||||
if steerMax > 0:
|
||||
self.params.STEER_MAX = steerMax
|
||||
if steerDeltaUp > 0:
|
||||
self.steerDeltaUp = steerDeltaUp
|
||||
#self.params.ANGLE_TORQUE_UP_RATE = steerDeltaUp
|
||||
else:
|
||||
self.steerDeltaUp = self.steerDeltaUpOrg
|
||||
if steerDeltaDown > 0:
|
||||
self.steerDeltaDown = steerDeltaDown
|
||||
#self.params.ANGLE_TORQUE_DOWN_RATE = steerDeltaDown
|
||||
else:
|
||||
self.steerDeltaDown = self.steerDeltaDownOrg
|
||||
|
||||
if steerDeltaUpLC > 0:
|
||||
self.steerDeltaUpLC = steerDeltaUpLC
|
||||
else:
|
||||
self.steerDeltaUpLC = self.steerDeltaUp
|
||||
if steerDeltaDownLC > 0:
|
||||
self.steerDeltaDownLC = steerDeltaDownLC
|
||||
else:
|
||||
self.steerDeltaDownLC = self.steerDeltaDown
|
||||
|
||||
self.soft_hold_mode = 1 if params.get_int("AutoCruiseControl") > 1 else 2
|
||||
self.hapticFeedbackWhenSpeedCamera = int(params.get_int("HapticFeedbackWhenSpeedCamera"))
|
||||
|
||||
self.button_spam1 = params.get_int("CruiseButtonTest1")
|
||||
self.button_spam2 = params.get_int("CruiseButtonTest2")
|
||||
self.button_spam3 = params.get_int("CruiseButtonTest3")
|
||||
self.speed_from_pcm = params.get_int("SpeedFromPCM")
|
||||
|
||||
self.canfd_debug = params.get_int("CanfdDebug")
|
||||
self.camera_scc_params = params.get_int("HyundaiCameraSCC")
|
||||
self.enable_corner_radar = params.get_int("EnableCornerRadar")
|
||||
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
|
||||
if hud_control.modelDesire in [3,4]:
|
||||
self.params.STEER_DELTA_UP = self.steerDeltaUpLC
|
||||
self.params.STEER_DELTA_DOWN = self.steerDeltaDownLC
|
||||
else:
|
||||
self.params.STEER_DELTA_UP = self.steerDeltaUp
|
||||
self.params.STEER_DELTA_DOWN = self.steerDeltaDown
|
||||
|
||||
angle_control = self.CP.flags & HyundaiFlags.ANGLE_CONTROL
|
||||
|
||||
# steering torque
|
||||
new_torque = int(round(actuators.torque * self.params.STEER_MAX))
|
||||
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, self.params)
|
||||
|
||||
# >90 degree steering fault prevention
|
||||
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
|
||||
self.angle_limit_counter, MAX_ANGLE_FRAMES,
|
||||
self.angle_limit_counter, self.max_angle_frames,
|
||||
MAX_ANGLE_CONSECUTIVE_FRAMES)
|
||||
|
||||
#apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgoRaw,
|
||||
# CS.out.steeringAngleDeg, CC.latActive, self.params.ANGLE_LIMITS)
|
||||
|
||||
apply_angle = apply_steer_angle_limits_physics(
|
||||
actuators.steeringAngleDeg,
|
||||
self.apply_angle_last,
|
||||
CS.out.vEgoRaw,
|
||||
CS.out.steeringAngleDeg,
|
||||
CC.latActive,
|
||||
self.CP.wheelbase,
|
||||
self.CP.steerRatio,
|
||||
self.params.ANGLE_LIMITS.STEER_ANGLE_MAX,
|
||||
CS.modelV2,
|
||||
)
|
||||
|
||||
|
||||
if angle_control:
|
||||
apply_steer_req = CC.latActive
|
||||
|
||||
angle_torque_cap = self.angle_max_torque
|
||||
|
||||
steering_pressed_rising = CS.out.steeringPressed and not self.steering_pressed_prev
|
||||
if steering_pressed_rising:
|
||||
if 0 < self.full_recovery_frames < int(5.0 / DT_CTRL):
|
||||
self.repeated_override_count = min(self.repeated_override_count + 1, 3)
|
||||
self.full_recovery_frames = 0
|
||||
self.recovering_from_override = True
|
||||
|
||||
torque_threshold = max(self.params.STEER_THRESHOLD, 1.0)
|
||||
# Filter signed torque so alternating sensor noise cancels out before its
|
||||
# magnitude is used for pre-override prediction.
|
||||
driver_torque = float(CS.out.steeringTorque)
|
||||
driver_torque_abs = abs(driver_torque)
|
||||
if not CC.latActive:
|
||||
self.driver_torque_filtered = driver_torque
|
||||
self.driver_torque_filtered_prev = driver_torque
|
||||
self.pre_override_frames = 0
|
||||
else:
|
||||
torque_filter_alpha = DT_CTRL / (DRIVER_TORQUE_FILTER_TAU + DT_CTRL)
|
||||
self.driver_torque_filtered_prev = self.driver_torque_filtered
|
||||
self.driver_torque_filtered += torque_filter_alpha * (driver_torque - self.driver_torque_filtered)
|
||||
|
||||
driver_torque_filtered_abs = abs(self.driver_torque_filtered)
|
||||
driver_torque_filtered_prev_abs = abs(self.driver_torque_filtered_prev)
|
||||
driver_torque_rate = max(0.0, (driver_torque_filtered_abs - driver_torque_filtered_prev_abs) / DT_CTRL)
|
||||
torque_ratio = driver_torque_filtered_abs / torque_threshold
|
||||
raw_torque_ratio = driver_torque_abs / torque_threshold
|
||||
predicted_torque_ratio = (
|
||||
driver_torque_filtered_abs + driver_torque_rate * PRE_OVERRIDE_PREDICTION_TIME
|
||||
) / torque_threshold
|
||||
pre_override_candidate = (
|
||||
CC.latActive and
|
||||
not CS.out.steeringPressed and
|
||||
raw_torque_ratio > PRE_OVERRIDE_RAW_MIN_RATIO and
|
||||
torque_ratio > PRE_OVERRIDE_FILTERED_MIN_RATIO and
|
||||
predicted_torque_ratio > PRE_OVERRIDE_START_RATIO and
|
||||
driver_torque_rate > torque_threshold * PRE_OVERRIDE_MIN_RATE_RATIO
|
||||
)
|
||||
self.pre_override_frames = self.pre_override_frames + 1 if pre_override_candidate else 0
|
||||
pre_override_yield = 0.0
|
||||
if self.pre_override_frames >= PRE_OVERRIDE_CONFIRM_FRAMES:
|
||||
pre_override_yield = float(np.interp(
|
||||
predicted_torque_ratio,
|
||||
[PRE_OVERRIDE_START_RATIO, PRE_OVERRIDE_FULL_RATIO],
|
||||
[0.0, 1.0],
|
||||
))
|
||||
recovery_allowed = False
|
||||
|
||||
if CS.out.steeringPressed:
|
||||
# Start yielding immediately when driver override is confirmed.
|
||||
self.override_latched = True
|
||||
self.override_release_frames = 0
|
||||
torque_delta = -20.0
|
||||
elif pre_override_yield > 0.0:
|
||||
# Start handing off gently before steeringPressed flips to avoid a sharp torque drop.
|
||||
torque_delta = PRE_OVERRIDE_MAX_TORQUE_DELTA * pre_override_yield
|
||||
elif self.lkas_max_torque >= self.angle_max_torque:
|
||||
# Once fully recovered, hold full authority until the next driver override.
|
||||
torque_delta = 0.0
|
||||
elif self.override_latched:
|
||||
# Hold reduced authority until driver torque stays below 60% for 0.2 seconds.
|
||||
self.override_release_frames = self.override_release_frames + 1 if torque_ratio < 0.6 else 0
|
||||
if self.override_release_frames >= int(0.2 / DT_CTRL):
|
||||
self.override_latched = False
|
||||
self.override_release_frames = 0
|
||||
recovery_allowed = True
|
||||
else:
|
||||
torque_delta = 0.0
|
||||
else:
|
||||
recovery_allowed = True
|
||||
|
||||
if recovery_allowed:
|
||||
# Use one-second model uncertainty to set the base torque recovery time.
|
||||
# Missing or invalid model data falls back to a moderate 1.5-second recovery.
|
||||
y_std_1s = 0.2
|
||||
if CS.modelV2 is not None and len(CS.modelV2.position.yStd) > 10:
|
||||
model_y_std_1s = float(CS.modelV2.position.yStd[10])
|
||||
if np.isfinite(model_y_std_1s) and model_y_std_1s >= 0.0:
|
||||
y_std_1s = model_y_std_1s
|
||||
|
||||
recovery_time = float(np.interp(y_std_1s, [0.1, 0.2, 0.3, 0.4], [0.5, 0.8, 1.5, 3.0]))
|
||||
recovery_time = max(recovery_time, float(np.interp(
|
||||
self.repeated_override_count,
|
||||
[0, 1, 2, 3],
|
||||
[0.1, 1.0, 2.0, 3.0],
|
||||
)))
|
||||
base_rate_up = (self.angle_max_torque - self.params.ANGLE_MIN_TORQUE) * DT_CTRL / recovery_time
|
||||
|
||||
# During recovery, taper the rate to zero. Only steeringPressed can reduce authority.
|
||||
torque_delta = base_rate_up * float(np.interp(torque_ratio, [0.6, 0.8], [1.0, 0.0]))
|
||||
self.lkas_max_torque = float(np.clip(self.lkas_max_torque + torque_delta,
|
||||
self.params.ANGLE_MIN_TORQUE, angle_torque_cap))
|
||||
|
||||
if not CS.out.steeringPressed and self.recovering_from_override and self.lkas_max_torque >= self.angle_max_torque:
|
||||
self.recovering_from_override = False
|
||||
self.full_recovery_frames = 1
|
||||
elif not CS.out.steeringPressed and self.full_recovery_frames > 0:
|
||||
self.full_recovery_frames += 1
|
||||
if self.full_recovery_frames >= int(5.0 / DT_CTRL):
|
||||
self.full_recovery_frames = 0
|
||||
self.repeated_override_count = 0
|
||||
|
||||
if not CC.latActive:
|
||||
apply_torque = 0
|
||||
if self.apply_torque_last > 0:
|
||||
self.apply_torque_last = max(self.apply_torque_last - self.params.STEER_DELTA_DOWN, 0)
|
||||
elif self.apply_torque_last < 0:
|
||||
self.apply_torque_last = min(self.apply_torque_last + self.params.STEER_DELTA_DOWN, 0)
|
||||
else:
|
||||
self.apply_torque_last = apply_torque
|
||||
self.lkas_max_torque = 0
|
||||
self.recovering_from_override = False
|
||||
self.full_recovery_frames = 0
|
||||
self.repeated_override_count = 0
|
||||
self.override_latched = False
|
||||
self.override_release_frames = 0
|
||||
self.driver_torque_filtered = 0.0
|
||||
self.driver_torque_filtered_prev = 0.0
|
||||
self.pre_override_frames = 0
|
||||
|
||||
if apply_torque == 0 and CC.latActive and CS.out.steeringPressed:
|
||||
apply_steer_req = False
|
||||
self.steering_pressed_prev = CS.out.steeringPressed if CC.latActive else False
|
||||
|
||||
self.apply_angle_last = apply_angle
|
||||
|
||||
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||
# FIXME: we don't use this with CAN FD?
|
||||
torque_fault = CC.latActive and not apply_steer_req
|
||||
|
||||
self.apply_torque_last = apply_torque
|
||||
|
||||
# accel + longitudinal
|
||||
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||
|
||||
# HUD messages
|
||||
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||
hud_control)
|
||||
|
||||
active_speed_decel = hud_control.activeCarrot == 3 and self.activeCarrot != 3 # 3: Speed Decel
|
||||
self.activeCarrot = hud_control.activeCarrot
|
||||
if active_speed_decel and self.speedCameraHapticEndFrame < 0: # 과속카메라 감속시작
|
||||
self.speedCameraHapticEndFrame = self.frame + (8.0 / DT_CTRL) #8초간 켜줌.
|
||||
elif not active_speed_decel:
|
||||
self.speedCameraHapticEndFrame = -1
|
||||
|
||||
if 0 <= self.speedCameraHapticEndFrame - self.frame < int(8.0 / DT_CTRL) and self.hapticFeedbackWhenSpeedCamera > 0:
|
||||
t = (self.frame - (self.speedCameraHapticEndFrame - int(8.0 / DT_CTRL))) * DT_CTRL
|
||||
|
||||
for start, end in vibrate_intervals:
|
||||
if start <= t < end:
|
||||
left_lane_warning = right_lane_warning = self.hapticFeedbackWhenSpeedCamera
|
||||
break
|
||||
|
||||
if self.frame >= self.speedCameraHapticEndFrame:
|
||||
self.speedCameraHapticEndFrame = -1
|
||||
|
||||
if self.frame % self.blinking_frame == 0:
|
||||
self.blinking_signal = True
|
||||
elif self.frame % self.blinking_frame == self.blinking_frame / 2:
|
||||
self.blinking_signal = False
|
||||
|
||||
|
||||
|
||||
can_sends = []
|
||||
|
||||
# *** common hyundai stuff ***
|
||||
|
||||
# tester present - w/ no response (keeps relevant ECU disabled)
|
||||
if self.frame % 100 == 0 and not ((self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC) or self.ESCC.enabled) and \
|
||||
self.CP.openpilotLongitudinalControl:
|
||||
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC) and self.CP.openpilotLongitudinalControl:
|
||||
# for longitudinal control, either radar or ADAS driving ECU
|
||||
addr, bus = 0x7d0, self.CAN.ECAN if self.CP.flags & HyundaiFlags.CANFD else 0
|
||||
if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
|
||||
if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||
addr, bus = 0x730, self.CAN.ECAN
|
||||
can_sends.append(make_tester_present_msg(addr, bus, suppress_response=True))
|
||||
|
||||
@@ -121,40 +448,135 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
|
||||
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||
can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True))
|
||||
|
||||
# *** CAN/CAN FD specific ***
|
||||
camera_scc = self.CP.flags & HyundaiFlags.CAMERA_SCC
|
||||
# CAN-FD platforms
|
||||
if self.CP.flags & HyundaiFlags.CANFD:
|
||||
can_sends.extend(self.create_canfd_msgs(apply_steer_req, apply_torque, set_speed_in_units, accel,
|
||||
stopping, hud_control, CS, CC))
|
||||
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
||||
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
|
||||
# steering control
|
||||
if camera_scc:
|
||||
can_sends.extend(hyundaicanfd.create_steering_messages_camera_scc(self.frame, self.packer, self.CP, self.CAN, CC, apply_steer_req, apply_torque, CS, apply_angle, self.lkas_max_torque, angle_control))
|
||||
else:
|
||||
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, apply_angle, self.lkas_max_torque, angle_control))
|
||||
|
||||
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
|
||||
if self.frame % 5 == 0 and hda2 and not camera_scc:
|
||||
can_sends.extend(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS))
|
||||
|
||||
# LFA and HDA icons
|
||||
if self.frame % 5 == 0 and (not hda2 or hda2_long or camera_scc):
|
||||
can_sends.extend(hyundaicanfd.create_lfahda_cluster(self.packer, CS, self.CAN, CC.longActive, CC.latActive))
|
||||
if not camera_scc:
|
||||
can_sends.extend(hyundaicanfd.create_lfa_icon_non_camera_scc(self.packer, CS, self.CAN, CC))
|
||||
|
||||
# blinkers
|
||||
if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
|
||||
|
||||
if self.camera_scc_params in [2, 3]:
|
||||
self.canfd_toggle_adas(CC, CS)
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
self.hyundai_jerk.make_jerk(self.CP, CS, accel, actuators, hud_control)
|
||||
self.hyundai_jerk.check_carrot_cruise(CC, CS, hud_control, stopping, accel, actuators.aTarget)
|
||||
|
||||
if True: #not camera_scc:
|
||||
can_sends.extend(hyundaicanfd.create_ccnc_messages(self.CP, self.packer, self.CAN, self.frame, CC, CS, hud_control, apply_angle, left_lane_warning, right_lane_warning, self.enable_corner_radar, stopping, self.canfd_debug))
|
||||
if hda2:
|
||||
can_sends.extend(hyundaicanfd.create_adrv_messages(self.CP, self.packer, self.CAN, self.frame))
|
||||
else:
|
||||
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.CP, self.packer, self.CAN, self.frame))
|
||||
if self.frame % 2 == 0:
|
||||
if self.CP.flags & HyundaiFlags.CAMERA_SCC.value:
|
||||
msg = hyundaicanfd.create_acc_control_scc2(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||
set_speed_in_units, hud_control, self.hyundai_jerk, CS)
|
||||
if msg is not None:
|
||||
can_sends.append(msg)
|
||||
can_sends.extend(hyundaicanfd.create_tcs_messages(self.packer, self.CAN, CS)) # for sorento SCC radar...
|
||||
else:
|
||||
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||
set_speed_in_units, hud_control, self.hyundai_jerk.jerk_u, self.hyundai_jerk.jerk_l, CS))
|
||||
self.accel_last = accel
|
||||
else:
|
||||
# button presses
|
||||
if self.camera_scc_params == 3: # camera scc but stock long
|
||||
send_button = self.make_spam_button(CC, CS)
|
||||
can_sends.extend(hyundaicanfd.forward_button_message(self.packer, self.CAN, self.frame, CS, send_button, self.MainMode_ACC_trigger, self.LFA_trigger))
|
||||
else:
|
||||
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
|
||||
else:
|
||||
can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel,
|
||||
stopping, hud_control, actuators, CS, CC))
|
||||
if CS.lkas11 is not None:
|
||||
if self.lkas11_active:
|
||||
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||
left_lane_warning, right_lane_warning, self.is_ldws_car))
|
||||
self.lkas11_active = True
|
||||
|
||||
if not self.CP.openpilotLongitudinalControl:
|
||||
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
|
||||
if self.CP.carFingerprint in CAN_GEARS["send_mdps12"] and CS.mdps12 is not None: # send mdps12 to LKAS to prevent LKAS error
|
||||
can_sends.append(hyundaican.create_mdps12(self.packer, self.frame, CS.mdps12))
|
||||
|
||||
casper_ev = self.CP.carFingerprint == CAR.HYUNDAI_CASPER_EV
|
||||
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
||||
self.hyundai_jerk.make_jerk(self.CP, CS, accel, actuators, hud_control)
|
||||
self.hyundai_jerk.check_carrot_cruise(CC, CS, hud_control, stopping, accel, actuators.aTarget)
|
||||
#jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||
if camera_scc:
|
||||
|
||||
can_sends.extend(hyundaican.create_acc_commands_scc(self.packer, CC.enabled, accel, self.hyundai_jerk, int(self.frame / 2),
|
||||
hud_control, set_speed_in_units, stopping,
|
||||
CC.cruiseControl.override, casper_ev, CS, self.soft_hold_mode))
|
||||
else:
|
||||
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, self.hyundai_jerk, int(self.frame / 2),
|
||||
hud_control, set_speed_in_units, stopping,
|
||||
CC.cruiseControl.override, use_fca, self.CP, CS, self.soft_hold_mode))
|
||||
|
||||
|
||||
# 20 Hz LFA MFA message
|
||||
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC, self.blinking_signal))
|
||||
|
||||
# 5 Hz ACC options
|
||||
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
||||
if camera_scc:
|
||||
if CS.scc13 is not None:
|
||||
if casper_ev:
|
||||
#can_sends.append(hyundaican.create_acc_opt_copy(CS, self.packer))
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
can_sends.extend(hyundaican.create_acc_opt(self.packer, self.CP))
|
||||
|
||||
# 2 Hz front radar options
|
||||
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl and not camera_scc:
|
||||
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
|
||||
|
||||
new_actuators = actuators.as_builder()
|
||||
new_actuators.torque = apply_torque / self.params.STEER_MAX
|
||||
new_actuators.torqueOutputCan = apply_torque
|
||||
new_actuators.accel = self.tuning.actual_accel
|
||||
# torqueOutputCan reflects the steering authority value actually sent over CAN.
|
||||
# Torque-control platforms send the signed torque command, while angle-control
|
||||
# platforms send LKAS_ANGLE_MAX_TORQUE alongside the requested angle.
|
||||
new_actuators.torqueOutputCan = self.lkas_max_torque if angle_control else apply_torque
|
||||
new_actuators.steeringAngleDeg = float(apply_angle)
|
||||
new_actuators.accel = accel
|
||||
|
||||
self.frame += 1
|
||||
return new_actuators, can_sends
|
||||
|
||||
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC):
|
||||
|
||||
def create_button_messages(self, CC: structs.CarControl, CS: CarState, use_clu11: bool):
|
||||
can_sends = []
|
||||
if CS.out.brakePressed or CS.out.brakeHoldActive:
|
||||
return can_sends
|
||||
if use_clu11:
|
||||
if CS.clu11 is None:
|
||||
return can_sends
|
||||
|
||||
# HUD messages
|
||||
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||
hud_control)
|
||||
|
||||
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||
left_lane_warning, right_lane_warning,
|
||||
self.lkas_icon))
|
||||
|
||||
# Button messages
|
||||
if not self.CP.openpilotLongitudinalControl:
|
||||
if CC.cruiseControl.cancel:
|
||||
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP))
|
||||
elif CC.cruiseControl.resume:
|
||||
elif False: #CC.cruiseControl.resume:
|
||||
# send resume at a max freq of 10Hz
|
||||
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
|
||||
# send 25 messages at a time to increases the likelihood of resume being accepted
|
||||
@@ -162,81 +584,205 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
|
||||
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
|
||||
self.last_button_frame = self.frame
|
||||
|
||||
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
||||
# TODO: unclear if this is needed
|
||||
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
||||
self.lead_data, hud_control, set_speed_in_units, stopping,
|
||||
CC.cruiseControl.override, use_fca, self.CP,
|
||||
CS.main_cruise_enabled, self.tuning, self.ESCC))
|
||||
if self.last_button_frame != self.frame:
|
||||
send_button = self.make_spam_button(CC, CS)
|
||||
if send_button > 0:
|
||||
can_sends.append(hyundaican.create_clu11_button(self.packer, self.frame, CS.clu11, send_button, self.CP))
|
||||
|
||||
# 20 Hz LFA MFA message
|
||||
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.lfa_icon))
|
||||
|
||||
# 5 Hz ACC options
|
||||
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
||||
can_sends.extend(hyundaican.create_acc_opt(self.packer, self.CP, self.ESCC))
|
||||
|
||||
# 2 Hz front radar options
|
||||
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl and not self.ESCC.enabled:
|
||||
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
|
||||
|
||||
return can_sends
|
||||
|
||||
def create_canfd_msgs(self, apply_steer_req, apply_torque, set_speed_in_units, accel, stopping, hud_control, CS, CC):
|
||||
can_sends = []
|
||||
|
||||
lka_steering = self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING
|
||||
lka_steering_long = lka_steering and self.CP.openpilotLongitudinalControl
|
||||
|
||||
# steering control
|
||||
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, self.lkas_icon))
|
||||
|
||||
# prevent LFA from activating on LKA steering cars by sending "no lane lines detected" to ADAS ECU
|
||||
if self.frame % 5 == 0 and lka_steering:
|
||||
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.lfa_block_msg,
|
||||
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT))
|
||||
|
||||
# LFA and HDA icons
|
||||
if self.frame % 5 == 0 and (not lka_steering or lka_steering_long):
|
||||
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, self.lfa_icon))
|
||||
|
||||
# blinkers
|
||||
if lka_steering and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, CC.leftBlinker, CC.rightBlinker))
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
if lka_steering:
|
||||
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
||||
else:
|
||||
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
|
||||
if self.frame % 2 == 0:
|
||||
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||
set_speed_in_units, hud_control, self.lead_data, CS.main_cruise_enabled, self.tuning))
|
||||
self.accel_last = accel
|
||||
else:
|
||||
# button presses
|
||||
|
||||
# carrot.. 왜 alt_cruise_button는 값이 리스트일까?, 그리고 왜? 빈데이터가 들어오는것일까?
|
||||
if CS.cruise_buttons_msg is not None and self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
try:
|
||||
cruise_buttons_msg_values = {key: value[0] for key, value in CS.cruise_buttons_msg.items()}
|
||||
except: # IndexError:
|
||||
#print("IndexError....")
|
||||
cruise_buttons_msg_values = None
|
||||
self.cruise_buttons_msg_cnt += 1
|
||||
if cruise_buttons_msg_values is not None:
|
||||
self.cruise_buttons_msg_values = cruise_buttons_msg_values
|
||||
self.cruise_buttons_msg_cnt = 0
|
||||
|
||||
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
||||
# cruise cancel
|
||||
if CC.cruiseControl.cancel:
|
||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
||||
self.last_button_frame = self.frame
|
||||
else:
|
||||
for _ in range(20):
|
||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.CANCEL))
|
||||
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
|
||||
print("cruiseControl.cancel222222")
|
||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
#can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.scc_control))
|
||||
if self.cruise_buttons_msg_values is not None:
|
||||
can_sends.append(hyundaicanfd.alt_cruise_buttons(self.packer, self.CP, self.CAN, Buttons.CANCEL, self.cruise_buttons_msg_values, self.cruise_buttons_msg_cnt))
|
||||
|
||||
else:
|
||||
for _ in range(20):
|
||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
|
||||
self.last_button_frame = self.frame
|
||||
|
||||
# cruise standstill resume
|
||||
elif CC.cruiseControl.resume:
|
||||
elif False: #CC.cruiseControl.resume:
|
||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
# TODO: resume for alt button cars
|
||||
pass
|
||||
else:
|
||||
for _ in range(20):
|
||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL))
|
||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
|
||||
self.last_button_frame = self.frame
|
||||
|
||||
## button 스패밍을 안했을때...
|
||||
if self.last_button_frame != self.frame:
|
||||
dat = self.canfd_speed_control_pcm(CC, CS, self.cruise_buttons_msg_values)
|
||||
if dat is not None:
|
||||
for _ in range(self.button_spam3):
|
||||
can_sends.append(dat)
|
||||
self.cruise_buttons_msg_cnt += 1
|
||||
|
||||
return can_sends
|
||||
|
||||
def canfd_toggle_adas(self, CC, CS):
|
||||
trigger_min = -200
|
||||
trigger_start = 6
|
||||
self.MainMode_ACC_trigger = max(trigger_min, self.MainMode_ACC_trigger - 1)
|
||||
self.LFA_trigger = max(trigger_min, self.LFA_trigger - 1)
|
||||
if self.MainMode_ACC_trigger == trigger_min and self.LFA_trigger == trigger_min:
|
||||
if CC.enabled and not CS.MainMode_ACC and CS.out.vEgo > 3.:
|
||||
self.MainMode_ACC_trigger = trigger_start
|
||||
elif CC.latActive and CS.LFA_ICON == 0:
|
||||
self.LFA_trigger = trigger_start
|
||||
|
||||
def canfd_speed_control_pcm(self, CC, CS, cruise_buttons_msg_values):
|
||||
|
||||
alt_buttons = True if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else False
|
||||
|
||||
if alt_buttons and cruise_buttons_msg_values is None:
|
||||
return None
|
||||
|
||||
send_button = self.make_spam_button(CC, CS)
|
||||
if send_button > 0:
|
||||
if alt_buttons:
|
||||
return hyundaicanfd.alt_cruise_buttons(self.packer, self.CP, self.CAN, send_button, cruise_buttons_msg_values, self.cruise_buttons_msg_cnt)
|
||||
else:
|
||||
return hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, send_button)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def make_spam_button(self, CC, CS):
|
||||
hud_control = CC.hudControl
|
||||
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||
target = int(set_speed_in_units+0.5)
|
||||
current = int(CS.out.cruiseState.speed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH) + 0.5)
|
||||
v_ego_kph = CS.out.vEgo * CV.MS_TO_KPH
|
||||
|
||||
send_button = 0
|
||||
activate_cruise = False
|
||||
|
||||
if CC.enabled:
|
||||
if not CS.out.cruiseState.enabled:
|
||||
if (hud_control.leadVisible or v_ego_kph > 10.0) and self.activateCruise == 0:
|
||||
send_button = Buttons.RES_ACCEL
|
||||
self.activateCruise = 1
|
||||
activate_cruise = True
|
||||
elif CC.cruiseControl.resume:
|
||||
send_button = Buttons.RES_ACCEL
|
||||
elif target < current and current>= 31 and self.speed_from_pcm != 1:
|
||||
send_button = Buttons.SET_DECEL
|
||||
elif target > current and current < 160 and self.speed_from_pcm != 1:
|
||||
send_button = Buttons.RES_ACCEL
|
||||
elif CS.out.activateCruise: #CC.cruiseControl.activate:
|
||||
if (hud_control.leadVisible or v_ego_kph > 10.0) and self.activateCruise == 0:
|
||||
self.activateCruise = 1
|
||||
send_button = Buttons.RES_ACCEL
|
||||
activate_cruise = True
|
||||
|
||||
if CS.out.brakePressed or CS.out.gasPressed:
|
||||
self.activateCruise = 0
|
||||
|
||||
if send_button == 0:
|
||||
self.button_spamming_count = 0
|
||||
self.prev_clu_speed = current
|
||||
return 0
|
||||
|
||||
speed_diff = self.prev_clu_speed - current
|
||||
spamming_max = self.button_spam1
|
||||
if CS.cruise_buttons[-1] != Buttons.NONE:
|
||||
self.last_button_frame = self.frame
|
||||
self.button_wait = self.button_spam2
|
||||
self.button_spamming_count = 0
|
||||
elif abs(self.button_spamming_count) >= spamming_max or abs(speed_diff) > 0:
|
||||
self.last_button_frame = self.frame
|
||||
self.button_wait = self.button_spam2 if abs(self.button_spamming_count) >= spamming_max else 7
|
||||
self.button_spamming_count = 0
|
||||
|
||||
self.prev_clu_speed = current
|
||||
send_button_allowed = (self.frame - self.last_button_frame) > self.button_wait
|
||||
#CC.debugTextCC = "{} speed_diff={:.1f},{:.0f}/{:.0f}, button={}, button_wait={}, count={}".format(
|
||||
# send_button_allowed, speed_diff, target, current, send_button, self.button_wait, self.button_spamming_count)
|
||||
|
||||
if send_button_allowed or activate_cruise or (CC.cruiseControl.resume and self.frame % 2 == 0):
|
||||
self.button_spamming_count = self.button_spamming_count + 1 if send_button == Buttons.RES_ACCEL else self.button_spamming_count - 1
|
||||
return send_button
|
||||
else:
|
||||
self.button_spamming_count = 0
|
||||
return 0
|
||||
|
||||
from openpilot.common.filter_simple import MyMovingAverage
|
||||
class HyundaiJerk:
|
||||
def __init__(self):
|
||||
self.params = Params()
|
||||
self.jerk = 0.0
|
||||
self.jerk_u = self.jerk_l = 0.0
|
||||
self.cb_upper = self.cb_lower = 0.0
|
||||
self.jerk_u_min = 0.5
|
||||
self.carrot_cruise = 1
|
||||
self.carrot_cruise_accel = 0.0
|
||||
|
||||
def check_carrot_cruise(self, CC, CS, hud_control, stopping, accel, a_target):
|
||||
carrot_cruise_decel = self.params.get_float("CarrotCruiseDecel")
|
||||
carrot_cruise_atc_decel = self.params.get_float("CarrotCruiseAtcDecel")
|
||||
if carrot_cruise_atc_decel >= 0 and 0 < hud_control.atcDistance < 500:
|
||||
carrot_cruise_decel = max(carrot_cruise_decel, carrot_cruise_atc_decel)
|
||||
self.carrot_cruise = 0
|
||||
if CS.out.carrotCruise > 0 and not CC.cruiseControl.override:
|
||||
if CS.softHoldActive == 0 and not stopping:
|
||||
if CS.out.vEgo > 10/3.6:
|
||||
if carrot_cruise_decel < 0:
|
||||
if (a_target > -0.1 or accel > -0.1):
|
||||
self.carrot_cruise = 1
|
||||
self.carrot_cruise_accel = 0.0
|
||||
else:
|
||||
self.carrot_cruise = 2
|
||||
carrot_cruise = min(accel, -carrot_cruise_decel * 0.01)
|
||||
self.carrot_cruise_accel = max(carrot_cruise, self.carrot_cruise_accel - 1.0 * DT_CTRL) # 점진적으로 줄임.
|
||||
if self.carrot_cruise == 0:
|
||||
self.carrot_cruise_accel = CS.out.aEgo
|
||||
|
||||
def make_jerk(self, CP, CS, accel, actuators, hud_control):
|
||||
if actuators.longControlState == LongCtrlState.stopping:
|
||||
self.jerk = self.jerk_u_min / 2 - CS.out.aEgo
|
||||
else:
|
||||
jerk = actuators.jerk if actuators.longControlState == LongCtrlState.pid else 0.0
|
||||
#a_error = actuators.aTarget - CS.out.aEgo
|
||||
self.jerk = jerk# + a_error
|
||||
|
||||
jerk_max_l = 5.0
|
||||
jerk_max_u = jerk_max_l
|
||||
if actuators.longControlState == LongCtrlState.off:
|
||||
self.jerk_u = jerk_max_u
|
||||
self.jerk_l = jerk_max_l
|
||||
self.cb_upper = self.cb_lower = 0.0
|
||||
else:
|
||||
if CP.flags & HyundaiFlags.CANFD:
|
||||
# Keep deceleration authority after the MPC jerk settles to zero. Stock SCC raises the
|
||||
# lower jerk limit with the raw acceleration request instead of relying on jerk alone.
|
||||
jerk_l_base = 1.2
|
||||
jerk_l_raw = np.clip(jerk_l_base + 2.0 * max(0.0, -accel - 2.8), jerk_l_base, jerk_max_l)
|
||||
jerk_l_mpc = np.clip(-self.jerk * 4.0, jerk_l_base, jerk_max_l)
|
||||
|
||||
self.jerk_u = min(max(self.jerk_u_min, self.jerk * 2.0), jerk_max_u)
|
||||
self.jerk_l = max(jerk_l_raw, jerk_l_mpc)
|
||||
self.cb_upper = self.cb_lower = 0.0
|
||||
else:
|
||||
self.jerk_u = min(max(self.jerk_u_min, self.jerk * 2.0), jerk_max_u)
|
||||
self.jerk_l = min(max(1.0, -self.jerk * 4.0), jerk_max_l)
|
||||
self.cb_upper = np.clip(0.9 + accel * 0.2, 0, 1.2)
|
||||
self.cb_lower = np.clip(0.8 + accel * 0.2, 0, 1.2)
|
||||
|
||||
@@ -1,47 +1,83 @@
|
||||
from collections import deque
|
||||
import copy
|
||||
import math
|
||||
import numpy as np
|
||||
import ast
|
||||
|
||||
from iqdbc.can import CANDefine, CANParser
|
||||
from iqdbc.car import Bus, create_button_events, structs
|
||||
from iqdbc.car import Bus, create_button_events, structs, DT_CTRL
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, CAR, DBC, Buttons, CarControllerParams
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, CAR, DBC, Buttons, CarControllerParams, CAMERA_SCC_CAR, HyundaiExtFlags, \
|
||||
EV_MODE_ACTIVE_VALUES, EV_MODE_STATUS_ADDR, EV_MODE_STATUS_DLC, EV_MODE_STATUS_MSG, \
|
||||
EV_MODE_STATUS_SIGNAL
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
|
||||
from iqdbc.lvbs.car.hyundai.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.hyundai.escc import EsccCarStateBase
|
||||
from iqdbc.lvbs.car.hyundai.aol import AolCarState
|
||||
from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
|
||||
from openpilot.common.params import Params
|
||||
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
PREV_BUTTON_SAMPLES = 8
|
||||
CLUSTER_SAMPLE_RATE = 20 # frames
|
||||
STANDSTILL_THRESHOLD = 12 * 0.03125
|
||||
STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
|
||||
|
||||
# Cancel button can sometimes be ACC pause/resume button, main button can also enable on some cars
|
||||
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
|
||||
BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: ButtonType.decelCruise,
|
||||
Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
|
||||
Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel, Buttons.LFA_BUTTON: ButtonType.lfaButton}
|
||||
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
|
||||
READY_COUNT_OK = 200
|
||||
TRAILER_DISCONNECT_GRACE_FRAMES = int(5.0 / DT_CTRL)
|
||||
EV_MODE_STATUS_TIMEOUT_NS = 500_000_000
|
||||
|
||||
|
||||
class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
EsccCarStateBase.__init__(self)
|
||||
AolCarState.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
def _get_ev_mode_state(cp: CANParser) -> tuple[bool, bool]:
|
||||
timestamps = cp.ts_nanos.get(EV_MODE_STATUS_MSG)
|
||||
if timestamps is None:
|
||||
return False, False
|
||||
|
||||
timestamp = timestamps.get(EV_MODE_STATUS_SIGNAL, 0)
|
||||
dat = cp.dat.get(EV_MODE_STATUS_ADDR, b"")
|
||||
# The update timestamp advances even when the whole ECAN bus is silent.
|
||||
# last_nonempty_nanos would leave the final decoded state valid forever.
|
||||
age = cp._last_update_nanos - timestamp
|
||||
valid = timestamp > 0 and len(dat) == EV_MODE_STATUS_DLC and not cp.bus_timeout and 0 <= age <= EV_MODE_STATUS_TIMEOUT_NS
|
||||
active = valid and int(cp.vl[EV_MODE_STATUS_MSG][EV_MODE_STATUS_SIGNAL]) in EV_MODE_ACTIVE_VALUES
|
||||
return active, valid
|
||||
|
||||
|
||||
NUMERIC_TO_TZ = {
|
||||
840: "America/New_York", # 미국 (US) → 동부 시간대
|
||||
124: "America/Toronto", # 캐나다 (CA) → 동부 시간대
|
||||
250: "Europe/Paris", # 프랑스 (FR)
|
||||
276: "Europe/Berlin", # 독일 (DE)
|
||||
826: "Europe/London", # 영국 (GB)
|
||||
392: "Asia/Tokyo", # 일본 (JP)
|
||||
156: "Asia/Shanghai", # 중국 (CN)
|
||||
410: "Asia/Seoul", # 한국 (KR)
|
||||
36: "Australia/Sydney", # 호주 (AU)
|
||||
356: "Asia/Kolkata", # 인도 (IN)
|
||||
}
|
||||
|
||||
class CarState(CarStateBase):
|
||||
def __init__(self, CP, CP_IQ=None):
|
||||
super().__init__(CP, CP_IQ or structs.IQCarParams())
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
self.cruise_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||
self.main_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||
self.lda_button = 0
|
||||
|
||||
self.gear_msg_canfd = "ACCELERATOR" if CP.flags & HyundaiFlags.EV else \
|
||||
self.gear_msg_canfd = "GEAR" if CP.extFlags & HyundaiExtFlags.CANFD_GEARS_69 else \
|
||||
"ACCELERATOR" if CP.flags & HyundaiFlags.EV else \
|
||||
"GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
|
||||
"GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
|
||||
"GEAR_SHIFTER"
|
||||
|
||||
self.use_accelerator = self.gear_msg_canfd == "ACCELERATOR"
|
||||
if CP.flags & HyundaiFlags.CANFD:
|
||||
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
|
||||
elif CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
|
||||
@@ -63,31 +99,210 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
|
||||
self.is_metric = False
|
||||
self.buttons_counter = 0
|
||||
|
||||
self.cruise_info = {}
|
||||
# for generic CAN parsing
|
||||
self.fca11 = None
|
||||
self.scc11 = None
|
||||
self.scc12 = None
|
||||
self.scc13 = None
|
||||
self.scc14 = None
|
||||
self.lkas11 = None
|
||||
self.clu11 = None
|
||||
|
||||
# for CANFD parsing
|
||||
self.scc_control = None
|
||||
self.lfa = None
|
||||
self.lfa_alt = None
|
||||
self.lfahda_cluster = None
|
||||
self.adrv_0x161 = None
|
||||
self.adrv_0x200 = None
|
||||
self.adrv_0x1ea = None
|
||||
self.adrv_0x160 = None
|
||||
self.ccnc_0x162 = None
|
||||
self.hda_info_4a3 = None
|
||||
self.tcs = None
|
||||
self.mdps = None
|
||||
self.steer_touch_2af = None
|
||||
self.cruise_buttons_msg = None
|
||||
self.cam_0x362 = None
|
||||
self.cam_0x2a4 = None
|
||||
self.manual_speed_limit_assist = None
|
||||
self.accelerator = None
|
||||
self.blinkers = None
|
||||
self.blinkers_alt = None
|
||||
self.doors_seatbelts = None
|
||||
self.cruise_buttons_alt2 = None
|
||||
|
||||
# On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
|
||||
self.cluster_speed = 0
|
||||
self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
|
||||
|
||||
self.params = CarControllerParams(CP)
|
||||
self.op_params = Params()
|
||||
|
||||
self.main_enabled = True if self.op_params.get_int("AutoEngage") == 2 else False
|
||||
self.gear_shifter = GearShifter.drive # Gear_init for Nexo ?? unknown 21.02.23.LSW
|
||||
|
||||
self.totalDistance = 0.0
|
||||
self.speedLimitDistance = 0
|
||||
self.pcmCruiseGap = 0
|
||||
|
||||
self.cruise_buttons_alt = True if self.CP.carFingerprint in (CAR.HYUNDAI_CASPER, CAR.HYUNDAI_CASPER_EV) else False
|
||||
self.MainMode_ACC = False
|
||||
self.ACCMode = 0
|
||||
self.LFA_ICON = 0
|
||||
self.paddle_button_prev = 0
|
||||
|
||||
self.lf_distance = 0
|
||||
self.rf_distance = 0
|
||||
self.lr_distance = 0
|
||||
self.rr_distance = 0
|
||||
#self.lf_lateral = 0
|
||||
#self.rf_lateral = 0
|
||||
|
||||
fingerprints_str = Params().get("FingerPrints")
|
||||
try:
|
||||
fingerprints = ast.literal_eval(fingerprints_str) if fingerprints_str else {i: {} for i in range(8)}
|
||||
except (SyntaxError, ValueError):
|
||||
fingerprints = {i: {} for i in range(8)}
|
||||
#print("fingerprints =", fingerprints)
|
||||
ecu_disabled = False
|
||||
if self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC):
|
||||
ecu_disabled = True
|
||||
|
||||
|
||||
self.HAS_LFA_BUTTON = True if 913 in fingerprints[0] else False
|
||||
self.CRUISE_BUTTON_ALT = True if 1007 in fingerprints[0] else False
|
||||
|
||||
cam_bus = CanBus(CP).CAM
|
||||
pt_bus = CanBus(CP).ECAN
|
||||
alt_bus = CanBus(CP).ACAN
|
||||
self.GEAR = True if 69 in fingerprints[pt_bus] else False
|
||||
self.GEAR_ALT = True if 64 in fingerprints[pt_bus] else False
|
||||
self.TPMS = True if 0x3a0 in fingerprints[pt_bus] else False
|
||||
self.LOCAL_TIME = True if 1264 in fingerprints[pt_bus] else False
|
||||
|
||||
self.cp_bsm = None
|
||||
self.time_zone = "UTC"
|
||||
|
||||
self.cp = None
|
||||
self.cp_cam = None
|
||||
self.cp_alt = None
|
||||
self.controls_ready_count = 0
|
||||
|
||||
# trailer detection
|
||||
self.trailer_connected = False
|
||||
self.trailer_timeout_cnt = 0
|
||||
self.trailer_connected_prev = False
|
||||
self.trailer_status = None
|
||||
|
||||
def monitor_fingerprint(self, can_parsers, canfd):
|
||||
if self.controls_ready_count <= READY_COUNT_OK:
|
||||
if Params().get_bool("ControlsReady"):
|
||||
self.controls_ready_count += 1
|
||||
|
||||
self.cp = can_parsers[Bus.pt]
|
||||
self.cp_cam = can_parsers[Bus.cam]
|
||||
self.cp_alt = can_parsers[Bus.alt] if Bus.alt in can_parsers else None
|
||||
|
||||
def add_if_seen(parser, name, ignore_counter = False):
|
||||
msg = parser.dbc.name_to_msg.get(name)
|
||||
if not msg:
|
||||
print(f"{name} not in DBC")
|
||||
return
|
||||
if msg.address not in parser.seen_addresses:
|
||||
return
|
||||
if msg.address in parser.addresses:
|
||||
return
|
||||
parser._add_message(name, ignore_counter = ignore_counter) # ← 이름으로 등록
|
||||
|
||||
def add_and_cache(parser, name: str, attr: str, ignore_counter: bool = False):
|
||||
add_if_seen(parser, name, ignore_counter)
|
||||
if name in parser.vl: # 등록 성공했을 때만
|
||||
setattr(self, attr, parser.vl[name])
|
||||
return True
|
||||
return False
|
||||
|
||||
if self.controls_ready_count == 50:
|
||||
self.cp.controls_ready = self.cp_cam.controls_ready = True
|
||||
if self.cp_alt is not None:
|
||||
self.cp_alt.controls_ready = True
|
||||
elif self.controls_ready_count == 100:
|
||||
self.cp.enable_capture = self.cp_cam.enable_capture = False
|
||||
if self.cp_alt is not None:
|
||||
self.cp_alt.enable_capture = False
|
||||
elif self.controls_ready_count == 101:
|
||||
print("cp_cam.seen_addresses =", self.cp_cam.seen_addresses)
|
||||
elif self.controls_ready_count == 102:
|
||||
print("cp.seen_addresses =", self.cp.seen_addresses)
|
||||
elif self.controls_ready_count == 103:
|
||||
if self.cp_alt is not None:
|
||||
print("cp_alt.seen_addresses =", self.cp_alt.seen_addresses)
|
||||
else:
|
||||
print("cp_alt.seen_addresses = None")
|
||||
if not canfd:
|
||||
if self.controls_ready_count == 104:
|
||||
if not add_and_cache(self.cp_cam, "FCA11", "fca11"):
|
||||
add_and_cache(self.cp, "FCA11", "fca11")
|
||||
add_and_cache(self.cp_cam, "LKAS11", "lkas11")
|
||||
add_and_cache(self.cp, "CLU11", "clu11")
|
||||
elif self.controls_ready_count == 105:
|
||||
cp_cruise = self.cp_cam if self.CP.flags & HyundaiFlags.CAMERA_SCC else self.cp
|
||||
scc_messages_expected = not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC
|
||||
if scc_messages_expected:
|
||||
add_and_cache(cp_cruise, "SCC11", "scc11")
|
||||
add_and_cache(cp_cruise, "SCC12", "scc12")
|
||||
add_and_cache(cp_cruise, "SCC13", "scc13")
|
||||
add_and_cache(cp_cruise, "SCC14", "scc14")
|
||||
else: # canfd
|
||||
if self.controls_ready_count == 120:
|
||||
cp_cruise = self.cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else self.cp
|
||||
add_and_cache(cp_cruise, "SCC_CONTROL", "scc_control")
|
||||
elif self.controls_ready_count == 121:
|
||||
add_and_cache(self.cp, "TCS", "tcs")
|
||||
add_and_cache(self.cp, "MDPS", "mdps")
|
||||
add_and_cache(self.cp_cam, "LFA", "lfa")
|
||||
add_and_cache(self.cp_cam, "LFA_ALT", "lfa_alt")
|
||||
add_and_cache(self.cp_cam, "LFAHDA_CLUSTER", "lfahda_cluster")
|
||||
elif self.controls_ready_count == 122:
|
||||
add_and_cache(self.cp_cam, "ADRV_0x161", "adrv_0x161")
|
||||
add_and_cache(self.cp_cam, "ADRV_0x200", "adrv_0x200")
|
||||
add_and_cache(self.cp_cam, "ADRV_0x1ea", "adrv_0x1ea")
|
||||
add_and_cache(self.cp_cam, "ADRV_0x160", "adrv_0x160")
|
||||
add_and_cache(self.cp_cam, "CCNC_0x162", "ccnc_0x162")
|
||||
elif self.controls_ready_count == 123:
|
||||
add_and_cache(self.cp, "HDA_INFO_4A3", "hda_info_4a3")
|
||||
add_and_cache(self.cp, "STEER_TOUCH_2AF", "steer_touch_2af")
|
||||
elif self.controls_ready_count == 124:
|
||||
add_and_cache(self.cp, self.cruise_btns_msg_canfd, "cruise_buttons_msg")
|
||||
if not add_and_cache(self.cp_cam, "CAM_0x362", "cam_0x362") and self.cp_alt is not None:
|
||||
add_and_cache(self.cp_alt, "CAM_0x362", "cam_0x362")
|
||||
if not add_and_cache(self.cp_alt, "CAM_0x2a4", "cam_0x2a4") and self.cp_cam is not None:
|
||||
add_and_cache(self.cp_cam, "CAM_0x2a4", "cam_0x2a4")
|
||||
elif self.controls_ready_count == 125:
|
||||
add_and_cache(self.cp, "MANUAL_SPEED_LIMIT_ASSIST", "manual_speed_limit_assist", ignore_counter = True)
|
||||
if self.gear_msg_canfd == "ACCELERATOR":
|
||||
add_and_cache(self.cp, "ACCELERATOR", "accelerator", ignore_counter = True)
|
||||
add_and_cache(self.cp, "BLINKERS", "blinkers")
|
||||
add_and_cache(self.cp, "BLINKERS_ALT", "blinkers_alt")
|
||||
add_and_cache(self.cp, "DOORS_SEATBELTS", "doors_seatbelts")
|
||||
elif self.controls_ready_count == 126:
|
||||
add_and_cache(self.cp, "CRUISE_BUTTONS_ALT2", "cruise_buttons_alt2", ignore_counter = True)
|
||||
add_and_cache(self.cp, "TRAILER_STATUS", "trailer_status", ignore_counter = True)
|
||||
|
||||
|
||||
|
||||
self.steer_fault_counter = 0
|
||||
|
||||
def recent_button_interaction(self) -> bool:
|
||||
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
|
||||
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
|
||||
# Main button also can trigger an engagement on these cars
|
||||
return any(btn in ENABLE_BUTTONS for btn in self.cruise_buttons) or any(self.main_buttons)
|
||||
|
||||
def update(self, can_parsers) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
self.monitor_fingerprint(can_parsers, self.CP.flags & HyundaiFlags.CANFD)
|
||||
cp = can_parsers[Bus.pt]
|
||||
cp_cam = can_parsers[Bus.cam]
|
||||
cp_alt = can_parsers[Bus.alt] if Bus.alt in can_parsers else None
|
||||
|
||||
if self.CP.flags & HyundaiFlags.CANFD:
|
||||
return self.update_canfd(can_parsers)
|
||||
return self.update_canfd(can_parsers), self.out_iq
|
||||
|
||||
ret = structs.CarState()
|
||||
ret_iq = structs.IQCarState()
|
||||
cp_cruise = cp_cam if self.CP.flags & HyundaiFlags.CAMERA_SCC else cp
|
||||
self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
|
||||
speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||
@@ -97,13 +312,18 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
|
||||
|
||||
ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
|
||||
|
||||
self.parse_wheel_speeds(ret,
|
||||
if cp.ts_nanos["EMS21"]["SCR_UREA_LEVEL"] > 0:
|
||||
ret.ureaGauge = float(np.clip(cp.vl["EMS21"]["SCR_UREA_LEVEL"] / 100.0, 0.0, 1.0))
|
||||
|
||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||
cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
|
||||
cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
|
||||
cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
|
||||
cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
|
||||
)
|
||||
ret.standstill = cp.vl["WHL_SPD11"]["WHL_SPD_FL"] <= STANDSTILL_THRESHOLD and cp.vl["WHL_SPD11"]["WHL_SPD_RR"] <= STANDSTILL_THRESHOLD
|
||||
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
||||
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
||||
|
||||
self.cluster_speed_counter += 1
|
||||
if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
|
||||
@@ -116,73 +336,109 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
|
||||
if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
|
||||
self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
|
||||
|
||||
ret.vEgoCluster = self.cluster_speed * speed_conv
|
||||
#ret.vEgoCluster = self.cluster_speed * speed_conv
|
||||
|
||||
ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
|
||||
ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
|
||||
ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
|
||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
|
||||
50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
|
||||
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
|
||||
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
|
||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||
steer_fault_raw = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
||||
self.steer_fault_counter = self.steer_fault_counter + 1 if steer_fault_raw else 0
|
||||
ret.steerFaultTemporary = self.steer_fault_counter > 5
|
||||
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
||||
|
||||
# cruise state
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||
ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0
|
||||
ret.cruiseState.available = self.main_enabled and self.controls_ready_count >= READY_COUNT_OK #cp.vl["TCS13"]["ACCEnable"] == 0
|
||||
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
|
||||
ret.cruiseState.standstill = False
|
||||
ret.cruiseState.nonAdaptive = False
|
||||
elif not self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC:
|
||||
ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
|
||||
elif not self.CP.flags & HyundaiFlags.CC_ONLY_CAR:
|
||||
self.main_enabled = ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
|
||||
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
|
||||
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
|
||||
ret.cruiseState.nonAdaptive = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
|
||||
ret.cruiseState.speed = cp_cruise.vl["SCC11"]["VSetDis"] * speed_conv
|
||||
|
||||
ret.pcmCruiseGap = cp_cruise.vl["SCC11"]["TauGapSet"]
|
||||
|
||||
# TODO: Find brake pressure
|
||||
ret.brake = 0
|
||||
ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
|
||||
ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
|
||||
ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
|
||||
ret.espDisabled = cp.vl["TCS11"]["TCS_PAS"] == 1
|
||||
ret.espActive = cp.vl["TCS11"]["ABS_ACT"] == 1
|
||||
ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||
if not self.CP.flags & HyundaiFlags.CC_ONLY_CAR:
|
||||
ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
|
||||
ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
|
||||
ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
|
||||
ret.espDisabled = cp.vl["TCS11"]["TCS_PAS"] == 1
|
||||
ret.espActive = cp.vl["TCS11"]["ABS_ACT"] == 1
|
||||
ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||
ret.brakeLights = bool(cp.vl["TCS13"]["BrakeLight"] or ret.brakePressed)
|
||||
|
||||
if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV | HyundaiFlags.FCEV):
|
||||
if self.CP.flags & HyundaiFlags.FCEV:
|
||||
ret.gasPressed = cp.vl["FCEV_ACCELERATOR"]["ACCELERATOR_PEDAL"] > 0
|
||||
ret.gas = cp.vl["FCEV_ACCELERATOR"]["ACCELERATOR_PEDAL"] / 254.
|
||||
elif self.CP.flags & HyundaiFlags.HYBRID:
|
||||
ret.gasPressed = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] > 0
|
||||
ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
|
||||
else:
|
||||
ret.gasPressed = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] > 0
|
||||
ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
|
||||
ret.gasPressed = ret.gas > 0
|
||||
else:
|
||||
ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
|
||||
ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
|
||||
|
||||
# Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
|
||||
# as this seems to be standard over all cars, but is not the preferred method.
|
||||
if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
|
||||
gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
|
||||
ret.gearStep = cp.vl["ELECT_GEAR"]["Elect_Gear_Step"]
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_CASPER_EV:
|
||||
ret.gearStep = 0
|
||||
elif self.CP.flags & HyundaiFlags.FCEV:
|
||||
gear = cp.vl["EMS20"]["HYDROGEN_GEAR_SHIFTER"]
|
||||
elif self.CP.flags & HyundaiFlags.CLUSTER_GEARS:
|
||||
gear = cp.vl["CLU15"]["CF_Clu_Gear"]
|
||||
if self.CP.carFingerprint == CAR.KIA_K7:
|
||||
ret.gearStep = cp.vl["LVR11"]["CF_Lvr_GearInf"]
|
||||
elif self.CP.flags & HyundaiFlags.TCU_GEARS:
|
||||
gear = cp.vl["TCU12"]["CUR_GR"]
|
||||
else:
|
||||
gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
|
||||
ret.gearStep = cp.vl["LVR11"]["CF_Lvr_GearInf"]
|
||||
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||
if not self.CP.carFingerprint in (CAR.HYUNDAI_NEXO):
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||
else:
|
||||
gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
|
||||
gear_disp = cp.vl["ELECT_GEAR"]
|
||||
|
||||
if (not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC) and not self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC:
|
||||
gear_shifter = GearShifter.unknown
|
||||
|
||||
if gear == 1546: # Thank you for Neokii # fix PolorBear 22.06.05
|
||||
gear_shifter = GearShifter.drive
|
||||
elif gear == 2314:
|
||||
gear_shifter = GearShifter.neutral
|
||||
elif gear == 2569:
|
||||
gear_shifter = GearShifter.park
|
||||
elif gear == 2566:
|
||||
gear_shifter = GearShifter.reverse
|
||||
|
||||
if gear_shifter != GearShifter.unknown and self.gear_shifter != gear_shifter:
|
||||
self.gear_shifter = gear_shifter
|
||||
|
||||
ret.gearShifter = self.gear_shifter
|
||||
|
||||
if not self.CP.flags & HyundaiFlags.CC_ONLY_CAR and (not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC):
|
||||
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
|
||||
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
|
||||
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
|
||||
scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
|
||||
aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_CASPER_EV and aeb_src == "FCA11":
|
||||
fca_fault = cp_cruise.vl["FCA11"]["FCA_Failinfo"] != 0 or cp_cruise.vl["FCA11"]["FCA_Status"] == 3
|
||||
if fca_fault:
|
||||
aeb_warning = False
|
||||
aeb_braking = False
|
||||
ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
|
||||
ret.stockAeb = aeb_warning and aeb_braking
|
||||
|
||||
@@ -190,157 +446,393 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
|
||||
ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
|
||||
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
|
||||
|
||||
# save the entire LKAS11 and CLU11
|
||||
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
|
||||
self.clu11 = copy.copy(cp.vl["CLU11"])
|
||||
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
|
||||
prev_cruise_buttons = self.cruise_buttons[-1]
|
||||
#self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||
#carrot {{
|
||||
#if self.CRUISE_BUTTON_ALT and cp.vl["CRUISE_BUTTON_ALT"]["SET_ME_1"] == 1:
|
||||
# self.cruise_buttons_alt = True
|
||||
|
||||
cruise_button = [Buttons.NONE]
|
||||
if self.cruise_buttons_alt:
|
||||
lfa_button = cp.vl["CRUISE_BUTTON_LFA"]["CruiseSwLfa"]
|
||||
cruise_button = [Buttons.LFA_BUTTON] if lfa_button > 0 else [cp.vl["CRUISE_BUTTON_ALT"]["CruiseSwState"]]
|
||||
elif self.HAS_LFA_BUTTON and cp.vl["BCM_PO_11"]["LFA_Pressed"] == 1: # for K5
|
||||
cruise_button = [Buttons.LFA_BUTTON]
|
||||
else:
|
||||
cruise_button = cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"]
|
||||
self.cruise_buttons.extend(cruise_button)
|
||||
# }} carrot
|
||||
prev_main_buttons = self.main_buttons[-1]
|
||||
prev_lda_button = self.lda_button
|
||||
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||
if self.CP.flags & HyundaiFlags.HAS_LDA_BUTTON:
|
||||
self.lda_button = cp.vl["BCM_PO_11"]["LDA_BTN"]
|
||||
#self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||
if self.cruise_buttons_alt:
|
||||
self.main_buttons.extend(cp.vl_all["CRUISE_BUTTON_ALT"]["CruiseSwMain"])
|
||||
else:
|
||||
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||
self.mdps12 = copy.copy(cp.vl["MDPS12"])
|
||||
|
||||
ret.buttonEvents = [*create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT),
|
||||
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
|
||||
*create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})]
|
||||
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})]
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
ret.cruiseState.available = self.get_main_cruise(ret)
|
||||
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers, speed_conv)
|
||||
if not self.CP.flags & HyundaiFlags.CC_ONLY_CAR:
|
||||
tpms_unit = cp.vl["TPMS11"]["UNIT"] * 0.725 if int(cp.vl["TPMS11"]["UNIT"]) > 0 else 1.
|
||||
ret.tpms.fl = tpms_unit * cp.vl["TPMS11"]["PRESSURE_FL"]
|
||||
ret.tpms.fr = tpms_unit * cp.vl["TPMS11"]["PRESSURE_FR"]
|
||||
ret.tpms.rl = tpms_unit * cp.vl["TPMS11"]["PRESSURE_RL"]
|
||||
ret.tpms.rr = tpms_unit * cp.vl["TPMS11"]["PRESSURE_RR"]
|
||||
|
||||
ret.blockPcmEnable = not self.recent_button_interaction()
|
||||
cluSpeed = cp.vl["CLU11"]["CF_Clu_Vanz"]
|
||||
decimal = cp.vl["CLU11"]["CF_Clu_VanzDecimal"]
|
||||
if 0. < decimal < 0.5:
|
||||
cluSpeed += decimal
|
||||
|
||||
# low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
|
||||
if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
|
||||
self.low_speed_alert = True
|
||||
if ret.vEgo > (self.CP.minSteerSpeed + 4.):
|
||||
self.low_speed_alert = False
|
||||
ret.lowSpeedAlert = self.low_speed_alert
|
||||
ret.vEgoCluster = cluSpeed * speed_conv
|
||||
vEgoClu, aEgoClu = self.update_clu_speed_kf(ret.vEgoCluster)
|
||||
ret.vCluRatio = (ret.vEgo / vEgoClu) if (vEgoClu > 3. and ret.vEgo > 3.) else 1.0
|
||||
|
||||
return ret, ret_iq
|
||||
if self.CP.extFlags & HyundaiExtFlags.NAVI_CLUSTER.value:
|
||||
speedLimit = cp.vl["Navi_HU"]["SpeedLim_Nav_Clu"]
|
||||
speedLimitCam = cp.vl["Navi_HU"]["SpeedLim_Nav_Cam"]
|
||||
ret.speedLimit = speedLimit if speedLimit < 255 and speedLimitCam == 1 else 0
|
||||
speed_limit_cam = speedLimitCam == 1
|
||||
else:
|
||||
ret.speedLimit = 0
|
||||
ret.speedLimitDistance = 0
|
||||
speed_limit_cam = False
|
||||
|
||||
def update_canfd(self, can_parsers) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
self.update_speed_limit(ret, speed_limit_cam)
|
||||
|
||||
if prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
||||
self.main_enabled = not self.main_enabled
|
||||
|
||||
return ret, self.out_iq
|
||||
|
||||
def update_speed_limit(self, ret, speed_limit_cam):
|
||||
self.totalDistance += ret.vEgo * DT_CTRL
|
||||
if ret.speedLimit > 0 and not ret.gasPressed and speed_limit_cam:
|
||||
if self.speedLimitDistance <= self.totalDistance:
|
||||
self.speedLimitDistance = self.totalDistance + ret.speedLimit * 6
|
||||
self.speedLimitDistance = max(self.totalDistance + 1, self.speedLimitDistance)
|
||||
else:
|
||||
self.speedLimitDistance = self.totalDistance
|
||||
ret.speedLimitDistance = self.speedLimitDistance - self.totalDistance
|
||||
|
||||
def update_canfd(self, can_parsers) -> structs.CarState:
|
||||
cp = can_parsers[Bus.pt]
|
||||
cp_cam = can_parsers[Bus.cam]
|
||||
cp_alt = can_parsers[Bus.alt] if Bus.alt in can_parsers else None
|
||||
|
||||
ret = structs.CarState()
|
||||
ret_iq = structs.IQCarState()
|
||||
|
||||
if self.CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230:
|
||||
ret.evModeActive, ret.evModeValid = _get_ev_mode_state(cp)
|
||||
|
||||
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
|
||||
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||
|
||||
if self.CP.flags & (HyundaiFlags.EV | HyundaiFlags.HYBRID):
|
||||
ret.gasPressed = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] > 1e-5
|
||||
offset = 255. if self.CP.flags & HyundaiFlags.EV else 1023.
|
||||
ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset if not self.use_accelerator else 0 if self.accelerator is None else self.accelerator["ACCELERATOR_PEDAL"] / offset
|
||||
ret.gasPressed = ret.gas > 1e-5
|
||||
else:
|
||||
ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
|
||||
ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"]) if not self.use_accelerator else False if self.accelerator is None else bool(self.accelerator["ACCELERATOR_PEDAL_PRESSED"])
|
||||
|
||||
ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
|
||||
#print(cp.vl["TCS"], cp.vl_all["TCS"]["DriverBraking"][-10:])
|
||||
|
||||
ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
|
||||
ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
|
||||
if self.doors_seatbelts is not None:
|
||||
ret.doorOpen = self.doors_seatbelts["DRIVER_DOOR"] == 1
|
||||
ret.seatbeltUnlatched = self.doors_seatbelts["DRIVER_SEATBELT"] == 0
|
||||
|
||||
gear = cp.vl[self.gear_msg_canfd]["GEAR"]
|
||||
gear = cp.vl[self.gear_msg_canfd]["GEAR"] if not self.use_accelerator else 0 if self.accelerator is None else self.accelerator["GEAR"]
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||
|
||||
if self.TPMS:
|
||||
tpms_unit = cp.vl["TPMS"]["UNIT"] * 0.725 if int(cp.vl["TPMS"]["UNIT"]) > 0 else 1.
|
||||
ret.tpms.fl = tpms_unit * cp.vl["TPMS"]["PRESSURE_FL"]
|
||||
ret.tpms.fr = tpms_unit * cp.vl["TPMS"]["PRESSURE_FR"]
|
||||
ret.tpms.rl = tpms_unit * cp.vl["TPMS"]["PRESSURE_RL"]
|
||||
ret.tpms.rr = tpms_unit * cp.vl["TPMS"]["PRESSURE_RR"]
|
||||
|
||||
# TODO: figure out positions
|
||||
self.parse_wheel_speeds(ret,
|
||||
cp.vl["WHEEL_SPEEDS"]["WHL_SpdFLVal"],
|
||||
cp.vl["WHEEL_SPEEDS"]["WHL_SpdFRVal"],
|
||||
cp.vl["WHEEL_SPEEDS"]["WHL_SpdRLVal"],
|
||||
cp.vl["WHEEL_SPEEDS"]["WHL_SpdRRVal"],
|
||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
|
||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
|
||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
|
||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
|
||||
)
|
||||
ret.standstill = cp.vl["WHEEL_SPEEDS"]["WHL_SpdFLVal"] <= STANDSTILL_THRESHOLD and cp.vl["WHEEL_SPEEDS"]["WHL_SpdFRVal"] <= STANDSTILL_THRESHOLD and \
|
||||
cp.vl["WHEEL_SPEEDS"]["WHL_SpdRLVal"] <= STANDSTILL_THRESHOLD and cp.vl["WHEEL_SPEEDS"]["WHL_SpdRRVal"] <= STANDSTILL_THRESHOLD
|
||||
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
||||
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
||||
|
||||
ret.brakeLights = ret.brakePressed or cp.vl["TCS"]["BrakeLight"] == 1 or ret.aEgo < -0.5
|
||||
|
||||
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
|
||||
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"]
|
||||
|
||||
# steering angle deg값이 이상함. mdps값이 더 신뢰가 가는듯.. torque steering 차량도 확인해야함.
|
||||
#ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
|
||||
#ret.steeringAngleDeg = cp.vl["MDPS"]["STEERING_ANGLE"] * -1
|
||||
if self.CP.flags & HyundaiFlags.ANGLE_CONTROL:
|
||||
ret.steeringAngleDeg = cp.vl["MDPS"]["STEERING_ANGLE_2"] * -1
|
||||
else:
|
||||
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
|
||||
|
||||
trailer_signal = self.trailer_status is not None and self.trailer_status["TRAILER_CONNECTED"] != 0
|
||||
if trailer_signal:
|
||||
# Rising edge is immediate so trailer-specific behavior is preserved.
|
||||
self.trailer_timeout_cnt = 0
|
||||
self.trailer_connected = True
|
||||
elif self.trailer_connected:
|
||||
# During ignition-off, the trailer bit can clear before the cluster shuts down.
|
||||
# Keep suppression active through that transient, while still detecting a real
|
||||
# disconnect after 5 seconds at the 100 Hz CarState update rate.
|
||||
self.trailer_timeout_cnt += 1
|
||||
if self.trailer_timeout_cnt > TRAILER_DISCONNECT_GRACE_FRAMES:
|
||||
self.trailer_connected = False
|
||||
else:
|
||||
self.trailer_timeout_cnt = 0
|
||||
|
||||
ret.trailerConnected = self.trailer_connected
|
||||
|
||||
if self.trailer_connected != self.trailer_connected_prev:
|
||||
print(f"[TRAILER_DEBUG] connected={self.trailer_connected} timeout={self.trailer_timeout_cnt}")
|
||||
self.trailer_connected_prev = self.trailer_connected
|
||||
|
||||
ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
|
||||
ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
|
||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||
steer_fault_raw = cp.vl["MDPS"]["LKA_FAULT"] != 0
|
||||
self.steer_fault_counter = self.steer_fault_counter + 1 if steer_fault_raw else 0
|
||||
ret.steerFaultTemporary = self.steer_fault_counter > 5
|
||||
ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0 or cp.vl["MDPS"]["LFA2_FAULT"] != 0
|
||||
#ret.steerFaultTemporary = False
|
||||
|
||||
blinkers_info = self.blinkers if self.blinkers is not None else self.blinkers_alt if self.blinkers_alt is not None else None
|
||||
if blinkers_info is not None:
|
||||
left_blinker_lamp = blinkers_info["LEFT_LAMP"] or blinkers_info["LEFT_LAMP_ALT"]
|
||||
right_blinker_lamp = blinkers_info["RIGHT_LAMP"] or blinkers_info["RIGHT_LAMP_ALT"]
|
||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, left_blinker_lamp, right_blinker_lamp)
|
||||
|
||||
# TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
|
||||
left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_KONA_EV_2ND_GEN:
|
||||
left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
|
||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
|
||||
cp.vl["BLINKERS"][right_blinker_sig])
|
||||
if self.CP.enableBsm:
|
||||
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
|
||||
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
|
||||
if self.cp_bsm is None:
|
||||
if 442 in cp.seen_addresses:
|
||||
self.cp_bsm = cp
|
||||
print("######## BSM in ECAN")
|
||||
elif 442 in cp_cam.seen_addresses:
|
||||
self.cp_bsm = cp_cam
|
||||
print("######## BSM in CAM")
|
||||
else:
|
||||
bsm_info = self.cp_bsm.vl["BLINDSPOTS_REAR_CORNERS"]
|
||||
ret.leftBlindspot = (bsm_info["FL_INDICATOR"] + bsm_info["INDICATOR_LEFT_TWO"] + bsm_info["INDICATOR_LEFT_FOUR"]) > 0
|
||||
ret.rightBlindspot = (bsm_info["FR_INDICATOR"] + bsm_info["INDICATOR_RIGHT_TWO"] + bsm_info["INDICATOR_RIGHT_FOUR"]) > 0
|
||||
|
||||
# cruise state
|
||||
if self.cruise_buttons_alt2 is not None:
|
||||
cruise_button = self.cruise_buttons_alt2["CRUISE_BUTTONS"]
|
||||
else:
|
||||
cruise_button = cp.vl[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]
|
||||
if cruise_button in [Buttons.RES_ACCEL, Buttons.SET_DECEL] and self.CP.openpilotLongitudinalControl:
|
||||
self.main_enabled = True
|
||||
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
|
||||
ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0
|
||||
ret.cruiseState.available = self.main_enabled and self.controls_ready_count >= READY_COUNT_OK #cp.vl["TCS"]["ACCEnable"] == 0
|
||||
if self.CP.flags & HyundaiFlags.CAMERA_SCC.value:
|
||||
self.MainMode_ACC = cp_cam.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
|
||||
self.ACCMode = cp_cam.vl["SCC_CONTROL"]["ACCMode"]
|
||||
self.LFA_ICON = cp_cam.vl["LFAHDA_CLUSTER"]["HDA_LFA_SymSta"]
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
|
||||
ret.cruiseState.standstill = False
|
||||
if self.MainMode_ACC or self.main_enabled:
|
||||
self.main_enabled = True
|
||||
else:
|
||||
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
||||
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
||||
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
||||
if cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1: # carrot
|
||||
ret.cruiseState.available = self.main_enabled = True
|
||||
ret.pcmCruiseGap = int(np.clip(cp_cruise_info.vl["SCC_CONTROL"]["DISTANCE_SETTING"], 1, 4))
|
||||
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["InfoDisplay"] >= 4
|
||||
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
||||
self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
|
||||
ret.brakeHoldActive = cp.vl["ESP_STATUS"]["AUTO_HOLD"] == 1 and cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] not in (1, 2)
|
||||
|
||||
speed_limit_cam = False
|
||||
corner = False
|
||||
corner_infos = [info for info in (self.adrv_0x1ea, self.ccnc_0x162) if info is not None]
|
||||
if corner_infos:
|
||||
def corner_max(signal):
|
||||
return max(info[signal] for info in corner_infos)
|
||||
|
||||
ret.leftLongDist = self.lf_distance = corner_max("LF_DETECT_DISTANCE")
|
||||
ret.rightLongDist = self.rf_distance = corner_max("RF_DETECT_DISTANCE")
|
||||
self.lr_distance = corner_max("LR_DETECT_DISTANCE")
|
||||
self.rr_distance = corner_max("RR_DETECT_DISTANCE")
|
||||
ret.leftLatDist = corner_max("LF_DETECT_LATERAL")
|
||||
ret.rightLatDist = corner_max("RF_DETECT_LATERAL")
|
||||
ret.leftRearLongDist = self.lr_distance
|
||||
ret.rightRearLongDist = self.rr_distance
|
||||
ret.leftRearLatDist = corner_max("LR_DETECT_LATERAL")
|
||||
ret.rightRearLatDist = corner_max("RR_DETECT_LATERAL")
|
||||
corner = True
|
||||
if corner:
|
||||
raw_corner_radar_enabled = (
|
||||
self.op_params.get_int("EnableCornerRadar") > 0 and
|
||||
bool(self.CP.extFlags & (HyundaiExtFlags.CORNER_RADAR_OBJECTS_235.value |
|
||||
HyundaiExtFlags.CORNER_RADAR_OBJECTS_180.value))
|
||||
)
|
||||
left_front_block = (not raw_corner_radar_enabled) and 0 < ret.leftLongDist < 7.0
|
||||
right_front_block = (not raw_corner_radar_enabled) and 0 < ret.rightLongDist < 7.0
|
||||
rear_block_dist = 5.0 if raw_corner_radar_enabled else 7.0
|
||||
left_rear_block = 0 < self.lr_distance < rear_block_dist
|
||||
right_rear_block = 0 < self.rr_distance < rear_block_dist
|
||||
left_block = left_front_block or left_rear_block
|
||||
right_block = right_front_block or right_rear_block
|
||||
if left_block:
|
||||
ret.leftBlindspot = True
|
||||
if right_block:
|
||||
ret.rightBlindspot = True
|
||||
|
||||
if self.hda_info_4a3 is not None:
|
||||
speedLimit = self.hda_info_4a3["SPEED_LIMIT"]
|
||||
if not self.is_metric:
|
||||
speedLimit *= CV.MPH_TO_KPH
|
||||
ret.speedLimit = speedLimit if speedLimit < 255 else 0
|
||||
if int(self.hda_info_4a3["MapSource"]) == 2:
|
||||
speed_limit_cam = True
|
||||
|
||||
if self.time_zone == "UTC":
|
||||
country_code = int(self.hda_info_4a3["CountryCode"])
|
||||
self.time_zone = ZoneInfo(NUMERIC_TO_TZ.get(country_code, "UTC"))
|
||||
|
||||
ret.gearStep = cp.vl["GEAR"]["GEAR_STEP"] if self.GEAR else 0
|
||||
if 1 <= ret.gearStep <= 8 and ret.gearShifter == GearShifter.unknown:
|
||||
ret.gearShifter = GearShifter.drive
|
||||
ret.gearStep = cp.vl["GEAR_ALT"]["GEAR_STEP"] if self.GEAR_ALT else ret.gearStep
|
||||
|
||||
lane_info = self.cam_0x2a4 if self.cam_0x2a4 is not None else self.cam_0x362
|
||||
|
||||
if lane_info is not None:
|
||||
left_lane_prob = lane_info["LEFT_LANE_PROB"]
|
||||
right_lane_prob = lane_info["RIGHT_LANE_PROB"]
|
||||
left_lane_type = lane_info["LEFT_LANE_TYPE"] # 0: dashed, 1: solid, 2: undecided, 3: road edge, 4: DLM Inner Solid, 5: DLM InnerDashed, 6:DLM Inner Undecided, 7: Botts Dots, 8: Barrier
|
||||
right_lane_type = lane_info["RIGHT_LANE_TYPE"]
|
||||
left_lane_color = lane_info["LEFT_LANE_COLOR"] # 0: none, 1: white, 2: yellow, 3: blue
|
||||
right_lane_color = lane_info["RIGHT_LANE_COLOR"]
|
||||
left_lane_info = left_lane_color * 10 + left_lane_type
|
||||
right_lane_info = right_lane_color * 10 + right_lane_type
|
||||
ret.leftLaneLine = left_lane_info
|
||||
ret.rightLaneLine = right_lane_info
|
||||
|
||||
# Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
|
||||
# It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
|
||||
# The car will brake, but does not respect positive acceleration commands in this mode
|
||||
# TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
|
||||
if self.CP.flags & HyundaiFlags.EV:
|
||||
ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
|
||||
if self.manual_speed_limit_assist is not None:
|
||||
#ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
|
||||
ret.cruiseState.nonAdaptive = self.manual_speed_limit_assist["MSLA_ENABLED"] == 1
|
||||
|
||||
if self.LOCAL_TIME and self.time_zone != "UTC":
|
||||
lt = cp.vl["LOCAL_TIME"]
|
||||
y, m, d, H, M, S = int(lt["YEAR"]) + 2000, int(lt["MONTH"]), int(lt["DATE"]), int(lt["HOURS"]), int(lt["MINUTES"]), int(lt["SECONDS"])
|
||||
try:
|
||||
dt_local = datetime(y, m, d, H, M, S, tzinfo=self.time_zone)
|
||||
ret.datetime = int(dt_local.timestamp() * 1000)
|
||||
except:
|
||||
#print(f"Error parsing local time: {y}-{m}-{d} {H}:{M}:{S} in {self.time_zone}")
|
||||
pass
|
||||
|
||||
prev_cruise_buttons = self.cruise_buttons[-1]
|
||||
#self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
|
||||
#carrot {{
|
||||
|
||||
if self.cruise_buttons_alt2 is not None:
|
||||
if int(self.cruise_buttons_alt2.get("LFA_BTN", 0)) == 1:
|
||||
cruise_button = [Buttons.LFA_BUTTON]
|
||||
else:
|
||||
v = int(self.cruise_buttons_alt2.get("CRUISE_BUTTONS", 0))
|
||||
cruise_button = [v if v < 5 else Buttons.NONE]
|
||||
elif cp.vl[self.cruise_btns_msg_canfd]["LFA_BTN"]:
|
||||
cruise_button = [Buttons.LFA_BUTTON]
|
||||
else:
|
||||
cruise_button = cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]
|
||||
|
||||
self.cruise_buttons.extend(cruise_button)
|
||||
# }} carrot
|
||||
|
||||
|
||||
#if self.cruise_btns_msg_canfd in cp.vl:
|
||||
# self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
|
||||
"""
|
||||
if self.cruise_btns_msg_canfd in cp.vl: #carrot
|
||||
if not cp.vl[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]:
|
||||
pass
|
||||
#print("empty cruise btns...")
|
||||
else:
|
||||
self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
|
||||
"""
|
||||
prev_main_buttons = self.main_buttons[-1]
|
||||
prev_lda_button = self.lda_button
|
||||
self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
|
||||
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
|
||||
self.lda_button = cp.vl[self.cruise_btns_msg_canfd]["LDA_BTN"]
|
||||
#self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
|
||||
if self.cruise_buttons_alt2 is not None:
|
||||
self.main_buttons.extend([1 if int(self.cruise_buttons_alt2.get("CRUISE_BUTTONS", 0)) == 8 else 0])
|
||||
else:
|
||||
adaptive_main = cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"]
|
||||
normal_main = cp.vl_all[self.cruise_btns_msg_canfd]["NORMAL_CRUISE_MAIN_BTN"]
|
||||
self.main_buttons.extend(int(adaptive or normal) for adaptive, normal in zip(adaptive_main, normal_main, strict=True))
|
||||
if self.main_buttons[-1] != prev_main_buttons and not self.main_buttons[-1]: # and self.CP.openpilotLongitudinalControl: #carrot
|
||||
self.main_enabled = not self.main_enabled
|
||||
print("main_enabled = {}".format(self.main_enabled))
|
||||
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
|
||||
ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||
|
||||
if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
self.lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
||||
else cp_cam.vl["CAM_0x2a4"])
|
||||
speed_conv = CV.KPH_TO_MS # if self.is_metric else CV.MPH_TO_MS
|
||||
cluSpeed = cp.vl["CRUISE_BUTTONS_ALT"]["CLU_SPEED"]
|
||||
ret.vEgoCluster = cluSpeed * speed_conv # MPH단위에서도 KPH로 나오는듯..
|
||||
vEgoClu, aEgoClu = self.update_clu_speed_kf(ret.vEgoCluster)
|
||||
ret.vCluRatio = (ret.vEgo / vEgoClu) if (vEgoClu > 3. and ret.vEgo > 3.) else 1.0
|
||||
|
||||
AolCarState.update_aol_canfd(self, ret, can_parsers)
|
||||
self.update_speed_limit(ret, speed_limit_cam)
|
||||
|
||||
paddle_button = self.paddle_button_prev
|
||||
if self.cruise_btns_msg_canfd == "CRUISE_BUTTONS":
|
||||
paddle_button = 1 if cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"] == 1 else 2 if cp.vl["CRUISE_BUTTONS"]["RIGHT_PADDLE"] == 1 else 0
|
||||
elif self.gear_msg_canfd == "GEAR":
|
||||
paddle_button = 1 if cp.vl["GEAR"]["LEFT_PADDLE"] == 1 else 2 if cp.vl["GEAR"]["RIGHT_PADDLE"] == 1 else 0
|
||||
|
||||
ret.buttonEvents = [*create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT),
|
||||
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
|
||||
*create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})]
|
||||
*create_button_events(paddle_button, self.paddle_button_prev, {1: ButtonType.paddleLeft, 2: ButtonType.paddleRight}),
|
||||
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})]
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
ret.cruiseState.available = self.get_main_cruise(ret)
|
||||
self.paddle_button_prev = paddle_button
|
||||
|
||||
CarStateExt.update_canfd_ext(self, ret, ret_iq, can_parsers, speed_factor)
|
||||
return ret
|
||||
|
||||
ret.blockPcmEnable = not self.recent_button_interaction()
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
def get_can_parsers_canfd(self, CP):
|
||||
def get_can_parsers_canfd(self, CP, CP_IQ=None):
|
||||
msgs = []
|
||||
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
|
||||
# TODO: this can be removed once we add dynamic support to vl_all
|
||||
msgs += [
|
||||
# this message is 50Hz but the ECU frequently stops transmitting for ~0.5s
|
||||
("CRUISE_BUTTONS", 1)
|
||||
("CRUISE_BUTTONS", 50)
|
||||
]
|
||||
|
||||
CAN = CanBus(CP)
|
||||
pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CAN.ECAN)
|
||||
if CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230:
|
||||
# Display-only while the signal is fleet-validated: checksum and freshness
|
||||
# gate the value without making a counter/alive fault disable controls.
|
||||
pt_parser._add_message(EV_MODE_STATUS_MSG, math.nan, ignore_counter=True)
|
||||
|
||||
return {
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CanBus(CP).ECAN),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).CAM),
|
||||
Bus.pt: pt_parser,
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CAN.CAM),
|
||||
Bus.alt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CAN.ACAN),
|
||||
}
|
||||
|
||||
def get_can_parsers(self, CP, CP_IQ):
|
||||
def get_can_parsers(self, CP, CP_IQ=None):
|
||||
if CP.flags & HyundaiFlags.CANFD:
|
||||
return self.get_can_parsers_canfd(CP)
|
||||
|
||||
return {
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
|
||||
# EMS21 carries SCR_UREA_LEVEL on diesel platforms. NaN frequency makes
|
||||
# it optional, so gasoline/EV platforms do not fail CAN validity.
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [("EMS21", math.nan)], 0),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.hyundai.values import CAR
|
||||
|
||||
from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
|
||||
from iqdbc.lvbs.car.hyundai.fingerprints_ext import FW_VERSIONS_EXT
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
# The existence of SCC or RDR in the fwdRadar FW usually determines the radar's function,
|
||||
@@ -12,6 +8,14 @@ Ecu = CarParams.Ecu
|
||||
|
||||
|
||||
FW_VERSIONS = {
|
||||
CAR.HYUNDAI_AZERA_7TH_GEN: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00GN7_ RDR ----- 1.00 1.03 99110-N1000 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00GN7 MFC AT KOR LHD 1.00 1.03 99211-N1000 230322',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_AZERA_6TH_GEN: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00IG__ SCC F-CU- 1.00 1.00 99110-G8100 ',
|
||||
@@ -21,7 +25,6 @@ FW_VERSIONS = {
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00IG MFC AT MES LHD 1.00 1.04 99211-G8100 200511',
|
||||
b'\xf1\x00IG MFC AT MES LHD 1.00 1.05 99211-G8100 210409',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_AZERA_HEV_6TH_GEN: {
|
||||
@@ -55,20 +58,13 @@ FW_VERSIONS = {
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00AE MDPS C 1.00 1.03 56310/G2300 4AEHC103',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.03 56310G2300\x00 4AEHC103',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.04 56310G2550\x00 4AEHC104',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.05 56310/G2500 4AEHC105',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.05 56310/G2501 4AEHC105',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2301 4AEHC107',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2501 4AEHC107',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2551 4AEHC107',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
|
||||
b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G7200 160418',
|
||||
b'\xf1\x00AEH MFC AT EUR RHD 1.00 1.00 95740-G2200 161014',
|
||||
b'\xf1\x00AEH MFC AT EUR RHD 1.00 1.00 95740-G2400 180222',
|
||||
b'\xf1\x00AEH MFC AT USA LHD 1.00 1.00 95740-G2300 170703',
|
||||
b'\xf1\x00AEH MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
|
||||
],
|
||||
},
|
||||
@@ -78,13 +74,11 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2100 ',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2201 4AEHC107',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2501 4AEHC107',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2551 4AEHC107',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00AEP MFC AT AUS RHD 1.00 1.00 95740-G2400 180222',
|
||||
b'\xf1\x00AEP MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
|
||||
b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
|
||||
],
|
||||
},
|
||||
@@ -154,12 +148,10 @@ FW_VERSIONS = {
|
||||
CAR.HYUNDAI_IONIQ_HEV_2022: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
|
||||
b'\xf1\x00AEhe SCC F-CUP 1.00 1.02 99110-G2100 ',
|
||||
b'\xf1\x00AEhe SCC FHCUP 1.00 1.00 99110-G2600 ',
|
||||
b'\xf1\x00AEhe SCC FHCUP 1.00 1.02 99110-G2100 ',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310-XX000 4APHC101',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
|
||||
],
|
||||
@@ -173,7 +165,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00DN8_ SCC F-CU- 1.00 1.00 99110-L0000 ',
|
||||
b'\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ',
|
||||
b'\xf1\x00DN8_ SCC F-CUP 1.00 1.02 99110-L1000 ',
|
||||
b'\xf1\x00DN8_ SCC FHCU- 1.00 1.00 99110-L0000 ',
|
||||
b'\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ',
|
||||
b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ',
|
||||
b'\xf1\x00DN8_ SCC FHCUP 1.00 1.02 99110-L1000 ',
|
||||
@@ -232,6 +223,15 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00LFF LKAS AT USA LHD 1.01 1.02 95740-C1000 E52',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_SONATA_2024: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
|
||||
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L1800 230512',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_TUCSON: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00TL__ FCA F-CUP 1.00 1.01 99110-D3500 ',
|
||||
@@ -293,7 +293,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00TM ESC \x04 101 \x08\x04 58910-S2GA0',
|
||||
b'\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
|
||||
b'\xf1\x00TM ESC \x04 103"\x07\x08 58910-S2GA0',
|
||||
b'\xf1\x00TM ESC \x1b 102 \x08\x08 58910-S1DA0',
|
||||
b'\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0',
|
||||
b'\xf1\x00TM ESC 103!\x030 58910-S1MA0',
|
||||
],
|
||||
@@ -301,7 +300,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00TM MDPS C 1.00 1.01 56310-S1AB0 4TSDC101',
|
||||
b'\xf1\x00TM MDPS C 1.00 1.01 56310-S1EB0 4TSDC101',
|
||||
b'\xf1\x00TM MDPS C 1.00 1.02 56370-S2AA0 0B19',
|
||||
b'\xf1\x00TM MDPS R 1.00 1.05 57700-S1500 4TSDP105',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00TM MFC AT EUR LHD 1.00 1.03 99211-S1500 210224',
|
||||
@@ -367,7 +365,6 @@ FW_VERSIONS = {
|
||||
},
|
||||
CAR.KIA_STINGER: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00CK__ SCC FHCUP 1.00 1.02 96400-J5000 ',
|
||||
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5000 ',
|
||||
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ',
|
||||
b'\xf1\x00CK__ SCC F_CUP 1.00 1.02 96400-J5100 ',
|
||||
@@ -383,7 +380,6 @@ FW_VERSIONS = {
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822',
|
||||
b'\xf1\x00CK MFC AT KOR LHD 1.00 1.04 95740-J5000 180504',
|
||||
b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822',
|
||||
b'\xf1\x00CK MFC AT USA LHD 1.00 1.04 95740-J5000 180504',
|
||||
],
|
||||
@@ -400,7 +396,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5320 4C2VL503',
|
||||
b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5380 4C2VR503',
|
||||
b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5520 4C4VL503',
|
||||
b'\xf1\x00CK MDPS R 1.00 5.04 57700-J5320 4C2VL504',
|
||||
b'\xf1\x00CK MDPS R 1.00 5.04 57700-J5520 4C4VL504',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
@@ -442,7 +437,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00LX ESC \x0b 104 \x10\x13 58910-S8330',
|
||||
b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360',
|
||||
b'\xf1\x00ON ESC \x01 101\x19\t\x08 58910-S9360',
|
||||
b'\xf1\x00ON ESC \x01 103$\x04\x08 58910-S9360',
|
||||
b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360',
|
||||
b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320',
|
||||
b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360',
|
||||
@@ -648,6 +642,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.04 99210-L2000 210527',
|
||||
],
|
||||
},
|
||||
CAR.KIA_K5_DL3_24_HEV: { # (DL3)
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.02 99210-L2500 230911'
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00DL3_ RDR ----- 1.00 1.01 99110-L2500 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_KONA_EV: {
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00OS IEB \x01 212 \x11\x13 58520-K4000',
|
||||
@@ -703,7 +705,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310-K4271 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4971 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4260\x00 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4261\x00 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4971\x00 4OEPC102',
|
||||
@@ -720,6 +721,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00SX2EMFC AT KOR LHD 1.00 1.00 99211-BF000 230410',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_KONA_HEV_2ND_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00SX2HMFC AT EUR RHD 1.00 1.04 99211-BE000 231010',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
|
||||
],
|
||||
},
|
||||
CAR.KIA_NIRO_EV: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
|
||||
@@ -737,14 +746,11 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00DE MDPS C 1.00 1.04 56310Q4100\x00 4DEEC104',
|
||||
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4000\x00 4DEEC105',
|
||||
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4100\x00 4DEEC105',
|
||||
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4150\x00 4DEEC105',
|
||||
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4200\x00 4DEEC105',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211',
|
||||
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4100 200706',
|
||||
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.03 95740-Q4000 180821',
|
||||
b'\xf1\x00DEE MFC AT EUR RHD 1.00 1.00 99211-Q4000 191211',
|
||||
b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.02 95740-Q4000 180705',
|
||||
b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.03 95740-Q4000 180821',
|
||||
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.00 99211-Q4000 191211',
|
||||
@@ -756,13 +762,9 @@ FW_VERSIONS = {
|
||||
CAR.KIA_NIRO_EV_2ND_GEN: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',
|
||||
b'\xf1\x00SG__ RDR ----- 1.00 1.00 99110-AT200 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00SG2EMFC AT EUR LHD 1.00 1.00 99211-AT200 240315',
|
||||
b'\xf1\x00SG2EMFC AT EUR LHD 1.01 1.09 99211-AT000 220801',
|
||||
b'\xf1\x00SG2EMFC AT USA LHD 1.00 1.00 99211-AT100 230216',
|
||||
b'\xf1\x00SG2EMFC AT USA LHD 1.00 1.00 99211-AT200 240401',
|
||||
b'\xf1\x00SG2EMFC AT USA LHD 1.01 1.09 99211-AT000 220801',
|
||||
],
|
||||
},
|
||||
@@ -866,11 +868,9 @@ FW_VERSIONS = {
|
||||
CAR.KIA_OPTIMA_H_G4_FL: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00JFhe SCC FHCUP 1.00 1.01 99110-A8500 ',
|
||||
b'\xf1\x00JFhe SCC FHCUP 1.00 1.03 99110-A8500 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00JFH MFC AT KOR LHD 1.00 1.01 95895-A8200 180323',
|
||||
b'\xf1\x00JFH MFC AT KOR LHD 1.00 1.04 95895-A8200 181217',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_ELANTRA: {
|
||||
@@ -930,7 +930,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111',
|
||||
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.07 99210-AA000 220426',
|
||||
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728',
|
||||
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.09 99210-AA000 221108',
|
||||
],
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800',
|
||||
@@ -998,7 +997,6 @@ FW_VERSIONS = {
|
||||
},
|
||||
CAR.KIA_SORENTO: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00UMP LKAS AT AUS RHD 1.00 1.00 96400-C6550 S30',
|
||||
b'\xf1\x00UMP LKAS AT KOR LHD 1.00 1.00 95740-C5550 S30',
|
||||
b'\xf1\x00UMP LKAS AT USA LHD 1.00 1.00 95740-C6550 d00',
|
||||
b'\xf1\x00UMP LKAS AT USA LHD 1.01 1.01 95740-C6550 d01',
|
||||
@@ -1032,6 +1030,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.06 99210-CV000 220328',
|
||||
],
|
||||
},
|
||||
CAR.KIA_EV6_PE: { # (CV1)
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00CV__ RDR ----- 1.00 1.01 99110-CV500 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00CV MFC AT KOR LHD 1.00 1.01 99210-CV500 240405',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_IONIQ_5: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ',
|
||||
@@ -1042,7 +1048,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.00 99211-GI100 230915',
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.01 99211-GI010 211007',
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.01 99211-GI100 240110',
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.02 99211-GI010 211206',
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.03 99211-GI010 220401',
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813',
|
||||
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI010 230110',
|
||||
@@ -1056,13 +1061,29 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.00 99211-GI020 230719',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.00 99211-GI100 230915',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI100 240110',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.06 99211-GI010 230110',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_IONIQ_5_PE: { # (NE1)
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NE__ RDR ----- 1.00 1.00 99110-GI500 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00NE MFC AT KOR LHD 1.00 1.02 99211-GI500 240221',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_IONIQ_5_N: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NE1N RDR ----- 1.00 1.00 99110-NI000 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00NE1NMFC AT KOR LHD 1.00 1.04 99211-NI000 231219',
|
||||
b'\xf1\x00NE1NMFC AT USA LHD 1.00 1.04 99211-NI000 231219',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_IONIQ_6: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00CE__ RDR ----- 1.00 1.01 99110-KL000 ',
|
||||
@@ -1076,9 +1097,16 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00CE MFC AT USA LHD 1.00 1.06 99211-KL000 230915',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_IONIQ_9: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00MEev RDR ----- 1.00 1.00 99110-GO000 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00ME MFC AT KOR LHD 1.00 1.00 99211-GO000 241007',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_TUCSON_4TH_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9220 14K',
|
||||
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9260 14Y',
|
||||
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.01 99211-N9100 14A',
|
||||
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9220 14K',
|
||||
@@ -1090,14 +1118,12 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9260 14Y',
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A',
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T',
|
||||
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9240 14Q',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
|
||||
b'\xf1\x00NX4__ 1.00 1.01 99110-N9000 ',
|
||||
b'\xf1\x00NX4__ 1.00 1.02 99110-N9000 ',
|
||||
b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ',
|
||||
b'\xf1\x00NX4__ 1.01 1.02 99110-N9000 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN: {
|
||||
@@ -1115,13 +1141,11 @@ FW_VERSIONS = {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663',
|
||||
b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663',
|
||||
b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1040 663',
|
||||
b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665',
|
||||
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662',
|
||||
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663',
|
||||
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665',
|
||||
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690',
|
||||
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.01 99211-P1060 680',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NQ5__ 1.00 1.02 99110-P1000 ',
|
||||
@@ -1134,14 +1158,11 @@ FW_VERSIONS = {
|
||||
CAR.GENESIS_GV70_1ST_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00JK1 MFC AT CAN LHD 1.00 1.02 99211-IY000 230627',
|
||||
b'\xf1\x00JK1 MFC AT CAN LHD 1.00 1.04 99211-AR100 210204',
|
||||
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR200 220125',
|
||||
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR300 220125',
|
||||
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.02 99211-IY000 230627',
|
||||
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00JK1_ SCC ----- 1.00 1.02 99110-AR100 ',
|
||||
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR200 ',
|
||||
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR300 ',
|
||||
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-IY000 ',
|
||||
@@ -1158,6 +1179,24 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00JKev SCC ----- 1.00 1.01 99110-DS000 ',
|
||||
],
|
||||
},
|
||||
|
||||
CAR.HYUNDAI_NEXO_1ST_GEN: {
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00FE IEB \x01 312 \x11\x13 58520-M5000',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00FE MFC AT KOR LHD 1.00 1.00 99211-M5100 201218',
|
||||
b'\xf1\x00FE MFC AT KOR LHD 1.00 1.02 99211-M5100 220405',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00FE MDPS C 1.00 1.05 56340-M5000 9903',
|
||||
b'\xf1\x00FE MDPS C 1.00 1.06 56340-M5000 1625',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00FE__ SCC FHCUP 1.00 1.05 99110-M5000 ',
|
||||
],
|
||||
},
|
||||
|
||||
CAR.GENESIS_GV60_EV_1ST_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00JW1 MFC AT AUS RHD 1.00 1.03 99211-CU100 221118',
|
||||
@@ -1189,7 +1228,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00MQ4HMFC AT KOR LHD 1.00 1.12 99210-P2000 230331',
|
||||
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.10 99210-P2000 210406',
|
||||
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.11 99210-P2000 211217',
|
||||
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.12 99210-P2000 230331',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00MQhe SCC FHCUP 1.00 1.04 99110-P4000 ',
|
||||
@@ -1250,40 +1288,15 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00US4_ RDR ----- 1.00 1.00 99110-CG000 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_NEXO_1ST_GEN: {
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00FE IEB \x01 312 \x11\x13 58520-M5000',
|
||||
CAR.KIA_EV9: { # (MV)
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00MV__ RDR ----- 1.00 1.02 99110-DO700 ',
|
||||
b'\xf1\x00MV__ RDR ----- 1.00 1.02 99110-DO000 '
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00FE MFC AT KOR LHD 1.00 1.00 99211-M5100 201218',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00FE MDPS C 1.00 1.05 56340-M5000 9903',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00FE__ SCC FHCUP 1.00 1.05 99110-M5000 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_KONA_2022: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00OSP LKA AT CND LHD 1.00 1.04 99211-J9200 904',
|
||||
b'\xf1\x00OSP LKA AT USA LHD 1.00 1.04 99211-J9200 904',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.04 56310/J9290 4OPCC104',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.04 56310/J9291 4OPCC104',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.04 56310J9291\x00 4OPCC104',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00YB__ FCA ----- 1.00 1.01 99110-J9000 \x00\x00\x00',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xf1\x00HT6WA280BLHT6VA650A1COS4N20NS1\x00\x00\x00\x00\x00\x00\x15\xf5\x87~',
|
||||
b'\xf1\x00T01960BL T01E60A1 DOS2T16X4XE60NS4N\x90\xe6\xcb',
|
||||
b'\xf1\x00T01G00BL T01I00A1 DOS2T16X2XI00NS0\x8c`\xff\xe7',
|
||||
b'\xf1\x00T01G00BL T01I00A1 DOS2T16X4XI00NS0\x99L\xeeq',
|
||||
b'\xf1\x00MV MFC AT KOR LHD 1.00 1.01 99211-DO000 230419',
|
||||
b'\xf1\x00MV MFC AT USA LHD 1.00 1.02 99211-DO000 230616',
|
||||
b'\xf1\x00MV MFC AT EUR LHD 1.00 1.02 99211-DO000 230616',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
FW_VERSIONS = extend_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
import copy
|
||||
import crcmod
|
||||
from iqdbc.car.hyundai.values import CAR, HyundaiFlags
|
||||
|
||||
from iqdbc.lvbs.car.hyundai.escc import EnhancedSmartCruiseControl
|
||||
from iqdbc.lvbs.car.hyundai.lead_data_ext import CanLeadData
|
||||
|
||||
hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
|
||||
|
||||
def suppress_casper_ev_fca11_fault(values):
|
||||
# CASPER EV can report transient FCA faults during camera-SCC handoff.
|
||||
# Keep the copied FCA11 frame non-faulting without changing other cars.
|
||||
fca_fault = values["FCA_Failinfo"] != 0 or values["FCA_Status"] == 3
|
||||
values["FCA_Failinfo"] = 0
|
||||
|
||||
if fca_fault:
|
||||
values["FCA_Status"] = 2
|
||||
values["CF_VSM_Prefill"] = 0
|
||||
values["CF_VSM_HBACmd"] = 0
|
||||
values["CF_VSM_Warn"] = 0
|
||||
values["CF_VSM_BeltCmd"] = 0
|
||||
values["CR_VSM_DecCmd"] = 0
|
||||
values["FCA_CmdAct"] = 0
|
||||
values["FCA_StopReq"] = 0
|
||||
values["CF_VSM_DecCmdAct"] = 0
|
||||
|
||||
return values
|
||||
|
||||
def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||
left_lane, right_lane,
|
||||
left_lane_depart, right_lane_depart,
|
||||
lkas_icon):
|
||||
left_lane_depart, right_lane_depart, is_ldws_car):
|
||||
|
||||
values = {s: lkas11[s] for s in [
|
||||
"CF_Lkas_LdwsActivemode",
|
||||
"CF_Lkas_LdwsSysState",
|
||||
@@ -30,7 +46,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
"CF_Lkas_LdwsOpt_USM",
|
||||
]}
|
||||
values["CF_Lkas_LdwsSysState"] = sys_state
|
||||
values["CF_Lkas_SysWarning"] = 3 if sys_warning else 0
|
||||
values["CF_Lkas_SysWarning"] = 0 # 3 if sys_warning else 0
|
||||
values["CF_Lkas_LdwsLHWarning"] = left_lane_depart
|
||||
values["CF_Lkas_LdwsRHWarning"] = right_lane_depart
|
||||
values["CR_Lkas_StrToqReq"] = apply_torque
|
||||
@@ -38,16 +54,10 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
values["CF_Lkas_ToiFlt"] = torque_fault # seems to allow actuation on CR_Lkas_StrToqReq
|
||||
values["CF_Lkas_MsgCount"] = frame % 0x10
|
||||
|
||||
if CP.carFingerprint in (CAR.HYUNDAI_SONATA, CAR.HYUNDAI_PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_NIRO_PHEV_2022, CAR.HYUNDAI_SANTA_FE,
|
||||
CAR.HYUNDAI_IONIQ_EV_2020, CAR.HYUNDAI_IONIQ_PHEV, CAR.KIA_SELTOS, CAR.HYUNDAI_ELANTRA_2021, CAR.GENESIS_G70_2020,
|
||||
CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
|
||||
CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
|
||||
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
|
||||
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022,
|
||||
CAR.KIA_CEED_PHEV_2022_NON_SCC, CAR.HYUNDAI_KONA_EV_NON_SCC, CAR.HYUNDAI_ELANTRA_2022_NON_SCC,
|
||||
CAR.GENESIS_G70_2021_NON_SCC, CAR.KIA_SELTOS_2023_NON_SCC, CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC):
|
||||
|
||||
if CP.flags & HyundaiFlags.SEND_LFA.value or CP.carFingerprint in (CAR.HYUNDAI_SANTA_FE):
|
||||
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
|
||||
values["CF_Lkas_LdwsOpt_USM"] = 2
|
||||
values["CF_Lkas_LdwsOpt_USM"] = 0 if CP.carFingerprint in (CAR.KIA_RAY_EV) else 2
|
||||
|
||||
# FcwOpt_USM 5 = Orange blinking car + lanes
|
||||
# FcwOpt_USM 4 = Orange car + lanes
|
||||
@@ -55,16 +65,16 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
# FcwOpt_USM 2 = Green car + lanes
|
||||
# FcwOpt_USM 1 = White car + lanes
|
||||
# FcwOpt_USM 0 = No car + lanes
|
||||
values["CF_Lkas_FcwOpt_USM"] = lkas_icon
|
||||
values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
|
||||
|
||||
# SysWarning 4 = keep hands on wheel
|
||||
# SysWarning 5 = keep hands on wheel (red)
|
||||
# SysWarning 6 = keep hands on wheel (red) + beep
|
||||
# Note: the warning is hidden while the blinkers are on
|
||||
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
||||
values["CF_Lkas_SysWarning"] = 0 #4 if sys_warning else 0
|
||||
|
||||
# Likely cars lacking the ability to show individual lane lines in the dash
|
||||
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.HYUNDAI_KONA_NON_SCC):
|
||||
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
|
||||
# SysWarning 4 = keep hands on wheel + beep
|
||||
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
||||
|
||||
@@ -72,7 +82,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
# SysState 1-2 = white car + lanes
|
||||
# SysState 3 = green car + lanes, green steering wheel
|
||||
# SysState 4 = green car + lanes
|
||||
values["CF_Lkas_LdwsSysState"] = lkas_icon
|
||||
values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
|
||||
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
|
||||
|
||||
# these have no effect
|
||||
@@ -84,6 +94,11 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
# Genesis and Optima fault when forwarding while engaged
|
||||
values["CF_Lkas_LdwsActivemode"] = 2
|
||||
|
||||
if is_ldws_car:
|
||||
values["CF_Lkas_LdwsOpt_USM"] = 3
|
||||
|
||||
values["CF_Lkas_Chksum"] = 0
|
||||
|
||||
dat = packer.make_can_msg("LKAS11", 0, values)[1]
|
||||
|
||||
if CP.flags & HyundaiFlags.CHECKSUM_CRC8:
|
||||
@@ -124,145 +139,265 @@ def create_clu11(packer, frame, clu11, button, CP):
|
||||
return packer.make_can_msg("CLU11", bus, values)
|
||||
|
||||
|
||||
def create_lfahda_mfc(packer, enabled, lfa_icon):
|
||||
def create_lfahda_mfc(packer, CC, blinking_signal):
|
||||
activeCarrot = CC.hudControl.activeCarrot
|
||||
values = {
|
||||
"LFA_Icon_State": lfa_icon,
|
||||
"LFA_Icon_State": 2 if CC.latActive else 1 if CC.enabled else 0,
|
||||
#"HDA_Active": 1 if activeCarrot >= 2 else 0,
|
||||
#"HDA_Icon_State": 2 if activeCarrot == 3 and blinking_signal else 2 if activeCarrot >= 2 else 0,
|
||||
"HDA_Icon_State": 0 if activeCarrot == 3 and blinking_signal else 2 if activeCarrot >= 1 else 0,
|
||||
"HDA_VSetReq": 0, #set_speed_in_units if activeCarrot >= 2 else 0,
|
||||
"HDA_USM" : 2,
|
||||
"HDA_Icon_Wheel" : 1 if CC.latActive else 0,
|
||||
#"HDA_Chime" : 1 if CC.latActive else 0, # comment for K9 chime,
|
||||
}
|
||||
return packer.make_can_msg("LFAHDA_MFC", 0, values)
|
||||
|
||||
def create_acc_commands_scc(packer, enabled, accel, jerk, idx, hud_control, set_speed, stopping, long_override, suppress_casper_ev_fca, CS, soft_hold_mode):
|
||||
from iqdbc.car.hyundai.carcontroller import HyundaiJerk
|
||||
cruise_available = CS.out.cruiseState.available
|
||||
if CS.paddle_button_prev > 0:
|
||||
cruise_available = False
|
||||
soft_hold_active = CS.softHoldActive
|
||||
soft_hold_info = soft_hold_active > 1 and enabled
|
||||
#soft_hold_mode = 2 ## some cars can't enable while braking
|
||||
long_enabled = enabled or (soft_hold_active > 0 and soft_hold_mode == 2)
|
||||
stop_req = 1 if stopping or (soft_hold_active > 0 and soft_hold_mode == 2) else 0
|
||||
d = hud_control.leadDistance
|
||||
objGap = 0 if d == 0 else 2 if d < 25 else 3 if d < 40 else 4 if d < 70 else 5
|
||||
objGap2 = 0 if objGap == 0 else 2 if hud_control.leadRelSpeed < -0.2 else 1
|
||||
|
||||
if long_enabled:
|
||||
if jerk.carrot_cruise == 1:
|
||||
long_enabled = False
|
||||
accel = -0.5
|
||||
elif jerk.carrot_cruise == 2:
|
||||
accel = jerk.carrot_cruise_accel
|
||||
|
||||
if long_enabled:
|
||||
scc12_acc_mode = 2 if long_override else 1
|
||||
scc14_acc_mode = 2 if long_override else 1
|
||||
if CS.out.brakeHoldActive:
|
||||
scc12_acc_mode = 0
|
||||
scc14_acc_mode = 4
|
||||
elif CS.out.brakePressed:
|
||||
scc12_acc_mode = 1
|
||||
scc14_acc_mode = 1
|
||||
else:
|
||||
scc12_acc_mode = 0
|
||||
scc14_acc_mode = 4
|
||||
|
||||
warning_front = False
|
||||
|
||||
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_data: CanLeadData,
|
||||
hud_control, set_speed, stopping, long_override, use_fca, CP,
|
||||
main_cruise_enabled, tuning, ESCC: EnhancedSmartCruiseControl | None = None):
|
||||
commands = []
|
||||
if CS.scc11 is not None:
|
||||
values = copy.copy(CS.scc11)
|
||||
values["MainMode_ACC"] = 1 if cruise_available else 0
|
||||
values["TauGapSet"] = hud_control.leadDistanceBars
|
||||
values["VSetDis"] = set_speed if enabled else 0
|
||||
values["AliveCounterACC"] = idx % 0x10
|
||||
values["SCCInfoDisplay"] = 3 if warning_front else 4 if soft_hold_info else 0 if enabled else 0 #2: 크루즈 선택, 3: 전방상황주의, 4: 출발준비
|
||||
values["ObjValid"] = 1 if hud_control.leadVisible else 0
|
||||
values["ACC_ObjStatus"] = 1 if hud_control.leadVisible else 0
|
||||
values["ACC_ObjLatPos"] = 0
|
||||
values["ACC_ObjRelSpd"] = hud_control.leadRelSpeed
|
||||
values["ACC_ObjDist"] = int(hud_control.leadDistance)
|
||||
values["DriverAlertDisplay"] = 0
|
||||
commands.append(packer.make_can_msg("SCC11", 0, values))
|
||||
|
||||
def get_scc11_values():
|
||||
return {
|
||||
"MainMode_ACC": 1 if main_cruise_enabled else 0,
|
||||
"TauGapSet": hud_control.leadDistanceBars,
|
||||
"VSetDis": set_speed if enabled else 0,
|
||||
"AliveCounterACC": idx % 0x10,
|
||||
"ObjValid": int(lead_data.lead_visible), # close lead makes controls tighter
|
||||
"ACC_ObjStatus": int(lead_data.lead_visible), # close lead makes controls tighter
|
||||
"ACC_ObjLatPos": 0,
|
||||
"ACC_ObjRelSpd": lead_data.lead_rel_speed,
|
||||
"ACC_ObjDist": int(lead_data.lead_distance), # close lead makes controls tighter
|
||||
}
|
||||
if CS.scc12 is not None:
|
||||
values = copy.copy(CS.scc12)
|
||||
values["ACCMode"] = scc12_acc_mode #2 if enabled and long_override else 1 if long_enabled else 0
|
||||
values["StopReq"] = stop_req
|
||||
values["aReqRaw"] = accel
|
||||
values["aReqValue"] = accel
|
||||
values["ACCFailInfo"] = 0
|
||||
|
||||
def get_scc12_values():
|
||||
scc12_values = {
|
||||
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
|
||||
"StopReq": 1 if tuning.stopping else 0,
|
||||
"aReqRaw": tuning.desired_accel,
|
||||
"aReqValue": tuning.actual_accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
||||
"CR_VSM_Alive": idx % 0xF,
|
||||
}
|
||||
#values["DESIRED_DIST"] = CS.out.vEgo * 1.0 + 4.0 # TF: 1.0 + STOPDISTANCE 4.0 m로 가정함.
|
||||
|
||||
# show AEB disabled indicator on dash with SCC12 if not sending FCA messages.
|
||||
# these signals also prevent a TCS fault on non-FCA cars with alpha longitudinal
|
||||
if not use_fca:
|
||||
scc12_values["CF_VSM_ConfMode"] = 1
|
||||
scc12_values["AEB_Status"] = 1 # AEB disabled
|
||||
|
||||
# Since we have ESCC available, we can update SCC12 with ESCC values.
|
||||
if ESCC and ESCC.enabled:
|
||||
ESCC.update_scc12(scc12_values)
|
||||
|
||||
return scc12_values
|
||||
|
||||
def calculate_scc12_checksum(values):
|
||||
values["CR_VSM_ChkSum"] = 0
|
||||
values["CR_VSM_Alive"] = idx % 0xF
|
||||
scc12_dat = packer.make_can_msg("SCC12", 0, values)[1]
|
||||
values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10
|
||||
return values
|
||||
|
||||
def get_scc14_values():
|
||||
return {
|
||||
"ComfortBandUpper": tuning.comfort_band_upper, # stock usually is 0 but sometimes uses higher values
|
||||
"ComfortBandLower": tuning.comfort_band_lower, # stock usually is 0 but sometimes uses higher values
|
||||
"JerkUpperLimit": tuning.jerk_upper, # stock usually is 1.0 but sometimes uses higher values
|
||||
"JerkLowerLimit": tuning.jerk_lower, # stock usually is 0.5 but sometimes uses higher values
|
||||
"ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
||||
"ObjGap": lead_data.object_gap, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||
"ObjDistStat": lead_data.object_rel_gap,
|
||||
}
|
||||
commands.append(packer.make_can_msg("SCC12", 0, values))
|
||||
|
||||
def get_fca11_values():
|
||||
return {
|
||||
if CS.scc14 is not None:
|
||||
values = copy.copy(CS.scc14)
|
||||
values["ComfortBandUpper"] = jerk.cb_upper
|
||||
values["ComfortBandLower"] = jerk.cb_lower
|
||||
values["JerkUpperLimit"] = jerk.jerk_u
|
||||
values["JerkLowerLimit"] = jerk.jerk_l if long_enabled else 0 # for KONA test
|
||||
values["ACCMode"] = scc14_acc_mode #2 if enabled and long_override else 1 if long_enabled else 4 # stock will always be 4 instead of 0 after first disengage
|
||||
values["ObjGap"] = objGap #2 if hud_control.leadVisible else 0 # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||
values["ObjDistStat"] = objGap2
|
||||
commands.append(packer.make_can_msg("SCC14", 0, values))
|
||||
|
||||
if CS.fca11 is not None and suppress_casper_ev_fca: # CASPER_EV의 경우 FCA11에서 fail이 간헐적 발생함.. 그냥막자.. 원인불명..
|
||||
values = suppress_casper_ev_fca11_fault(copy.copy(CS.fca11))
|
||||
fca11_dat = packer.make_can_msg("FCA11", 0, values)[1]
|
||||
values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
|
||||
commands.append(packer.make_can_msg("FCA11", 0, values))
|
||||
# Only send FCA11 on cars where it exists on the bus
|
||||
if False: #use_fca:
|
||||
# note that some vehicles most likely have an alternate checksum/counter definition
|
||||
# https://github.com/commaai/iqdbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
|
||||
fca11_values = {
|
||||
"CR_FCA_Alive": idx % 0xF,
|
||||
"PAINT1_Status": 1,
|
||||
"FCA_DrvSetStatus": 1,
|
||||
"FCA_Status": 1,
|
||||
"FCA_Status": 1, # AEB disabled
|
||||
}
|
||||
|
||||
def calculate_fca11_checksum(values):
|
||||
fca11_dat = packer.make_can_msg("FCA11", 0, values)[1]
|
||||
values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
|
||||
return values
|
||||
|
||||
scc11_values = get_scc11_values()
|
||||
commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
|
||||
|
||||
scc12_values = get_scc12_values()
|
||||
scc12_values = calculate_scc12_checksum(scc12_values)
|
||||
commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
|
||||
|
||||
scc14_values = get_scc14_values()
|
||||
commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
|
||||
|
||||
# Only send FCA11 on cars where it exists on the bus
|
||||
# On Camera SCC cars, FCA11 is not disabled, so we forward stock FCA11 back to the car forward hooks
|
||||
# If we don't use ESCC since ESCC does not block FCA11 from stock radar
|
||||
if use_fca and not ((CP.flags & HyundaiFlags.CAMERA_SCC) or (ESCC and ESCC.enabled)):
|
||||
# note that some vehicles most likely have an alternate checksum/counter definition
|
||||
# https://github.com/commaai/iqdbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
|
||||
fca11_values = get_fca11_values()
|
||||
fca11_values = calculate_fca11_checksum(fca11_values)
|
||||
fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[1]
|
||||
fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
|
||||
commands.append(packer.make_can_msg("FCA11", 0, fca11_values))
|
||||
|
||||
return commands
|
||||
|
||||
def create_acc_opt_copy(CS, packer):
|
||||
values = copy.copy(CS.scc13)
|
||||
if values["NEW_SIGNAL_1"] == 255:
|
||||
values["NEW_SIGNAL_1"] = 218
|
||||
values["NEW_SIGNAL_2"] = 0
|
||||
return packer.make_can_msg("SCC13", 0, CS.scc13)
|
||||
|
||||
def create_acc_opt(packer, CP, ESCC: EnhancedSmartCruiseControl | None = None):
|
||||
"""
|
||||
Creates SCC13 and FCA12. If ESCC is enabled, it will only create SCC13 since ESCC does not block FCA12.
|
||||
:param packer:
|
||||
:param ESCC:
|
||||
:return:
|
||||
"""
|
||||
def create_acc_commands(packer, enabled, accel, jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP, CS, soft_hold_mode):
|
||||
from iqdbc.car.hyundai.carcontroller import HyundaiJerk
|
||||
cruise_available = CS.out.cruiseState.available
|
||||
soft_hold_active = CS.softHoldActive
|
||||
soft_hold_info = soft_hold_active > 1 and enabled
|
||||
#soft_hold_mode = 2 ## some cars can't enable while braking
|
||||
long_enabled = enabled or (soft_hold_active > 0 and soft_hold_mode == 2)
|
||||
stop_req = 1 if stopping or (soft_hold_active > 0 and soft_hold_mode == 2) else 0
|
||||
d = hud_control.leadDistance
|
||||
objGap = 0 if d == 0 else 2 if d < 25 else 3 if d < 40 else 4 if d < 70 else 5
|
||||
objGap2 = 0 if objGap == 0 else 2 if hud_control.leadRelSpeed < -0.2 else 1
|
||||
|
||||
def get_scc13_values():
|
||||
return {
|
||||
"SCCDrvModeRValue": 2,
|
||||
"SCC_Equip": 1,
|
||||
"Lead_Veh_Dep_Alert_USM": 2,
|
||||
}
|
||||
if long_enabled:
|
||||
scc12_acc_mode = 2 if long_override else 1
|
||||
scc14_acc_mode = 2 if long_override else 1
|
||||
if CS.out.brakeHoldActive:
|
||||
scc12_acc_mode = 0
|
||||
scc14_acc_mode = 4
|
||||
elif CS.out.brakePressed:
|
||||
scc12_acc_mode = 1
|
||||
scc14_acc_mode = 1
|
||||
else:
|
||||
scc12_acc_mode = 0
|
||||
scc14_acc_mode = 4
|
||||
|
||||
def get_fca12_values():
|
||||
return {
|
||||
"FCA_DrvSetState": 2,
|
||||
"FCA_USM": 1, # AEB disabled
|
||||
}
|
||||
warning_front = False
|
||||
|
||||
commands = []
|
||||
|
||||
scc13_values = get_scc13_values()
|
||||
commands.append(packer.make_can_msg("SCC13", 0, scc13_values))
|
||||
scc11_values = {
|
||||
"MainMode_ACC": 1 if cruise_available else 0,
|
||||
"TauGapSet": hud_control.leadDistanceBars,
|
||||
"VSetDis": set_speed if enabled else 0,
|
||||
"AliveCounterACC": idx % 0x10,
|
||||
"SCCInfoDisplay": 3 if warning_front else 4 if soft_hold_info else 0 if enabled else 0,
|
||||
"ObjValid": 1 if hud_control.leadVisible else 0, # close lead makes controls tighter
|
||||
"ACC_ObjStatus": 1 if hud_control.leadVisible else 0, # close lead makes controls tighter
|
||||
"ACC_ObjLatPos": 0,
|
||||
"ACC_ObjRelSpd": hud_control.leadRelSpeed,
|
||||
"ACC_ObjDist": int(hud_control.leadDistance), # close lead makes controls tighter
|
||||
"DriverAlertDisplay": 0,
|
||||
}
|
||||
commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
|
||||
|
||||
# If ESCC is available and enabled, we skip FCA12, since ESCC does not block FCA12
|
||||
if ESCC and ESCC.enabled:
|
||||
return commands
|
||||
scc12_values = {
|
||||
"ACCMode": scc12_acc_mode,
|
||||
"StopReq": stop_req,
|
||||
"aReqRaw": 0 if stop_req > 0 else accel,
|
||||
"aReqValue": accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
||||
#"DESIRED_DIST": CS.out.vEgo * 1.0 + 4.0,
|
||||
"CR_VSM_Alive": idx % 0xF,
|
||||
}
|
||||
|
||||
# show AEB disabled indicator on dash with SCC12 if not sending FCA messages.
|
||||
# these signals also prevent a TCS fault on non-FCA cars with alpha longitudinal
|
||||
if not use_fca:
|
||||
scc12_values["CF_VSM_ConfMode"] = 1
|
||||
scc12_values["AEB_Status"] = 1 # AEB disabled
|
||||
|
||||
scc12_dat = packer.make_can_msg("SCC12", 0, scc12_values)[1]
|
||||
scc12_values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10
|
||||
|
||||
commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
|
||||
|
||||
scc14_values = {
|
||||
"ComfortBandUpper": jerk.cb_upper, # stock usually is 0 but sometimes uses higher values
|
||||
"ComfortBandLower": jerk.cb_lower, # stock usually is 0 but sometimes uses higher values
|
||||
"JerkUpperLimit": jerk.jerk_u, # stock usually is 1.0 but sometimes uses higher values
|
||||
"JerkLowerLimit": jerk.jerk_l, # stock usually is 0.5 but sometimes uses higher values
|
||||
"ACCMode": scc14_acc_mode, # if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
||||
"ObjGap": objGap, #2 if hud_control.leadVisible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||
"ObjDistStat": objGap2,
|
||||
}
|
||||
commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
|
||||
|
||||
# Only send FCA11 on cars where it exists on the bus
|
||||
# On Camera SCC cars, FCA11 is not disabled, so we forward stock FCA11 back to the car forward hooks
|
||||
if use_fca and not (CP.flags & HyundaiFlags.CAMERA_SCC):
|
||||
# note that some vehicles most likely have an alternate checksum/counter definition
|
||||
# https://github.com/commaai/iqdbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
|
||||
fca11_values = {
|
||||
"CR_FCA_Alive": idx % 0xF,
|
||||
"PAINT1_Status": 1,
|
||||
"FCA_DrvSetStatus": 1,
|
||||
"FCA_Status": 1, # AEB disabled
|
||||
}
|
||||
fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[1]
|
||||
fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
|
||||
commands.append(packer.make_can_msg("FCA11", 0, fca11_values))
|
||||
|
||||
return commands
|
||||
|
||||
def create_acc_opt(packer, CP):
|
||||
commands = []
|
||||
|
||||
scc13_values = {
|
||||
"SCCDrvModeRValue": 2,
|
||||
"SCC_Equip": 1,
|
||||
"Lead_Veh_Dep_Alert_USM": 2,
|
||||
}
|
||||
commands.append(packer.make_can_msg("SCC13", 0, scc13_values))
|
||||
|
||||
# TODO: this needs to be detected and conditionally sent on unsupported long cars
|
||||
# On Camera SCC cars, FCA12 is not disabled, so we forward stock FCA12 back to the car forward hooks
|
||||
if not (CP.flags & HyundaiFlags.CAMERA_SCC):
|
||||
fca12_values = get_fca12_values()
|
||||
fca12_values = {
|
||||
"FCA_DrvSetState": 2,
|
||||
"FCA_USM": 1, # AEB disabled
|
||||
}
|
||||
commands.append(packer.make_can_msg("FCA12", 0, fca12_values))
|
||||
|
||||
return commands
|
||||
|
||||
|
||||
def create_frt_radar_opt(packer):
|
||||
frt_radar11_values = {
|
||||
"CF_FCA_Equip_Front_Radar": 1,
|
||||
}
|
||||
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
|
||||
|
||||
def create_clu11_button(packer, frame, clu11, button, CP):
|
||||
values = clu11.copy()
|
||||
values["CF_Clu_CruiseSwState"] = button
|
||||
#values["CF_Clu_AliveCnt1"] = frame % 0x10
|
||||
values["CF_Clu_AliveCnt1"] = (values["CF_Clu_AliveCnt1"] + 1) % 0x10
|
||||
# send buttons to camera on camera-scc based cars
|
||||
bus = 2 if CP.flags & HyundaiFlags.CAMERA_SCC else 0
|
||||
return packer.make_can_msg("CLU11", bus, values)
|
||||
|
||||
def create_mdps12(packer, frame, mdps12):
|
||||
values = mdps12
|
||||
values["CF_Mdps_ToiActive"] = 0
|
||||
values["CF_Mdps_ToiUnavail"] = 1
|
||||
values["CF_Mdps_MsgCount2"] = frame % 0x100
|
||||
values["CF_Mdps_Chksum2"] = 0
|
||||
|
||||
dat = packer.make_can_msg("MDPS12", 2, values)[1]
|
||||
checksum = sum(dat) % 256
|
||||
values["CF_Mdps_Chksum2"] = checksum
|
||||
|
||||
return packer.make_can_msg("MDPS12", 2, values)
|
||||
|
||||
@@ -2,22 +2,42 @@ import copy
|
||||
import numpy as np
|
||||
from iqdbc.car import CanBusBase
|
||||
from iqdbc.car.crc import CRC16_XMODEM
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags
|
||||
from iqdbc.lvbs.car.hyundai.lead_data_ext import CanFdLeadData
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, HyundaiExtFlags
|
||||
from openpilot.common.params import Params
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from cereal import log
|
||||
|
||||
LaneChangeState = log.LaneChangeState
|
||||
LaneChangeDirection = log.LaneChangeDirection
|
||||
TurnDirection = log.Desire
|
||||
|
||||
|
||||
def hyundai_crc8(data: bytes) -> int:
|
||||
poly = 0x2F
|
||||
crc = 0xFF
|
||||
|
||||
for byte in data:
|
||||
crc ^= byte
|
||||
for _ in range(8):
|
||||
if crc & 0x80:
|
||||
crc = ((crc << 1) ^ poly) & 0xFF
|
||||
else:
|
||||
crc = (crc << 1) & 0xFF
|
||||
|
||||
return crc ^ 0xFF
|
||||
|
||||
class CanBus(CanBusBase):
|
||||
def __init__(self, CP, fingerprint=None, lka_steering=None) -> None:
|
||||
super().__init__(CP, fingerprint)
|
||||
|
||||
if lka_steering is None:
|
||||
lka_steering = CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value if CP is not None else False
|
||||
lka_steering = CP.flags & HyundaiFlags.CANFD_HDA2.value if CP is not None else False
|
||||
|
||||
# On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. LKA steering cars
|
||||
# have a different harness than the LFA steering variants in order to split
|
||||
# a different bus, since the steering is done by different ECUs.
|
||||
self._a, self._e = 1, 0
|
||||
if lka_steering:
|
||||
if lka_steering and Params().get_int("HyundaiCameraSCC") == 0: #배선개조는 무조건 Bus0가 ECAN임.
|
||||
self._a, self._e = 0, 1
|
||||
|
||||
self._a += self.offset
|
||||
@@ -36,50 +56,190 @@ class CanBus(CanBusBase):
|
||||
def CAM(self):
|
||||
return self._cam
|
||||
|
||||
# CAN LIST (CAM) - 롱컨개조시... ADAS + CAM
|
||||
# 160: ADRV_0x160
|
||||
# 1da: ADRV_0x1da
|
||||
# 1ea: ADRV_0x1ea
|
||||
# 200: ADRV_0x200
|
||||
# 345: ADRV_0x345
|
||||
# 1fa: CLUSTER_SPEED_LIMIT
|
||||
# 12a: LFA
|
||||
# 1e0: LFAHDA_CLUSTER
|
||||
# 11a:
|
||||
# 1b5:
|
||||
# 1a0: SCC_CONTROL
|
||||
|
||||
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque, lkas_icon):
|
||||
common_values = {
|
||||
"LKA_MODE": 2,
|
||||
"LKA_ICON": lkas_icon,
|
||||
"TORQUE_REQUEST": apply_torque,
|
||||
"LKA_ASSIST": 0,
|
||||
"STEER_REQ": 1 if lat_active else 0,
|
||||
"STEER_MODE": 0,
|
||||
"HAS_LANE_SAFETY": 0, # hide LKAS settings
|
||||
"NEW_SIGNAL_2": 0,
|
||||
"DAMP_FACTOR": 100, # can potentially tuned for better perf [3, 200]
|
||||
}
|
||||
# CAN LIST (ACAN)
|
||||
# 160: ADRV_0x160
|
||||
# 51: ADRV_0x51
|
||||
# 180: CAM_0x180
|
||||
# ...
|
||||
# 185: CAM_0x185
|
||||
# 1b6: CAM_0x1b6
|
||||
# ...
|
||||
# 1b9: CAM_0x1b9
|
||||
# 1fb: CAM_0x1fb
|
||||
# 2a2 - 2a4
|
||||
# 2bb - 2be
|
||||
# LKAS
|
||||
# 201 - 2a0
|
||||
|
||||
lkas_values = copy.copy(common_values)
|
||||
lkas_values["LKA_AVAILABLE"] = 0
|
||||
|
||||
lfa_values = copy.copy(common_values)
|
||||
lfa_values["NEW_SIGNAL_1"] = 0
|
||||
|
||||
def create_steering_messages_camera_scc(frame, packer, CP, CAN, CC, lat_active, apply_steer, CS, apply_angle, max_torque, angle_control):
|
||||
|
||||
emergency_steering = False
|
||||
if CS.adrv_0x161 is not None:
|
||||
values = CS.adrv_0x161
|
||||
emergency_steering = values["ALERTS_1"] in [11, 12, 13, 14, 15, 21, 22, 23, 24, 25, 26]
|
||||
|
||||
|
||||
ret = []
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
|
||||
if CP.openpilotLongitudinalControl:
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
|
||||
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values))
|
||||
else:
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
|
||||
if CS.mdps is not None:
|
||||
values = copy.copy(CS.mdps)
|
||||
#rx_counter = values.pop("COUNTER", None)
|
||||
if angle_control:
|
||||
if CS.lfa_alt is not None:
|
||||
values["LFA2_ACTIVE"] = CS.lfa_alt["LKAS_ANGLE_ACTIVE"]
|
||||
else:
|
||||
if CS.lfa is not None:
|
||||
values["LKA_ACTIVE"] = 1 if CS.lfa["STEER_REQ"] == 1 else 0
|
||||
|
||||
if frame % 1000 < 40:
|
||||
values["STEERING_COL_TORQUE"] += 220
|
||||
#ret.append(packer.make_can_msg("MDPS", CAN.CAM, values, rx_counter = rx_counter))
|
||||
ret.append(packer.make_can_msg("MDPS", CAN.CAM, values))
|
||||
|
||||
if frame % 10 == 0:
|
||||
if CS.steer_touch_2af is not None:
|
||||
values = copy.copy(CS.steer_touch_2af)
|
||||
if frame % 1000 < 40:
|
||||
values["TOUCH_DETECT"] = 3
|
||||
values["TOUCH1"] = 50
|
||||
values["TOUCH2"] = 50
|
||||
values["CHECKSUM_"] = 0
|
||||
dat = packer.make_can_msg("STEER_TOUCH_2AF", 0, values)[1]
|
||||
values["CHECKSUM_"] = hyundai_crc8(dat[1:8])
|
||||
|
||||
ret.append(packer.make_can_msg("STEER_TOUCH_2AF", CAN.CAM, values))
|
||||
|
||||
if angle_control:
|
||||
if CS.lfa_alt is not None:
|
||||
values = copy.copy(CS.lfa_alt)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
if emergency_steering:
|
||||
pass
|
||||
else:
|
||||
#values = {} #CS.lfa_alt
|
||||
values["LKAS_ANGLE_ACTIVE"] = 2 if CC.latActive else 1
|
||||
values["LKAS_ANGLE_CMD"] = -apply_angle
|
||||
values["LKAS_ANGLE_MAX_TORQUE"] = max_torque if CC.latActive else 0
|
||||
ret.append(packer.make_can_msg("LFA_ALT", CAN.ECAN, values, rx_counter = rx_counter))
|
||||
|
||||
if CS.lfa is not None:
|
||||
values = copy.copy(CS.lfa)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
if not emergency_steering:
|
||||
values["LKA_MODE"] = 0
|
||||
values["LKA_ICON"] = 2 if CC.latActive else 1
|
||||
values["TORQUE_REQUEST"] = -1024 # apply_steer,
|
||||
values["VALUE63"] = 0 # LKA_ASSIST
|
||||
values["STEER_REQ"] = 0 # 1 if lat_active else 0,
|
||||
values["HAS_LANE_SAFETY"] = 0 # hide LKAS settings
|
||||
values["LKA_ACTIVE"] = 3 if CC.latActive else 0 # this changes sometimes, 3 seems to indicate engaged
|
||||
values["VALUE64"] = 0 #STEER_MODE, NEW_SIGNAL_2
|
||||
values["LKAS_ANGLE_CMD"] = -25.6 #-apply_angle,
|
||||
values["LKAS_ANGLE_ACTIVE"] = 0 #2 if lat_active else 1,
|
||||
values["LKAS_ANGLE_MAX_TORQUE"] = 0 #max_torque if lat_active else 0,
|
||||
values["NEW_SIGNAL_1"] = 10
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values, rx_counter = rx_counter))
|
||||
|
||||
elif CS.lfa is not None:
|
||||
values = {}
|
||||
values["LKA_MODE"] = 2
|
||||
values["LKA_ICON"] = 2 if lat_active else 1
|
||||
values["TORQUE_REQUEST"] = apply_steer
|
||||
values["STEER_REQ"] = 1 if lat_active else 0
|
||||
values["VALUE64"] = 0 # STEER_MODE, NEW_SIGNAL_2
|
||||
values["HAS_LANE_SAFETY"] = 0
|
||||
values["LKA_ACTIVE"] = 0 # NEW_SIGNAL_1
|
||||
|
||||
values["DampingGain"] = 0 if lat_active else 100
|
||||
#values["VALUE63"] = 0
|
||||
|
||||
#values["VALUE82_SET256"] = 0
|
||||
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||
|
||||
return ret
|
||||
|
||||
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer, apply_angle, max_torque, angle_control):
|
||||
|
||||
def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt):
|
||||
suppress_msg = "CAM_0x362" if lka_steering_alt else "CAM_0x2a4"
|
||||
msg_bytes = 32 if lka_steering_alt else 24
|
||||
ret = []
|
||||
if angle_control:
|
||||
values = {
|
||||
"LKA_MODE": 0,
|
||||
"LKA_ICON": 2 if enabled else 1,
|
||||
"TORQUE_REQUEST": 0, # apply_steer,
|
||||
"VALUE63": 0, # LKA_ASSIST
|
||||
"STEER_REQ": 0, # 1 if lat_active else 0,
|
||||
"HAS_LANE_SAFETY": 0, # hide LKAS settings
|
||||
"LKA_ACTIVE": 3 if lat_active else 0, # this changes sometimes, 3 seems to indicate engaged
|
||||
"VALUE64": 0, #STEER_MODE, NEW_SIGNAL_2
|
||||
"LKAS_ANGLE_CMD": -apply_angle,
|
||||
"LKAS_ANGLE_ACTIVE": 2 if lat_active else 1,
|
||||
"LKAS_ANGLE_MAX_TORQUE": max_torque if lat_active else 0,
|
||||
|
||||
values = {f"BYTE{i}": lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
|
||||
# test for EV6PE
|
||||
"NEW_SIGNAL_1": 10, #2,
|
||||
"DampingGain": 9,
|
||||
"VALUE231": 146,
|
||||
"VALUE239": 1,
|
||||
"VALUE247": 255,
|
||||
"VALUE255": 255,
|
||||
}
|
||||
else:
|
||||
values = {
|
||||
"LKA_MODE": 2,
|
||||
"LKA_ICON": 2 if enabled else 1,
|
||||
"TORQUE_REQUEST": apply_steer,
|
||||
"DampingGain": 100, #3 if enabled else 100,
|
||||
"STEER_REQ": 1 if lat_active else 0,
|
||||
#"STEER_MODE": 0,
|
||||
"HAS_LANE_SAFETY": 0, # hide LKAS settings
|
||||
"VALUE63": 0,
|
||||
"VALUE64": 100,
|
||||
}
|
||||
|
||||
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "LKAS"
|
||||
if CP.openpilotLongitudinalControl:
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||
if not (CP.flags & HyundaiFlags.CAMERA_SCC.value):
|
||||
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, values))
|
||||
else:
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||
|
||||
return ret
|
||||
|
||||
def create_suppress_lfa(packer, CAN, CS):
|
||||
if CS.cam_0x362 is not None:
|
||||
suppress_msg = "CAM_0x362"
|
||||
lfa_block_msg = CS.cam_0x362
|
||||
elif CS.cam_0x2a4 is not None:
|
||||
suppress_msg = "CAM_0x2a4"
|
||||
lfa_block_msg = CS.cam_0x2a4
|
||||
else:
|
||||
return []
|
||||
|
||||
#values = {f"BYTE{i}": lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
|
||||
values = copy.copy(lfa_block_msg)
|
||||
values["COUNTER"] = lfa_block_msg["COUNTER"]
|
||||
values["SET_ME_0"] = 0
|
||||
values["SET_ME_0_2"] = 0
|
||||
values["LEFT_LANE_LINE"] = 0
|
||||
values["RIGHT_LANE_LINE"] = 0
|
||||
return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
|
||||
|
||||
return [packer.make_can_msg(suppress_msg, CAN.ACAN, values)]
|
||||
|
||||
def create_buttons(packer, CP, CAN, cnt, btn):
|
||||
values = {
|
||||
@@ -88,14 +248,12 @@ def create_buttons(packer, CP, CAN, cnt, btn):
|
||||
"CRUISE_BUTTONS": btn,
|
||||
}
|
||||
|
||||
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM
|
||||
#bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
|
||||
bus = CAN.ECAN
|
||||
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
|
||||
|
||||
|
||||
def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
|
||||
# CAN FD camera-based SCC requires additional signals to be preserved
|
||||
# verbatim from the previous SCC_CONTROL frame to avoid checksum or
|
||||
# state validation faults. Classic CAN SCC only validates a subset.
|
||||
# TODO: why do we copy different values here?
|
||||
if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value:
|
||||
values = {s: cruise_info_copy[s] for s in [
|
||||
"COUNTER",
|
||||
@@ -124,49 +282,169 @@ def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
|
||||
})
|
||||
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||
|
||||
|
||||
def create_lfahda_cluster(packer, CAN, enabled, lfa_icon):
|
||||
values = {
|
||||
"HDA_ICON": 1 if enabled else 0,
|
||||
"LFA_ICON": lfa_icon,
|
||||
}
|
||||
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
|
||||
def create_lfahda_cluster(packer, CS, CAN, long_active, lat_active):
|
||||
|
||||
|
||||
def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control,
|
||||
lead_data: CanFdLeadData, main_cruise_enabled, tuning):
|
||||
if CS.lfahda_cluster is not None:
|
||||
values = copy.copy(CS.lfahda_cluster)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
else:
|
||||
return []
|
||||
values = {}
|
||||
rx_counter = None
|
||||
values["LFA_OptUsmSta"] = 2
|
||||
values["HDA_OptUsmSta"] = 2
|
||||
values["HDA_CntrlModSta"] = 2 if long_active else 0
|
||||
values["HDA_LFA_SymSta"] = 2 if lat_active else 0
|
||||
return [packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values, rx_counter=rx_counter)]
|
||||
|
||||
def create_lfa_icon_non_camera_scc(packer, CS, CAN, CC):
|
||||
ret = []
|
||||
if CS.adrv_0x161 is not None:
|
||||
values = copy.copy(CS.adrv_0x161)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
|
||||
lat_active = CC.latActive
|
||||
lat_enabled = CS.out.latEnabled
|
||||
|
||||
values["LFA_ICON"] = 2 if lat_active else 1 if lat_enabled else 0
|
||||
values["LKA_ICON"] = 4 if lat_active else 3 if lat_enabled else 0
|
||||
|
||||
if values["ALERTS_2"] in [1, 2, 5, 6, 10, 21, 22]:
|
||||
values["ALERTS_2"] = 0
|
||||
values["DAW_ICON"] = 0
|
||||
|
||||
if values["ALERTS_1"] == 0:
|
||||
values["SOUNDS_1"] = 0
|
||||
values["SOUNDS_2"] = 0
|
||||
values["SOUNDS_4"] = 0
|
||||
|
||||
if values["ALERTS_3"] in [3, 4, 11, 12, 13, 14, 17, 19, 26, 7, 8, 9, 10]:
|
||||
values["ALERTS_3"] = 0
|
||||
values["SOUNDS_3"] = 0
|
||||
|
||||
if values["ALERTS_5"] in [1, 2, 3, 4, 5]:
|
||||
values["ALERTS_5"] = 0
|
||||
|
||||
ret.append(packer.make_can_msg("ADRV_0x161", CAN.ECAN, values, rx_counter=rx_counter))
|
||||
return ret
|
||||
|
||||
def create_acc_control_scc2(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control, hyundai_jerk, CS):
|
||||
|
||||
if CS.scc_control is None:
|
||||
return None
|
||||
enabled = (enabled or CS.softHoldActive > 0) and CS.paddle_button_prev == 0
|
||||
|
||||
acc_mode = 0 if not enabled else (2 if gas_override else 1)
|
||||
|
||||
if hyundai_jerk.carrot_cruise == 1:
|
||||
acc_mode = 4 if enabled else 0
|
||||
enabled = False
|
||||
accel = accel_last = 0.5
|
||||
|
||||
elif hyundai_jerk.carrot_cruise == 2:
|
||||
accel = accel_last = hyundai_jerk.carrot_cruise_accel
|
||||
|
||||
jerk_u = hyundai_jerk.jerk_u
|
||||
jerk_l = hyundai_jerk.jerk_l
|
||||
jerk = 5
|
||||
jn = jerk / 50
|
||||
if not enabled or gas_override:
|
||||
a_val, a_raw = 0, 0
|
||||
else:
|
||||
a_raw = accel # noqa: F841
|
||||
a_val = np.clip(accel, accel_last - jn, accel_last + jn) # noqa: F841
|
||||
a_raw = accel
|
||||
a_val = accel #np.clip(accel, accel_last - jn, accel_last + jn)
|
||||
|
||||
values = copy.copy(CS.scc_control)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
values["ACCMode"] = acc_mode
|
||||
values["MainMode_ACC"] = 1
|
||||
values["StopReq"] = 1 if stopping or CS.softHoldActive > 0 else 0 # 1: Stop control is required, 2: Not used, 3: Error Indicator
|
||||
values["aReqValue"] = a_val
|
||||
values["aReqRaw"] = a_raw
|
||||
values["VSetDis"] = set_speed
|
||||
#values["JerkLowerLimit"] = jerk if enabled else 1
|
||||
#values["JerkUpperLimit"] = 3.0
|
||||
values["JerkLowerLimit"] = jerk_l if enabled else 1
|
||||
values["JerkUpperLimit"] = 2.0 if stopping or CS.softHoldActive else jerk_u
|
||||
values["DISTANCE_SETTING"] = hud_control.leadDistanceBars # + 5
|
||||
#values["DISTANCE_SETTING"] = hud_control.leadDistanceBars + 5
|
||||
|
||||
#values["ACC_ObjDist"] = 1
|
||||
#values["ObjValid"] = 0
|
||||
#values["OBJ_STATUS"] = 2
|
||||
#values["NSCCOper"] = 1 if enabled else 0 # 0: off, 1: Ready, 2: Act, 3: Error Indicator
|
||||
#values["NSCCOnOff"] = 2 # 0: Default, 1: Off, 2: On, 3: Invalid
|
||||
#values["SET_ME_3"] = 0x3 # objRelsped와 충돌
|
||||
#values["ACC_ObjLatPos"] = - hud_control.leadDPath
|
||||
values["DriveMode"] = 0 # 0: Default, 1: Comfort Mode, 2:Normal mode, 3:Dynamic mode, reserved
|
||||
|
||||
hud_lead_info = 0
|
||||
if hud_control.leadVisible:
|
||||
hud_lead_info = 1 if values["ACC_ObjRelSpd"] > 0 else 2
|
||||
values["HUD_LEAD_INFO"] = hud_lead_info #1: in-path object detected(uncontrollable), 2: controllable long, 3: controllable long & lat, ... reserved
|
||||
|
||||
values["DriverAlert"] = 0 # 1: SCC Disengaged, 2: No SCC Engage condition, 3: SCC Disenganed when the vehicle stops
|
||||
|
||||
values["TARGET_DISTANCE"] = CS.out.vEgo * 1.0 + 4.0
|
||||
|
||||
soft_hold_info = 1 if CS.softHoldActive > 1 and enabled else 0
|
||||
|
||||
# 이거안하면 정지중 뒤로 밀리는 현상 발생하는듯.. (신호정지중에 뒤로 밀리는 경험함.. 시험해봐야)
|
||||
if values["InfoDisplay"] != 5: #5: Front Car Departure Notice
|
||||
values["InfoDisplay"] = 4 if stopping and CS.out.aEgo > -0.3 else 0 # 1: SCC Mode, 2: Convention Cruise Mode, 3: Object disappered at low speed, 4: Available to resume acceleration control, 5: Front vehicle departure notice, 6: Reserved, 7: Invalid
|
||||
|
||||
values["TakeOverReq"] = 0 # 1: Takeover request, 2: Not used, 3: Error indicator , 이것이 켜지면 가속을 안하는듯함.
|
||||
#values["NEW_SIGNAL_4"] = 9 if hud_control.leadVisible else 0
|
||||
# AccelLimitBandUpper, Lower
|
||||
values["SysFailState"] = 0 # 1: Performance degredation, 2: system temporairy unavailble, 3: SCC Service required , 눈이 묻어 레이더오류시... 2가 됨. 이때 가속을 안함...
|
||||
|
||||
values["AccelLimitBandUpper"] = 0.0 # 이값이 1.26일때 가속을 안하는 증상이 보임..
|
||||
values["AccelLimitBandLower"] = 0.0
|
||||
|
||||
values["ZEROS_7"] = 1
|
||||
|
||||
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||
|
||||
def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control, jerk_u, jerk_l, CS):
|
||||
|
||||
enabled = enabled or CS.softHoldActive > 0
|
||||
jerk = 5
|
||||
jn = jerk / 50
|
||||
if not enabled or gas_override:
|
||||
a_val, a_raw = 0, 0
|
||||
else:
|
||||
a_raw = accel
|
||||
a_val = np.clip(accel, accel_last - jn, accel_last + jn)
|
||||
|
||||
values = {
|
||||
"ACCMode": 0 if not enabled else (2 if gas_override else 1),
|
||||
"MainMode_ACC": 1 if main_cruise_enabled else 0,
|
||||
"StopReq": 1 if tuning.stopping else 0,
|
||||
"aReqValue": tuning.actual_accel,
|
||||
"aReqRaw": tuning.actual_accel,
|
||||
"MainMode_ACC": 1,
|
||||
"StopReq": 1 if stopping or CS.softHoldActive > 0 else 0,
|
||||
"aReqValue": a_val,
|
||||
"aReqRaw": a_raw,
|
||||
"VSetDis": set_speed,
|
||||
"JerkLowerLimit": tuning.jerk_lower,
|
||||
"JerkUpperLimit": tuning.jerk_upper,
|
||||
#"JerkLowerLimit": jerk if enabled else 1,
|
||||
#"JerkUpperLimit": 3.0,
|
||||
"JerkLowerLimit": jerk_l if enabled else 1,
|
||||
"JerkUpperLimit": jerk_u,
|
||||
|
||||
"ACC_ObjDist": int(lead_data.lead_distance),
|
||||
"ACC_ObjRelSpd": lead_data.lead_rel_speed,
|
||||
"ObjValid": int(not lead_data.lead_visible),
|
||||
"SCC_ObjSta": 0 if not (enabled and lead_data.lead_visible) else (1 if gas_override else 2),
|
||||
"SET_ME_2": 0x4,
|
||||
"SET_ME_3": 0x3,
|
||||
"SET_ME_TMP_64": 0x64,
|
||||
"DISTANCE_SETTING": hud_control.leadDistanceBars,
|
||||
"ACC_ObjDist": 1,
|
||||
#"ObjValid": 0,
|
||||
#"OBJ_STATUS": 2,
|
||||
"NSCCOper": 0,
|
||||
"NSCCOnOff": 2,
|
||||
"DriveMode": 0,
|
||||
#"SET_ME_3": 0x3,
|
||||
"ACC_ObjLatPos": 0x64,
|
||||
"DISTANCE_SETTING": hud_control.leadDistanceBars, # + 5,
|
||||
"InfoDisplay": 4 if stopping and CS.out.cruiseState.standstill else 0,
|
||||
}
|
||||
|
||||
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||
|
||||
|
||||
def create_spas_messages(packer, CAN, left_blink, right_blink):
|
||||
def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
|
||||
ret = []
|
||||
|
||||
values = {
|
||||
@@ -186,8 +464,10 @@ def create_spas_messages(packer, CAN, left_blink, right_blink):
|
||||
return ret
|
||||
|
||||
|
||||
def create_fca_warning_light(packer, CAN, frame):
|
||||
def create_fca_warning_light(CP, packer, CAN, frame):
|
||||
ret = []
|
||||
if CP.flags & HyundaiFlags.CAMERA_SCC.value:
|
||||
return ret
|
||||
|
||||
if frame % 2 == 0:
|
||||
values = {
|
||||
@@ -196,53 +476,100 @@ def create_fca_warning_light(packer, CAN, frame):
|
||||
'SET_ME_FF': 0xff,
|
||||
'SET_ME_FC': 0xfc,
|
||||
'SET_ME_9': 0x9,
|
||||
#'DATA102': 1,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
|
||||
return ret
|
||||
|
||||
def create_tcs_messages(packer, CAN, CS):
|
||||
ret = []
|
||||
if CS.tcs is not None:
|
||||
values = copy.copy(CS.tcs)
|
||||
#rx_counter = values.pop("COUNTER", None)
|
||||
values["DriverBraking"] = 0
|
||||
values["NEW_SIGNAL_20"] = 0
|
||||
values["NEW_SIGNAL_11"] = 0
|
||||
values["DriverBrakingLowSens"] = 0
|
||||
#values["NEW_SIGNAL_1"] = 0 # accel과 관련.. 옆두부 꺼지는것과 관련? 확인필요
|
||||
#values["ACC_REQ"] = 1 # 옆두부 꺼지는것과 관련? 확인필요.. 항상 켜지게함..
|
||||
values["NEW_SIGNAL_1"] = 0 if values["ACC_REQ"] == 1 else 1 # 옆두부..
|
||||
#ret.append(packer.make_can_msg("TCS", CAN.CAM, values, rx_counter = rx_counter))
|
||||
ret.append(packer.make_can_msg("TCS", CAN.CAM, values))
|
||||
return ret
|
||||
|
||||
def create_adrv_messages(packer, CAN, frame):
|
||||
def forward_button_message(packer, CAN, frame, CS, cruise_button, MainMode_ACC_trigger, LFA_trigger):
|
||||
ret = []
|
||||
if frame % 2 == 0:
|
||||
if CS.cruise_buttons_msg is not None:
|
||||
values = copy.copy(CS.cruise_buttons_msg)
|
||||
# A held MAIN is reported on this bit and switches some clusters to LIMIT mode.
|
||||
values["NORMAL_CRUISE_MAIN_BTN"] = 0
|
||||
#rx_counter = values.pop("COUNTER", None)
|
||||
cruise_button_driver = values["CRUISE_BUTTONS"]
|
||||
if cruise_button_driver == 0:
|
||||
values["CRUISE_BUTTONS"] = cruise_button
|
||||
if MainMode_ACC_trigger > 0:
|
||||
#values["ADAPTIVE_CRUISE_MAIN_BTN"] = 1
|
||||
pass
|
||||
elif LFA_trigger > 0:
|
||||
values["LFA_BTN"] = 1
|
||||
|
||||
#ret.append(packer.make_can_msg(CS.cruise_btns_msg_canfd, CAN.CAM, values, rx_counter = rx_counter))
|
||||
ret.append(packer.make_can_msg(CS.cruise_btns_msg_canfd, CAN.CAM, values))
|
||||
return ret
|
||||
|
||||
def create_adrv_messages(CP, packer, CAN, frame):
|
||||
# messages needed to car happy after disabling
|
||||
# the ADAS Driving ECU to do longitudinal control
|
||||
|
||||
ret = []
|
||||
|
||||
values = {
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
||||
if not CP.flags & HyundaiFlags.CAMERA_SCC.value:
|
||||
values = {}
|
||||
|
||||
ret.extend(create_fca_warning_light(packer, CAN, frame))
|
||||
ret.extend(create_fca_warning_light(CP, packer, CAN, frame))
|
||||
if frame % 5 == 0:
|
||||
values = {
|
||||
#'HDA_MODE1': 0x8,
|
||||
'HDA_MODE2': 0x1,
|
||||
#'SET_ME_1C': 0x1c,
|
||||
'SET_ME_FF': 0xff,
|
||||
#'SET_ME_TMP_F': 0xf,
|
||||
#'SET_ME_TMP_F_2': 0xf,
|
||||
#'DATA26': 1, #1
|
||||
#'DATA32': 5, #5
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
|
||||
|
||||
if frame % 5 == 0:
|
||||
values = {
|
||||
'SET_ME_1C': 0x1c,
|
||||
'SET_ME_FF': 0xff,
|
||||
'SET_ME_TMP_F': 0xf,
|
||||
'SET_ME_TMP_F_2': 0xf,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
|
||||
values = {
|
||||
'SET_ME_E1': 0xe1,
|
||||
#'SET_ME_3A': 0x3a,
|
||||
'TauGapSet' : 1,
|
||||
'NEW_SIGNAL_2': 3,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
|
||||
|
||||
values = {
|
||||
'SET_ME_E1': 0xe1,
|
||||
'SET_ME_3A': 0x3a,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
|
||||
if frame % 20 == 0:
|
||||
values = {
|
||||
'SET_ME_15': 0x15,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
|
||||
|
||||
if frame % 20 == 0:
|
||||
values = {
|
||||
'SET_ME_15': 0x15,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
|
||||
|
||||
if frame % 100 == 0:
|
||||
values = {
|
||||
'SET_ME_22': 0x22,
|
||||
'SET_ME_41': 0x41,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
|
||||
if frame % 100 == 0:
|
||||
values = {
|
||||
'SET_ME_22': 0x22,
|
||||
'SET_ME_41': 0x41,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
|
||||
|
||||
return ret
|
||||
|
||||
## carrot
|
||||
def alt_cruise_buttons(packer, CP, CAN, buttons, cruise_btns_msg, cnt):
|
||||
cruise_btns_msg["CRUISE_BUTTONS"] = buttons
|
||||
cruise_btns_msg["COUNTER"] = (cruise_btns_msg["COUNTER"] + 1 + cnt) % 256
|
||||
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
|
||||
return packer.make_can_msg("CRUISE_BUTTONS_ALT", bus, cruise_btns_msg)
|
||||
|
||||
def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
|
||||
crc = 0
|
||||
@@ -259,3 +586,348 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
|
||||
elif len(d) == 32:
|
||||
crc ^= 0x9F5B
|
||||
return crc
|
||||
|
||||
|
||||
|
||||
|
||||
def _clip_int(x, lo, hi):
|
||||
return lo if x < lo else hi if x > hi else int(x)
|
||||
|
||||
def _get_desire_and_lane_changing(md):
|
||||
desire = 0
|
||||
lane_changing = 0
|
||||
if md is not None:
|
||||
desire = md.meta.desire.raw
|
||||
ds = md.meta.desireState
|
||||
if len(ds) > 4:
|
||||
if ds[1] > 0.9: lane_changing = 1
|
||||
if ds[2] > 0.9: lane_changing = 2
|
||||
if ds[3] > 0.9: lane_changing = 3
|
||||
if ds[4] > 0.9: lane_changing = 4
|
||||
return desire, lane_changing
|
||||
|
||||
def _apply_lane_desire(values, desire):
|
||||
#values['LANE_CHANGING'] = 0
|
||||
|
||||
if desire == 1: # 좌회전
|
||||
values['LANE_CHANGING'] = 1
|
||||
values["LANELINE_CURVATURE"] = 15
|
||||
values["LANELINE_CURVATURE_DIRECTION"] = 0
|
||||
|
||||
elif desire == 2: # 우회전
|
||||
values['LANE_CHANGING'] = 2
|
||||
values["LANELINE_CURVATURE"] = 15
|
||||
values["LANELINE_CURVATURE_DIRECTION"] = 1
|
||||
|
||||
elif desire == 3: # 좌차선변경
|
||||
values['LANE_CHANGING'] = 3
|
||||
|
||||
elif desire == 4: # 우차선변경
|
||||
values['LANE_CHANGING'] = 4
|
||||
|
||||
def _apply_radar_blink(values, radar_pairs, frame, *,
|
||||
disp_dist=30.0, min_dist=14.0,
|
||||
max_interval=100, t=1.0):
|
||||
"""
|
||||
거리 > min_dist 일 때만 깜빡임.
|
||||
거리 멀수록 interval 커짐(느리게).
|
||||
"""
|
||||
for det_key, dist_key in radar_pairs:
|
||||
dist = values[dist_key]
|
||||
if dist <= min_dist:
|
||||
continue
|
||||
|
||||
d = min(dist, disp_dist)
|
||||
interval = int((1 + (max_interval - 1) * (d / disp_dist)) * t)
|
||||
interval = _clip_int(interval, 1, max_interval)
|
||||
|
||||
blink = (frame // interval) & 1
|
||||
values[det_key] = 2 - blink
|
||||
values[dist_key] = min_dist
|
||||
|
||||
def _suppress_trailer_mode_warning(values, CS):
|
||||
# Logs from IONIQ 9 show ALERTS_5=6 is the periodic
|
||||
# "driver assistance limited in trailer mode" popup.
|
||||
if CS.trailer_connected and values.get("ALERTS_5") == 6:
|
||||
values["ALERTS_5"] = 0
|
||||
|
||||
def _make_ccnc_values(values, CS, lat_active, frame, hud_control,
|
||||
lane_line=True, corner_radar=True,
|
||||
desire=0,
|
||||
blink_pairs=None,
|
||||
blink_t=1.0):
|
||||
if lane_line:
|
||||
curvature = round(CS.out.steeringAngleDeg / 3)
|
||||
mag = min(abs(curvature), 15)
|
||||
curv = mag + (-1 if curvature < 0 else 0)
|
||||
direction = 1 if curvature < 0 else 0
|
||||
values["LANELINE_CURVATURE"] = curv if lat_active else 0
|
||||
values["LANELINE_CURVATURE_DIRECTION"] = direction if lat_active else 0
|
||||
if desire:
|
||||
_apply_lane_desire(values, desire)
|
||||
|
||||
if corner_radar:
|
||||
radar_all = [
|
||||
('LF_DETECT', 'LF_DETECT_DISTANCE'),
|
||||
('RF_DETECT', 'RF_DETECT_DISTANCE'),
|
||||
('LR_DETECT', 'LR_DETECT_DISTANCE'),
|
||||
('RR_DETECT', 'RR_DETECT_DISTANCE'),
|
||||
]
|
||||
for det_key, dist_key in radar_all:
|
||||
if values[det_key] >= 4 and values[dist_key] != 0:
|
||||
values[det_key] = 1
|
||||
|
||||
if blink_pairs:
|
||||
_apply_radar_blink(values, blink_pairs, frame, t=blink_t)
|
||||
|
||||
def create_ccnc_messages(CP, packer, CAN, frame, CC, CS, hud_control,
|
||||
disp_angle, left_lane_warning, right_lane_warning,
|
||||
enable_corner_radar, stopping, canfd_debug):
|
||||
ret = []
|
||||
|
||||
md = CS.modelV2
|
||||
if not hasattr(create_ccnc_messages, '_lane_line_check') or frame % 100 == 0:
|
||||
create_ccnc_messages._lane_line_check = Params().get_int("LaneLineCheck")
|
||||
lane_line_check = create_ccnc_messages._lane_line_check
|
||||
desire, lane_changing = _get_desire_and_lane_changing(md)
|
||||
|
||||
if CP.flags & HyundaiFlags.CAMERA_SCC.value:
|
||||
HDA_CntrlModSta = 0
|
||||
HDA_LFA_SymSta = 0
|
||||
if CS.lfahda_cluster is not None:
|
||||
HDA_CntrlModSta = CS.lfahda_cluster["HDA_CntrlModSta"]
|
||||
HDA_LFA_SymSta = CS.lfahda_cluster["HDA_LFA_SymSta"]
|
||||
|
||||
if frame % 2 == 0:
|
||||
#if CS.adrv_0x160 is not None:
|
||||
# values = copy.copy(CS.adrv_0x160)
|
||||
# ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
|
||||
|
||||
if CS.cruise_buttons_msg is not None:
|
||||
values = copy.copy(CS.cruise_buttons_msg)
|
||||
# Keep the physical long press on ECAN for CarState, but don't forward it to CAM.
|
||||
values["NORMAL_CRUISE_MAIN_BTN"] = 0
|
||||
|
||||
if HDA_LFA_SymSta == 0 and 0 < frame % 200 < 12:
|
||||
values["LFA_BTN"] = 1
|
||||
|
||||
if CC.enabled:
|
||||
if not CS.MainMode_ACC:
|
||||
if 10 < frame % 200 <= 16 and CS.out.vEgo > 3.:
|
||||
values["ADAPTIVE_CRUISE_MAIN_BTN"] = 1
|
||||
elif CS.ACCMode in [0, 4]:
|
||||
if 10 < frame % 200 <= 16 and CS.out.vEgo > 3.:
|
||||
values["CRUISE_BUTTONS"] = 2
|
||||
elif CS.scc_control is not None and CS.scc_control["InfoDisplay"] == 4:
|
||||
if 10 < frame % 30 <= 16 and not stopping:
|
||||
values["CRUISE_BUTTONS"] = 2
|
||||
else:
|
||||
if CS.adrv_0x1ea is not None and CS.adrv_0x1ea["HDA_MODE2"] == 0: # if corner radar is disabled, send main btn
|
||||
if 10 < frame % 1000 <= 16 and CS.out.vEgo > 3:
|
||||
values["ADAPTIVE_CRUISE_MAIN_BTN"] = 1
|
||||
|
||||
ret.append(packer.make_can_msg(CS.cruise_btns_msg_canfd, CAN.CAM, values))
|
||||
|
||||
# --- 0x161/0x200/0x1ea/0x162 (frame%5) ---
|
||||
if frame % 5 == 0:
|
||||
lat_active = CC.latActive
|
||||
|
||||
if CS.adrv_0x161 is not None:
|
||||
main_enabled = CS.out.cruiseState.available
|
||||
cruise_enabled = CC.enabled
|
||||
lat_enabled = CS.out.latEnabled
|
||||
nav_active = hud_control.activeCarrot > 1
|
||||
|
||||
# hdpuse carrot
|
||||
hdp_use = int(Params().get("HDPuse"))
|
||||
hdp_active = False
|
||||
if hdp_use == 1:
|
||||
hdp_active = cruise_enabled and nav_active
|
||||
elif hdp_use == 2:
|
||||
hdp_active = cruise_enabled
|
||||
# hdpuse carrot
|
||||
|
||||
values = copy.copy(CS.adrv_0x161)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
values["SETSPEED"] = (6 if hdp_active else 3 if cruise_enabled else 1) if main_enabled else 0
|
||||
values["SETSPEED_HUD"] = (5 if hdp_active else 3 if cruise_enabled else 1) if main_enabled else 0
|
||||
|
||||
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||
values["vSetDis"] = int(set_speed_in_units + 0.5)
|
||||
|
||||
values["DISTANCE"] = 4 if hdp_active else hud_control.leadDistanceBars
|
||||
values["DISTANCE_LEAD"] = 2 if cruise_enabled and hud_control.leadVisible else 1 if main_enabled and hud_control.leadVisible else 0
|
||||
values["DISTANCE_CAR"] = 3 if hdp_active else 2 if cruise_enabled else 1 if main_enabled else 0
|
||||
values["DISTANCE_SPACING"] = 5 if hdp_active else 1 if cruise_enabled else 0
|
||||
|
||||
values["TARGET"] = 1 if hud_control.leadVisible and cruise_enabled else 0
|
||||
values["TARGET_DISTANCE"] = int(hud_control.leadDistance)
|
||||
|
||||
values["BACKGROUND"] = 6 if CS.paddle_button_prev > 0 else 1 if cruise_enabled else 3 if lat_active else 7
|
||||
values["CENTERLINE"] = 1 if HDA_CntrlModSta > 0 else 0
|
||||
values["CAR_CIRCLE"] = 2 if hdp_active else 1 if cruise_enabled else 0
|
||||
|
||||
values["NAV_ICON"] = 2 if nav_active and cruise_enabled else 1 if main_enabled and nav_active else 0
|
||||
values["HDA_ICON"] = 5 if hdp_active else 2 if cruise_enabled else 1 if main_enabled else 0
|
||||
values["LFA_ICON"] = 5 if hdp_active else 2 if lat_active else 1 if lat_enabled else 0
|
||||
values["LKA_ICON"] = 4 if lat_active else 3 if lat_enabled else 0
|
||||
values["FCA_ALT_ICON"] = 0
|
||||
|
||||
if values["ALERTS_2"] in [1, 2, 5, 6, 10, 21, 22]:
|
||||
values["ALERTS_2"] = 0
|
||||
values["DAW_ICON"] = 0
|
||||
|
||||
if values["ALERTS_1"] == 0: # alerts가 있으면 사운드도 같이 나옴
|
||||
values["SOUNDS_1"] = 0
|
||||
values["SOUNDS_2"] = 0
|
||||
values["SOUNDS_4"] = 0
|
||||
|
||||
if values["ALERTS_3"] in [3, 4, 11, 12, 13, 14, 17, 19, 20, 26, 27, 28, 7, 8, 9, 10]: # hide gap distance msg.(11,12,13,14), lanechange(19,20,27, 28)
|
||||
values["ALERTS_3"] = 0
|
||||
values["SOUNDS_3"] = 0
|
||||
|
||||
if values["ALERTS_5"] in [1, 2, 3, 4, 5]:
|
||||
values["ALERTS_5"] = 0
|
||||
|
||||
if values["ALERTS_5"] in [11] and CS.softHoldActive == 0:
|
||||
values["ALERTS_5"] = 0
|
||||
|
||||
# curvature 표시(0x161쪽 기존 로직 유지)
|
||||
_suppress_trailer_mode_warning(values, CS)
|
||||
|
||||
curvature = round(CS.out.steeringAngleDeg / 3)
|
||||
values["LANELINE_CURVATURE"] = (min(abs(curvature), 15) + (-1 if curvature < 0 else 0)) if lat_active else 0
|
||||
values["LANELINE_CURVATURE_DIRECTION"] = 1 if curvature < 0 and lat_active else 0
|
||||
|
||||
trailer_lane_change_blocked = CS.trailer_connected
|
||||
if trailer_lane_change_blocked:
|
||||
values["LANELINE_LEFT"] = 2 if hud_control.leftLaneVisible else 0
|
||||
values["LANELINE_RIGHT"] = 2 if hud_control.rightLaneVisible else 0
|
||||
else:
|
||||
lane_color = 6 if md is not None and md.meta.laneChangeAvailableLeft else 2
|
||||
if lane_line_check >= 1:
|
||||
lane_line_warn_left = CS.out.leftLaneLine % 10 not in (0, 5)
|
||||
else:
|
||||
lane_line_warn_left = CS.out.leftLaneLine // 10 == 2
|
||||
lane_color = 4 if lane_line_warn_left or CS.out.leftBlindspot else lane_color
|
||||
if hud_control.leftLaneDepart:
|
||||
values["LANELINE_LEFT"] = 4 if (frame // 50) % 2 == 0 else 1
|
||||
else:
|
||||
values["LANELINE_LEFT"] = lane_color if hud_control.leftLaneVisible else 0
|
||||
|
||||
lane_color = 6 if md is not None and md.meta.laneChangeAvailableRight else 2
|
||||
if lane_line_check >= 1:
|
||||
lane_line_warn_right = CS.out.rightLaneLine % 10 not in (0, 5)
|
||||
else:
|
||||
lane_line_warn_right = CS.out.rightLaneLine // 10 == 2
|
||||
lane_color = 4 if lane_line_warn_right or CS.out.rightBlindspot else lane_color
|
||||
if hud_control.rightLaneDepart:
|
||||
values["LANELINE_RIGHT"] = 4 if (frame // 50) % 2 == 0 else 1
|
||||
else:
|
||||
values["LANELINE_RIGHT"] = lane_color if hud_control.rightLaneVisible else 0
|
||||
|
||||
values["LCA_LEFT_ARROW"] = 2 if CS.out.leftBlinker else 0
|
||||
values["LCA_RIGHT_ARROW"] = 2 if CS.out.rightBlinker else 0
|
||||
|
||||
if trailer_lane_change_blocked:
|
||||
values["LCA_LEFT_ICON"] = 1 if lat_active else 0
|
||||
values["LCA_RIGHT_ICON"] = 1 if lat_active else 0
|
||||
else:
|
||||
values["LCA_LEFT_ICON"] = (1 if CS.out.leftBlindspot else 2) if lat_active else 0
|
||||
values["LCA_RIGHT_ICON"] = (1 if CS.out.rightBlindspot else 2) if lat_active else 0
|
||||
|
||||
values["LANE_LEFT"] = 0 if trailer_lane_change_blocked else 1 if desire in (1, 3) else 0
|
||||
values["LANE_RIGHT"] = 0 if trailer_lane_change_blocked else 1 if desire in (2, 4) else 0
|
||||
|
||||
ret.append(packer.make_can_msg("ADRV_0x161", CAN.ECAN, values, rx_counter = rx_counter))
|
||||
|
||||
if CS.adrv_0x200 is not None:
|
||||
values = copy.copy(CS.adrv_0x200)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
values["TauGapSet"] = hud_control.leadDistanceBars
|
||||
ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values, rx_counter = rx_counter))
|
||||
|
||||
if CS.adrv_0x1ea is not None:
|
||||
values = copy.copy(CS.adrv_0x1ea)
|
||||
rx_counter = values.pop("COUNTER", None)
|
||||
# blinker hold
|
||||
values['LEFT_BLINK_HOLD'] = 1 if lane_changing == 3 else 0
|
||||
values['RIGHT_BLINK_HOLD'] = 1 if lane_changing == 4 else 0
|
||||
|
||||
_make_ccnc_values(
|
||||
values, CS, lat_active, frame, hud_control,
|
||||
lane_line=True,
|
||||
corner_radar=True,
|
||||
desire=desire,
|
||||
# 기존대로 LR/RR만 깜빡임
|
||||
blink_pairs=[('LR_DETECT', 'LR_DETECT_DISTANCE'),
|
||||
('RR_DETECT', 'RR_DETECT_DISTANCE')],
|
||||
blink_t=1.0
|
||||
)
|
||||
|
||||
ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values, rx_counter = rx_counter))
|
||||
|
||||
if CS.ccnc_0x162 is not None:
|
||||
values = copy.copy(CS.ccnc_0x162)
|
||||
|
||||
if hud_control.leadDistance > 0:
|
||||
values["FF_DISTANCE"] = hud_control.leadDistance
|
||||
ff_type = 3 if hud_control.leadRadar == 1 else 13
|
||||
values["FF_DETECT"] = ff_type if hud_control.leadRelSpeed > -0.1 else ff_type + 1
|
||||
|
||||
_make_ccnc_values(
|
||||
values, CS, lat_active, frame, hud_control,
|
||||
lane_line=False,
|
||||
corner_radar=True,
|
||||
desire=0,
|
||||
# 필요하면 162도 깜빡임 적용(원래 코드처럼 LR/RR만)
|
||||
blink_pairs=[('LR_DETECT', 'LR_DETECT_DISTANCE'),
|
||||
('RR_DETECT', 'RR_DETECT_DISTANCE')],
|
||||
blink_t=1.0
|
||||
)
|
||||
|
||||
if (left_lane_warning and not CS.out.leftBlinker) or (right_lane_warning and not CS.out.rightBlinker):
|
||||
values["VIBRATE"] = 1
|
||||
|
||||
if canfd_debug > 0:
|
||||
values["FAULT_LSS"] = 0
|
||||
values["FAULT_DAS"] = 0
|
||||
|
||||
ret.append(packer.make_can_msg("CCNC_0x162", CAN.ECAN, values))
|
||||
|
||||
# --- NEW_MSG_4B9 (corner radar keep-alive?) ---
|
||||
if enable_corner_radar > 0:
|
||||
if HDA_CntrlModSta == 0:
|
||||
if frame % 500 in [10, 20, 30]:
|
||||
values = {
|
||||
'BYTE_1': 0,
|
||||
'BYTE_2': 0,
|
||||
'BYTE_3': 0x80,
|
||||
'BYTE_4': 0x8A,
|
||||
'BYTE_5': 0x32,
|
||||
'BYTE_6': 0x30,
|
||||
'BYTE_7': 0x01,
|
||||
'BYTE_8': 0x00,
|
||||
}
|
||||
ret.append(packer.make_can_msg("NEW_MSG_4B9", CAN.CAM, values))
|
||||
elif frame % 500 in [40, 50, 60]:
|
||||
values = {
|
||||
'BYTE_1': 0xff,
|
||||
'BYTE_2': 0xff,
|
||||
'BYTE_3': 0xff,
|
||||
'BYTE_4': 0xff,
|
||||
'BYTE_5': 0xff,
|
||||
'BYTE_6': 0xff,
|
||||
'BYTE_7': 0xff,
|
||||
'BYTE_8': 0xff,
|
||||
}
|
||||
ret.append(packer.make_can_msg("NEW_MSG_4B9", CAN.CAM, values))
|
||||
|
||||
if False: # canfd_debug > 1 and frame % 20 == 0:
|
||||
if CS.hda_info_4a3 is not None:
|
||||
values = copy.copy(CS.hda_info_4a3)
|
||||
values["LinkClass"] = 1
|
||||
values["SPEED_LIMIT"] = 100
|
||||
ret.append(packer.make_can_msg("HDA_INFO_4A3", CAN.CAM, values))
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from iqdbc.car import Bus, get_safety_config, structs, uds
|
||||
from iqdbc.car import Bus, get_safety_config, structs
|
||||
from iqdbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, CAR, DBC, \
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags, HyundaiFlagsIQ, CAR, DBC, CANFD_RADAR_SCC_CAR, \
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, HyundaiSafetyFlagsIQ, HyundaiExtFlags, \
|
||||
CANFD_HYBRID_STATUS_ADDR, CANFD_HYBRID_STATUS_DLC, \
|
||||
EV_MODE_STATUS_ADDR, EV_MODE_STATUS_DLC
|
||||
from iqdbc.car.hyundai.radar_interface import RADAR_START_ADDR
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
from iqdbc.car.disable_ecu import disable_ecu
|
||||
@@ -10,9 +12,7 @@ from iqdbc.car.hyundai.carcontroller import CarController
|
||||
from iqdbc.car.hyundai.carstate import CarState
|
||||
from iqdbc.car.hyundai.radar_interface import RadarInterface
|
||||
|
||||
from iqdbc.lvbs.car.hyundai.escc import ESCC_MSG
|
||||
from iqdbc.lvbs.car.hyundai.longitudinal.helpers import get_longitudinal_tune
|
||||
from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ, HyundaiSafetyFlagsIQ
|
||||
from openpilot.common.params import Params
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
Ecu = structs.CarParams.Ecu
|
||||
@@ -20,67 +20,125 @@ Ecu = structs.CarParams.Ecu
|
||||
# Cancel button can sometimes be ACC pause/resume button, main button can also enable on some cars
|
||||
ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.cancel, ButtonType.mainCruise)
|
||||
|
||||
SteerControlType = structs.CarParams.SteerControlType
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
CarState = CarState
|
||||
CarController = CarController
|
||||
RadarInterface = RadarInterface
|
||||
|
||||
DRIVABLE_GEARS = (structs.CarState.GearShifter.sport, structs.CarState.GearShifter.manumatic)
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
|
||||
|
||||
params = Params()
|
||||
camera_scc = params.get_int("HyundaiCameraSCC")
|
||||
if camera_scc > 0:
|
||||
ret.flags |= HyundaiFlags.CAMERA_SCC.value
|
||||
print("$$$CAMERA_SCC toggled...")
|
||||
|
||||
ret.brand = "hyundai"
|
||||
|
||||
# "LKA steering" if LKAS or LKAS_ALT messages are seen coming from the camera.
|
||||
# Generally means our LKAS message is forwarded to another ECU (commonly ADAS ECU)
|
||||
# that finally retransmits our steering command in LFA or LFA_ALT to the MDPS.
|
||||
# "LFA steering" if camera directly sends LFA to the MDPS
|
||||
cam_can = CanBus(None, fingerprint).CAM
|
||||
lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
|
||||
CAN = CanBus(None, fingerprint, lka_steering)
|
||||
if candidate == CAR.KIA_SORENTO:
|
||||
ret.extFlags |= HyundaiExtFlags.RADAR_GROUP4.value
|
||||
|
||||
cam_can = CanBus(None, fingerprint).CAM if camera_scc == 0 else 1
|
||||
hda2 = False #0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
|
||||
hda2 = hda2 or params.get_int("CanfdHDA2") > 0
|
||||
CAN = CanBus(None, fingerprint, hda2)
|
||||
|
||||
if ret.flags & HyundaiFlags.CANFD:
|
||||
# Shared configuration for CAN-FD cars
|
||||
ret.alphaLongitudinalAvailable = candidate not in CANFD_UNSUPPORTED_LONGITUDINAL_CAR
|
||||
if lka_steering and Ecu.adas not in [fw.ecu for fw in car_fw]:
|
||||
# this needs to be figured out for cars without an ADAS ECU
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
ret.alphaLongitudinalAvailable = True #candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR)
|
||||
#ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
|
||||
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN] # BLINDSPOTS_REAR_CORNERS 0x1ba(442)
|
||||
|
||||
ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
|
||||
|
||||
# Check if the car is hybrid. Only HEV/PHEV cars have 0xFA on E-CAN.
|
||||
if 0xFA in fingerprint[CAN.ECAN]:
|
||||
if 0x105 in fingerprint[CAN.ECAN]:
|
||||
ret.flags |= HyundaiFlags.HYBRID.value
|
||||
|
||||
if lka_steering:
|
||||
# detect LKA steering
|
||||
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING.value
|
||||
if 0x110 in fingerprint[CAN.CAM]:
|
||||
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value
|
||||
# Keep drivetrain/safety classification unchanged: this capability is display-only and requires both exact ECAN frames.
|
||||
has_ev_mode_status = fingerprint[CAN.ECAN].get(CANFD_HYBRID_STATUS_ADDR) == CANFD_HYBRID_STATUS_DLC and \
|
||||
fingerprint[CAN.ECAN].get(EV_MODE_STATUS_ADDR) == EV_MODE_STATUS_DLC
|
||||
if has_ev_mode_status:
|
||||
ret.extFlags |= HyundaiExtFlags.EV_MODE_STATUS_230.value
|
||||
|
||||
if 203 in fingerprint[CAN.CAM]: # LFA_ALT
|
||||
print("##### Anglecontrol detected (LFA_ALT)")
|
||||
ret.flags |= HyundaiFlags.ANGLE_CONTROL.value
|
||||
|
||||
print("ACAN=", fingerprint[CAN.ACAN])
|
||||
|
||||
if 0x210 in fingerprint[CAN.ACAN]:
|
||||
print("##### Radar Group 1 detected (0x210)")
|
||||
ret.extFlags |= HyundaiExtFlags.RADAR_GROUP1.value
|
||||
elif 0x400 in fingerprint[CAN.ACAN] and 0x41D in fingerprint[CAN.ACAN]:
|
||||
print("##### Radar Group 3 detected (0x400-0x41D)")
|
||||
ret.extFlags |= HyundaiExtFlags.RADAR_GROUP3.value
|
||||
if all(fingerprint[CAN.ACAN].get(addr) == 32 for addr in range(0x235, 0x249)):
|
||||
ret.extFlags |= HyundaiExtFlags.CORNER_RADAR_OBJECTS_235.value
|
||||
print("##### Corner radar objects 0x235 group detected")
|
||||
if all(fingerprint[CAN.ACAN].get(addr) == 32 for addr in range(0x180, 0x185)):
|
||||
ret.extFlags |= HyundaiExtFlags.CORNER_RADAR_OBJECTS_180.value
|
||||
print("##### Corner radar objects 0x180 group detected")
|
||||
if all(fingerprint[CAN.ACAN].get(addr) == 32 for addr in tuple(range(0x430, 0x438)) + tuple(range(0x440, 0x448))):
|
||||
ret.extFlags |= HyundaiExtFlags.CORNER_RADAR_OBJECTS_430.value
|
||||
print("##### Corner radar objects 0x430/0x440 group detected")
|
||||
|
||||
# detect HDA2 with ADAS Driving ECU
|
||||
if hda2:
|
||||
print("$$$CANFD HDA2")
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2.value
|
||||
if camera_scc > 0:
|
||||
if 0x110 in fingerprint[CAN.ACAN]:
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
||||
print("$$$CANFD ALT_STEERING1")
|
||||
else:
|
||||
if 0x110 in fingerprint[CAN.CAM]: # 0x110(272): LKAS_ALT
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
||||
print("$$$CANFD ALT_STEERING1")
|
||||
## carrot_todo: sorento:
|
||||
if 0x2a4 not in fingerprint[CAN.CAM]: # 0x2a4(676): CAM_0x2a4
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
||||
print("$$$CANFD ALT_STEERING2")
|
||||
|
||||
## carrot: canival 4th, no 0x1cf
|
||||
if 0x1cf not in fingerprint[CAN.ECAN]: # 0x1cf(463): CRUISE_BUTTONS
|
||||
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
|
||||
print("$$$CANFD ALT_BUTTONS")
|
||||
else:
|
||||
# no LKA steering
|
||||
# non-HDA2
|
||||
print("$$$CANFD non HDA2")
|
||||
if 0x1cf not in fingerprint[CAN.ECAN]:
|
||||
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
|
||||
if not ret.flags & HyundaiFlags.RADAR_SCC:
|
||||
ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
|
||||
|
||||
# Some LKA steering cars have alternative messages for gear checks
|
||||
print("$$$CANFD ALT_BUTTONS")
|
||||
#if not ret.flags & HyundaiFlags.RADAR_SCC:
|
||||
# ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
|
||||
# print("$$$CANFD CAMERA_SCC")
|
||||
# Some HDA2 cars have alternative messages for gear checks
|
||||
# ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead
|
||||
if 0x130 not in fingerprint[CAN.ECAN]:
|
||||
if 0x40 not in fingerprint[CAN.ECAN]:
|
||||
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
|
||||
else:
|
||||
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
|
||||
if 0x40 in fingerprint[CAN.ECAN]: # 0x40(64): GEAR_ALT
|
||||
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
|
||||
print("$$$CANFD ALT_GEARS")
|
||||
elif 69 in fingerprint[CAN.ECAN]: # Special case
|
||||
ret.extFlags |= HyundaiExtFlags.CANFD_GEARS_69.value
|
||||
print("$$$CANFD GEARS_69")
|
||||
elif 112 in fingerprint[CAN.ECAN]: # carrot: eGV70
|
||||
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
|
||||
print("$$$CANFD ALT_GEARS_2")
|
||||
elif 0x130 in fingerprint[CAN.ECAN]: # 0x130(304): GEAR_SHIFTER
|
||||
print("$$$CANFD GEAR_SHIFTER present")
|
||||
else:
|
||||
ret.extFlags |= HyundaiExtFlags.CANFD_GEARS_NONE.value
|
||||
print("$$$CANFD GEARS_NONE")
|
||||
|
||||
cfgs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiCanfd), ]
|
||||
if CAN.ECAN >= 4:
|
||||
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
|
||||
ret.safetyConfigs = cfgs
|
||||
|
||||
if ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
if ret.flags & HyundaiFlags.CANFD_HDA2:
|
||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_LKA_STEERING.value
|
||||
if ret.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT:
|
||||
if ret.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING:
|
||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT.value
|
||||
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_ALT_BUTTONS.value
|
||||
@@ -89,56 +147,93 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
else:
|
||||
# Shared configuration for non CAN-FD cars
|
||||
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR
|
||||
ret.alphaLongitudinalAvailable = True #candidate not in (UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR)
|
||||
ret.enableBsm = 0x58b in fingerprint[0]
|
||||
print(f"$$$ enableBsm = {ret.enableBsm}")
|
||||
|
||||
# Send LFA message on cars with HDA
|
||||
if 0x485 in fingerprint[2]:
|
||||
ret.flags |= HyundaiFlags.SEND_LFA.value
|
||||
print("$$$SEND_LFA")
|
||||
|
||||
# These cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
|
||||
if 0x38d in fingerprint[0] or 0x38d in fingerprint[2]:
|
||||
ret.flags |= HyundaiFlags.USE_FCA.value
|
||||
print("$$$USE_FCA")
|
||||
|
||||
if ret.flags & HyundaiFlags.LEGACY:
|
||||
# these cars require a special panda safety mode due to missing counters and checksums in the messages
|
||||
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiLegacy)]
|
||||
print("$$$Legacy Safety Model")
|
||||
else:
|
||||
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundai, 0)]
|
||||
|
||||
if ret.flags & HyundaiFlags.CAMERA_SCC:
|
||||
ret.safetyConfigs[0].safetyParam |= HyundaiSafetyFlags.CAMERA_SCC.value
|
||||
|
||||
# These cars have the LFA button on the steering wheel
|
||||
if 0x391 in fingerprint[0]:
|
||||
ret.flags |= HyundaiFlags.HAS_LDA_BUTTON.value
|
||||
print("$$$CAMERA_SCC")
|
||||
|
||||
# Common lateral control setup
|
||||
|
||||
ret.centerToFront = ret.wheelbase * 0.4
|
||||
ret.steerActuatorDelay = 0.1
|
||||
ret.steerLimitTimer = 0.4
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
if ret.flags & HyundaiFlags.ANGLE_CONTROL:
|
||||
ret.steerControlType = SteerControlType.angle
|
||||
else:
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
if ret.flags & HyundaiFlags.ALT_LIMITS:
|
||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.ALT_LIMITS.value
|
||||
|
||||
if ret.flags & HyundaiFlags.ALT_LIMITS_2:
|
||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.ALT_LIMITS_2.value
|
||||
|
||||
# see https://github.com/commaai/iqdbc/pull/1137/
|
||||
ret.dashcamOnly = True
|
||||
|
||||
# Common longitudinal control setup
|
||||
|
||||
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in DBC[ret.carFingerprint]
|
||||
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
|
||||
|
||||
# carrot, if camera_scc enabled, enable openpilotLongitudinalControl
|
||||
enable_radar_tracks = params.get_int("EnableRadarTracks")
|
||||
if ret.flags & HyundaiFlags.CAMERA_SCC.value or enable_radar_tracks > 0 or enable_radar_tracks == -2:
|
||||
ret.radarUnavailable = False
|
||||
ret.openpilotLongitudinalControl = True if camera_scc < 3 else False
|
||||
print(f"$$$OenpilotLongitudinalControl = True, CAMERA_SCC({ret.flags & HyundaiFlags.CAMERA_SCC.value}) or RadarTracks{enable_radar_tracks}")
|
||||
else:
|
||||
print(f"$$$OenpilotLongitudinalControl = {alpha_long}")
|
||||
|
||||
#ret.radarUnavailable = False # TODO: canfd... carrot, hyundai cars have radar
|
||||
|
||||
ret.radarTimeStep = 0.05 #if params.get_int("EnableRadarTracks") > 0 else 0.02
|
||||
|
||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||
ret.startingState = True
|
||||
ret.startingState = False # True # carrot
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.startAccel = 1.0
|
||||
ret.longitudinalActuatorDelay = 0.5
|
||||
|
||||
ret.longitudinalTuning.kpBP = [0.]
|
||||
ret.longitudinalTuning.kpV = [1.]
|
||||
ret.longitudinalTuning.kf = 1.0
|
||||
|
||||
# *** feature detection ***
|
||||
if ret.flags & HyundaiFlags.CANFD:
|
||||
print(f"$$$$$ CanFD ECAN = {CAN.ECAN}")
|
||||
if 0x1fa in fingerprint[CAN.ECAN]:
|
||||
ret.extFlags |= HyundaiExtFlags.NAVI_CLUSTER.value
|
||||
print("$$$$ NaviCluster = True")
|
||||
else:
|
||||
print("$$$$ NaviCluster = False")
|
||||
|
||||
else:
|
||||
if 1348 in fingerprint[0]:
|
||||
ret.extFlags |= HyundaiExtFlags.NAVI_CLUSTER.value
|
||||
print("$$$$ NaviCluster = True")
|
||||
if 1157 in fingerprint[0] or 1157 in fingerprint[2]:
|
||||
ret.extFlags |= HyundaiExtFlags.HAS_LFAHDA.value
|
||||
print("$$$$ HasLFAHDA")
|
||||
if 1007 in fingerprint[0]:
|
||||
print("#### cruiseButtonAlt")
|
||||
|
||||
print(f"$$$$ enableBsm = {ret.enableBsm}")
|
||||
|
||||
if ret.openpilotLongitudinalControl:
|
||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.LONG.value
|
||||
if ret.flags & HyundaiFlags.HYBRID:
|
||||
@@ -155,95 +250,64 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# Dashcam cars are missing a test route, or otherwise need validation
|
||||
# TODO: Optima Hybrid 2017 uses a different SCC12 checksum
|
||||
if candidate in (CAR.KIA_OPTIMA_H,):
|
||||
ret.dashcamOnly = True
|
||||
#ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, }
|
||||
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def _get_params_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams, candidate, fingerprint: dict[int, dict[int, int]],
|
||||
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
|
||||
# identical logic used in _get_params
|
||||
# "LKA steering" if LKAS or LKAS_ALT messages are seen coming from the camera.
|
||||
# Generally means our LKAS message is forwarded to another ECU (commonly ADAS ECU)
|
||||
# that finally retransmits our steering command in LFA or LFA_ALT to the MDPS.
|
||||
# "LFA steering" if camera directly sends LFA to the MDPS
|
||||
cam_can = CanBus(None, fingerprint).CAM
|
||||
lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
|
||||
CAN = CanBus(None, fingerprint, lka_steering)
|
||||
|
||||
if not stock_cp.flags & HyundaiFlags.CANFD:
|
||||
# TODO-IQ: add route with ESCC message for process replay
|
||||
if ESCC_MSG in fingerprint[0]:
|
||||
ret.flags |= HyundaiFlagsIQ.ENHANCED_SCC.value
|
||||
|
||||
if ret.flags & HyundaiFlagsIQ.ENHANCED_SCC:
|
||||
ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.ESCC
|
||||
stock_cp.radarUnavailable = False
|
||||
|
||||
if stock_cp.flags & HyundaiFlags.HAS_LDA_BUTTON:
|
||||
def _get_params_iq(stock_cp, ret, candidate, fingerprint, car_fw, alpha_long, is_release_iq, docs):
|
||||
del candidate, car_fw, alpha_long, is_release_iq, docs
|
||||
if not stock_cp.flags & HyundaiFlags.CANFD and 0x391 in fingerprint[0]:
|
||||
ret.flags |= HyundaiFlagsIQ.HAS_LFA_BUTTON
|
||||
ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON
|
||||
|
||||
if stock_cp.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC):
|
||||
stock_cp.radarUnavailable = False
|
||||
|
||||
if stock_cp.flags & HyundaiFlags.ALT_LIMITS_2:
|
||||
stock_cp.dashcamOnly = False
|
||||
|
||||
if ret.flags & HyundaiFlagsIQ.NON_SCC:
|
||||
stock_cp.alphaLongitudinalAvailable = False
|
||||
stock_cp.openpilotLongitudinalControl = False
|
||||
stock_cp.pcmCruise = True
|
||||
ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.NON_SCC
|
||||
|
||||
# untested non-SCC platforms, need user validations
|
||||
if stock_cp.carFingerprint in (CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC, CAR.KIA_FORTE_2021_NON_SCC,
|
||||
CAR.KIA_SELTOS_2023_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC):
|
||||
stock_cp.dashcamOnly = True
|
||||
|
||||
if stock_cp.flags & HyundaiFlags.CANFD:
|
||||
if 0x1fa in fingerprint[CAN.ECAN]:
|
||||
ret.flags |= HyundaiFlagsIQ.SPEED_LIMIT_AVAILABLE.value
|
||||
else:
|
||||
# Detect smartMDPS, which bypasses EPS low-speed lockout, allowing iqpilot to send steering commands down to 0
|
||||
if 0x2AA in fingerprint[0]:
|
||||
stock_cp.minSteerSpeed = 0.0
|
||||
stock_cp.flags &= ~HyundaiFlags.MIN_STEER_32_MPH.value
|
||||
|
||||
if 0x544 in fingerprint[0]:
|
||||
ret.flags |= HyundaiFlagsIQ.SPEED_LIMIT_AVAILABLE.value
|
||||
|
||||
if 0x53E in fingerprint[2]:
|
||||
ret.flags |= HyundaiFlagsIQ.HAS_LKAS12.value
|
||||
|
||||
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def _get_longitudinal_tuning_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams) -> structs.IQCarParams:
|
||||
if ret.flags & (HyundaiFlagsIQ.LONG_TUNING_DYNAMIC | HyundaiFlagsIQ.LONG_TUNING_PREDICTIVE):
|
||||
get_longitudinal_tune(stock_cp)
|
||||
def init(CP, can_recv, can_send):
|
||||
|
||||
return ret
|
||||
Params().put_int('LongitudinalPersonalityMax', 4)
|
||||
|
||||
@staticmethod
|
||||
def init(CP, CP_IQ, can_recv, can_send, communication_control=None):
|
||||
# 0x80 silences response
|
||||
if communication_control is None:
|
||||
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL])
|
||||
|
||||
if CP.openpilotLongitudinalControl and not ((CP.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)) or
|
||||
(CP_IQ.flags & HyundaiFlagsIQ.ENHANCED_SCC)):
|
||||
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & HyundaiFlags.CANFD else 0
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
|
||||
if CP.openpilotLongitudinalControl and not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC):
|
||||
addr, bus = 0x7d0, 0
|
||||
if CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||
addr, bus = 0x730, CanBus(CP).ECAN
|
||||
disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control)
|
||||
disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=b'\x28\x83\x01')
|
||||
|
||||
params = Params()
|
||||
if params.get_int("EnableRadarTracks") > 0 and not CP.flags & HyundaiFlags.CANFD:
|
||||
result = enable_radar_tracks(CP, can_recv, can_send)
|
||||
params.put_bool("EnableRadarTracksResult", result)
|
||||
|
||||
# for blinkers
|
||||
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||
disable_ecu(can_recv, can_send, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=communication_control)
|
||||
disable_ecu(can_recv, can_send, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01')
|
||||
|
||||
@staticmethod
|
||||
def deinit(CP, can_recv, can_send):
|
||||
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL])
|
||||
CarInterface.init(CP, can_recv, can_send, communication_control)
|
||||
def enable_radar_tracks(CP, logcan, sendcan):
|
||||
from iqdbc.car.isotp_parallel_query import IsoTpParallelQuery
|
||||
print("################ Try To Enable Radar Tracks ####################")
|
||||
|
||||
ret = False
|
||||
sccBus = 2 if CP.flags & HyundaiFlags.CAMERA_SCC.value else 0
|
||||
rdr_fw = None
|
||||
rdr_fw_address = 0x7d0 #
|
||||
try:
|
||||
try:
|
||||
query = IsoTpParallelQuery(sendcan, logcan, sccBus, [rdr_fw_address], [b'\x10\x07'], [b'\x50\x07'])
|
||||
for addr, dat in query.get_data(0.1).items(): # pylint: disable=unused-variable
|
||||
print("ecu write data by id ...")
|
||||
new_config = b"\x00\x00\x00\x01\x00\x01"
|
||||
#new_config = b"\x00\x00\x00\x00\x00\x01"
|
||||
dataId = b'\x01\x42'
|
||||
WRITE_DAT_REQUEST = b'\x2e'
|
||||
WRITE_DAT_RESPONSE = b'\x68'
|
||||
query = IsoTpParallelQuery(sendcan, logcan, sccBus, [rdr_fw_address], [WRITE_DAT_REQUEST+dataId+new_config], [WRITE_DAT_RESPONSE])
|
||||
result = query.get_data(0)
|
||||
print("result=", result)
|
||||
ret = True
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Failed : {e}")
|
||||
except Exception as e:
|
||||
print("############## Failed to enable tracks" + str(e))
|
||||
print("################ END Try to enable radar tracks")
|
||||
return ret
|
||||
|
||||
@@ -1,86 +1,885 @@
|
||||
import math
|
||||
import os
|
||||
from collections import deque
|
||||
|
||||
from iqdbc import DBC_PATH
|
||||
from iqdbc.can import CANParser
|
||||
from iqdbc.car import Bus, structs
|
||||
from iqdbc.car.interfaces import RadarInterfaceBase
|
||||
from iqdbc.car.hyundai.values import DBC
|
||||
|
||||
from iqdbc.lvbs.car.hyundai.radar_interface_ext import RadarInterfaceExt
|
||||
from iqdbc.car.hyundai.values import DBC, HyundaiFlags, HyundaiExtFlags
|
||||
from openpilot.common.params import Params
|
||||
from iqdbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from openpilot.common.filter_simple import MyMovingAverage
|
||||
|
||||
SCC_TID = 0
|
||||
RADAR_START_ADDR = 0x500
|
||||
RADAR_MSG_COUNT = 32
|
||||
RADAR_MSG_COUNT4 = 8
|
||||
RADAR_GROUP4_MAX_LONG_DIST = 325.0
|
||||
RADAR_GROUP4_MAX_YREL = 6.0
|
||||
RADAR_START_ADDR_CANFD1 = 0x210
|
||||
RADAR_MSG_COUNT1 = 16
|
||||
RADAR_START_ADDR_CANFD2 = 0x3A5 # Group 2, Group 1: 0x210 2개씩?어???단 보류.
|
||||
RADAR_MSG_COUNT2 = 32
|
||||
RADAR_START_ADDR_CANFD3 = 0x400
|
||||
RADAR_MSG_COUNT3 = 30
|
||||
CORNER_OBJECT_235_START_ADDR = 0x235
|
||||
CORNER_OBJECT_235_MSG_COUNT = 20
|
||||
CORNER_OBJECT_235_TRACK_ID_OFFSET = 200
|
||||
CORNER_OBJECT_235_DBC = 'hyundai_canfd_corner_radar_235_generated'
|
||||
CORNER_OBJECT_180_START_ADDR = 0x180
|
||||
CORNER_OBJECT_180_MSG_COUNT = 5
|
||||
CORNER_OBJECT_180_SLOTS_PER_MSG = 2
|
||||
CORNER_OBJECT_180_TRACK_ID_OFFSET = 240
|
||||
CORNER_OBJECT_180_DBC = 'hyundai_canfd_corner_radar_180_generated'
|
||||
CORNER_OBJECT_430_LEFT_START_ADDR = 0x430
|
||||
CORNER_OBJECT_430_RIGHT_START_ADDR = 0x440
|
||||
CORNER_OBJECT_430_MSG_COUNT_PER_SIDE = 8
|
||||
CORNER_OBJECT_430_SLOTS_PER_MSG = 7
|
||||
CORNER_OBJECT_430_TRACK_ID_OFFSET = 300
|
||||
CORNER_OBJECT_430_DBC = 'hyundai_canfd_corner_radar_430_generated'
|
||||
CORNER_OBJECT_430_EMPTY_RAW_VALUES = (0x010d1f40, 0x00010d1f)
|
||||
CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MIN = 2520 # 126.0 m
|
||||
CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MAX = 2600 # 130.0 m
|
||||
CORNER_OBJECT_430_MAX_DREL = 120.0
|
||||
CORNER_OBJECT_430_MAX_TRACKS_PER_SIDE = 4
|
||||
CORNER_OBJECT_430_DT = 0.05
|
||||
CORNER_OBJECT_430_MAX_DREL_DELTA = 1.5
|
||||
CORNER_OBJECT_430_CANDIDATE_META_BYTE_3 = (2,)
|
||||
CORNER_OBJECT_430_CANDIDATE_EXCLUDED_SLOTS = (1,)
|
||||
CORNER_OBJECT_430_CANDIDATE_RAW_DELTA = 200
|
||||
CORNER_OBJECT_430_STRONG_META_BYTE_2 = (10,)
|
||||
CORNER_OBJECT_430_WEAK_META_BYTE_2 = (5, 6, 7, 8, 9)
|
||||
CORNER_OBJECT_430_STRONG_MIN_SUPPORT = 2
|
||||
CORNER_OBJECT_430_WEAK_MIN_SUPPORT = 3
|
||||
CORNER_OBJECT_430_CLUSTER_RAW_GAP = 200
|
||||
CORNER_OBJECT_430_TRACK_MATCH_MAX_DREL_DELTA = 3.0
|
||||
CORNER_OBJECT_430_MAX_ABS_VREL = 20.0
|
||||
CORNER_OBJECT_430_MAX_ABS_YVREL = 3.0
|
||||
CORNER_OBJECT_430_VREL_ALPHA = 0.35
|
||||
CORNER_OBJECT_430_YVREL_ALPHA = 0.35
|
||||
CORNER_OBJECT_430_LATERAL_CELL_MSG_WEIGHT = 0.35
|
||||
CORNER_OBJECT_430_LATERAL_CELL_SLOT_WEIGHT = 0.65
|
||||
CORNER_OBJECT_430_YREL_OFFSET = 5.8
|
||||
CORNER_OBJECT_430_YREL_SCALE = 1.1
|
||||
CORNER_OBJECT_430_RIGHT_CELL_MIRROR = 7.0
|
||||
CORNER_OBJECT_430_MIN_ABS_YREL = 0.8
|
||||
CORNER_OBJECT_430_MAX_ABS_YREL = 4.2
|
||||
CORNER_OBJECT_430_HISTORY_SIZE = 8
|
||||
CORNER_OBJECT_430_MIN_HISTORY = 5
|
||||
CORNER_OBJECT_430_MIN_INWARD_YREL_DELTA = 0.35
|
||||
CORNER_OBJECT_430_MIN_RECENT_INWARD_YREL_DELTA = 0.05
|
||||
CORNER_OBJECT_430_MIN_INWARD_RATIO = 0.65
|
||||
CORNER_OBJECT_430_INWARD_CENTER_ABS_YREL = 1.55
|
||||
CORNER_OBJECT_430_INWARD_KEEP_YVREL_ABS_YREL = 2.2
|
||||
CORNER_OBJECT_430_EARLY_INWARD_NONCENTER_FRAMES = 2
|
||||
CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL = 2.0
|
||||
CORNER_OBJECT_STABLE_TRACK_ID_START = 1000
|
||||
CORNER_SIDE_OBJECT_MAX_DREL = 0.2
|
||||
CORNER_SIDE_OBJECT_MIN_ABS_YREL = 1.4
|
||||
CORNER_SIDE_OBJECT_MAX_ABS_YREL = 4.5
|
||||
|
||||
# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
|
||||
|
||||
|
||||
def get_radar_can_parser(CP):
|
||||
if Bus.radar not in DBC[CP.carFingerprint]:
|
||||
class CornerObjectTrackIdManager:
|
||||
def __init__(self):
|
||||
self.next_track_id = CORNER_OBJECT_STABLE_TRACK_ID_START
|
||||
self.objects: dict[tuple[str, int], tuple[int, int]] = {}
|
||||
|
||||
def get_track_id(self, source: str, object_id: int, age: int) -> int:
|
||||
key = (source, object_id)
|
||||
previous = self.objects.get(key)
|
||||
if previous is None or age < previous[1]:
|
||||
track_id = self.next_track_id
|
||||
self.next_track_id += 1
|
||||
else:
|
||||
track_id = previous[0]
|
||||
self.objects[key] = (track_id, age)
|
||||
return track_id
|
||||
|
||||
def clear_source(self, source: str):
|
||||
self.objects = {key: value for key, value in self.objects.items() if key[0] != source}
|
||||
|
||||
|
||||
def corner_object_position_valid(d_rel: float, y_rel: float) -> bool:
|
||||
normal_object = 0.2 < d_rel < 180.0
|
||||
clipped_side_object = (
|
||||
0.0 <= d_rel <= CORNER_SIDE_OBJECT_MAX_DREL and
|
||||
CORNER_SIDE_OBJECT_MIN_ABS_YREL <= abs(y_rel) <= CORNER_SIDE_OBJECT_MAX_ABS_YREL
|
||||
)
|
||||
return (normal_object or clipped_side_object) and abs(y_rel) < 40.0
|
||||
|
||||
|
||||
def get_radar_can_parser(CP, radar_tracks, msg_start_addr, msg_count, radar_group4=False):
|
||||
if not radar_tracks:
|
||||
return None
|
||||
#if Bus.radar not in DBC[CP.carFingerprint]:
|
||||
# return None
|
||||
print("RadarInterface: RadarTracks...")
|
||||
|
||||
if CP.flags & HyundaiFlags.CANFD:
|
||||
CAN = CanBus(CP)
|
||||
messages = [(f"RADAR_TRACK_{addr:x}", 20) for addr in range(msg_start_addr, msg_start_addr + msg_count)]
|
||||
return CANParser('hyundai_canfd_radar_generated', messages, CAN.ACAN)
|
||||
else:
|
||||
messages = [(f"RADAR_TRACK_{addr:x}", 20) for addr in range(msg_start_addr, msg_start_addr + msg_count)]
|
||||
#return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1)
|
||||
dbc_name = 'hyundai_kia_denso_front_radar_generated' if radar_group4 else 'hyundai_kia_mando_front_radar_generated'
|
||||
return CANParser(dbc_name, messages, 1)
|
||||
|
||||
def get_corner_object_can_parser(CP, enabled):
|
||||
if not enabled or not (CP.flags & HyundaiFlags.CANFD):
|
||||
return None
|
||||
|
||||
messages = [(f"RADAR_TRACK_{addr:x}", 50) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)]
|
||||
return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1)
|
||||
dbc_path = os.path.join(DBC_PATH, f"{CORNER_OBJECT_235_DBC}.dbc")
|
||||
if not os.path.exists(dbc_path):
|
||||
print(f"RadarInterface: missing {CORNER_OBJECT_235_DBC}.dbc, 0x235 corner radar disabled")
|
||||
return None
|
||||
|
||||
CAN = CanBus(CP)
|
||||
messages = [(f"CORNER_RADAR_235_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_235_START_ADDR, CORNER_OBJECT_235_START_ADDR + CORNER_OBJECT_235_MSG_COUNT)]
|
||||
return CANParser(CORNER_OBJECT_235_DBC, messages, CAN.ACAN)
|
||||
|
||||
class RadarInterface(RadarInterfaceBase, RadarInterfaceExt):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
RadarInterfaceBase.__init__(self, CP, CP_IQ)
|
||||
RadarInterfaceExt.__init__(self, CP, CP_IQ)
|
||||
self.updated_messages = set()
|
||||
self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
|
||||
def get_corner_object_180_can_parser(CP, enabled):
|
||||
if not enabled or not (CP.flags & HyundaiFlags.CANFD):
|
||||
return None
|
||||
|
||||
dbc_path = os.path.join(DBC_PATH, f"{CORNER_OBJECT_180_DBC}.dbc")
|
||||
if not os.path.exists(dbc_path):
|
||||
print(f"RadarInterface: missing {CORNER_OBJECT_180_DBC}.dbc, 0x180 corner radar disabled")
|
||||
return None
|
||||
|
||||
CAN = CanBus(CP)
|
||||
messages = [(f"CORNER_RADAR_180_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_180_START_ADDR, CORNER_OBJECT_180_START_ADDR + CORNER_OBJECT_180_MSG_COUNT)]
|
||||
return CANParser(CORNER_OBJECT_180_DBC, messages, CAN.ACAN)
|
||||
|
||||
def get_corner_object_430_can_parser(CP, enabled):
|
||||
if not enabled or not (CP.flags & HyundaiFlags.CANFD):
|
||||
return None
|
||||
|
||||
dbc_path = os.path.join(DBC_PATH, f"{CORNER_OBJECT_430_DBC}.dbc")
|
||||
if not os.path.exists(dbc_path):
|
||||
print(f"RadarInterface: missing {CORNER_OBJECT_430_DBC}.dbc, 0x430/0x440 corner radar disabled")
|
||||
return None
|
||||
|
||||
CAN = CanBus(CP)
|
||||
messages = [(f"CORNER_RADAR_430_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_430_LEFT_START_ADDR, CORNER_OBJECT_430_LEFT_START_ADDR + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE)]
|
||||
messages += [(f"CORNER_RADAR_430_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_430_RIGHT_START_ADDR, CORNER_OBJECT_430_RIGHT_START_ADDR + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE)]
|
||||
return CANParser(CORNER_OBJECT_430_DBC, messages, CAN.ACAN)
|
||||
|
||||
def get_radar_can_parser_scc(CP):
|
||||
CAN = CanBus(CP)
|
||||
if CP.flags & HyundaiFlags.CANFD:
|
||||
messages = [("SCC_CONTROL", 50)]
|
||||
bus = CAN.ECAN
|
||||
else:
|
||||
messages = [("SCC11", 50)]
|
||||
bus = CAN.ECAN
|
||||
|
||||
print("$$$$$$$$ ECAN = ", CAN.ECAN)
|
||||
bus = CAN.CAM if CP.flags & HyundaiFlags.CAMERA_SCC else bus
|
||||
return CANParser(DBC[CP.carFingerprint][Bus.pt], messages, bus)
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
def __init__(self, CP, CP_IQ=None):
|
||||
super().__init__(CP, CP_IQ or structs.IQCarParams())
|
||||
self.v_ego = 0.0
|
||||
|
||||
self.canfd = True if CP.flags & HyundaiFlags.CANFD else False
|
||||
self.radar_group1 = False
|
||||
self.radar_group3 = False
|
||||
self.radar_group4 = not self.canfd and bool(CP.extFlags & HyundaiExtFlags.RADAR_GROUP4.value)
|
||||
if self.canfd:
|
||||
if CP.extFlags & HyundaiExtFlags.RADAR_GROUP1.value:
|
||||
self.radar_start_addr = RADAR_START_ADDR_CANFD1
|
||||
self.radar_msg_count = RADAR_MSG_COUNT1
|
||||
self.radar_group1 = True
|
||||
elif CP.extFlags & HyundaiExtFlags.RADAR_GROUP3.value:
|
||||
self.radar_start_addr = RADAR_START_ADDR_CANFD3
|
||||
self.radar_msg_count = RADAR_MSG_COUNT3
|
||||
self.radar_group3 = True
|
||||
else:
|
||||
self.radar_start_addr = RADAR_START_ADDR_CANFD2
|
||||
self.radar_msg_count = RADAR_MSG_COUNT2
|
||||
else:
|
||||
self.radar_start_addr = RADAR_START_ADDR
|
||||
self.radar_msg_count = RADAR_MSG_COUNT4 if self.radar_group4 else RADAR_MSG_COUNT
|
||||
|
||||
self.params = Params()
|
||||
self.radar_tracks = self.params.get_int("EnableRadarTracks") >= 1
|
||||
self.corner_object_tracks = bool(CP.extFlags & HyundaiExtFlags.CORNER_RADAR_OBJECTS_235.value) and self.params.get_int("EnableCornerRadar") > 0
|
||||
self.corner_object_180_tracks = bool(CP.extFlags & HyundaiExtFlags.CORNER_RADAR_OBJECTS_180.value) and self.params.get_int("EnableCornerRadar") > 0
|
||||
self.corner_object_430_tracks = bool(CP.extFlags & HyundaiExtFlags.CORNER_RADAR_OBJECTS_430.value) and self.params.get_int("EnableCornerRadar") > 0
|
||||
self.updated_tracks = set()
|
||||
self.updated_scc = set()
|
||||
self.updated_corner_objects = set()
|
||||
self.updated_corner_objects_180 = set()
|
||||
self.updated_corner_objects_430 = set()
|
||||
self.corner_object_missed_updates = 0
|
||||
self.corner_object_180_missed_updates = 0
|
||||
self.corner_object_430_missed_updates = 0
|
||||
self.corner_object_track_ids = CornerObjectTrackIdManager()
|
||||
self.rcp_tracks = get_radar_can_parser(CP, self.radar_tracks, self.radar_start_addr, self.radar_msg_count, self.radar_group4)
|
||||
self.rcp_corner_objects = get_corner_object_can_parser(CP, self.corner_object_tracks)
|
||||
self.rcp_corner_objects_180 = get_corner_object_180_can_parser(CP, self.corner_object_180_tracks)
|
||||
self.rcp_corner_objects_430 = get_corner_object_430_can_parser(CP, self.corner_object_430_tracks)
|
||||
# Enabling raw radar tracks on legacy CAN disables the stock SCC11 stream on
|
||||
# some Hyundai/Kia platforms. Camera-SCC cars may still use SCC11.
|
||||
use_scc_parser = not (self.radar_tracks and not self.canfd and not (CP.flags & HyundaiFlags.CAMERA_SCC))
|
||||
self.rcp_scc = get_radar_can_parser_scc(CP) if use_scc_parser else None
|
||||
self.trigger_msg_scc = 416 if self.canfd else 0x420
|
||||
|
||||
self.trigger_msg_tracks = self.radar_start_addr + self.radar_msg_count - 1
|
||||
self.trigger_msg_corner_objects = CORNER_OBJECT_235_START_ADDR + CORNER_OBJECT_235_MSG_COUNT - 1
|
||||
self.trigger_msg_corner_objects_180 = CORNER_OBJECT_180_START_ADDR + CORNER_OBJECT_180_MSG_COUNT - 1
|
||||
self.trigger_msg_corner_objects_430 = CORNER_OBJECT_430_RIGHT_START_ADDR + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE - 1
|
||||
self.track_id = 0
|
||||
|
||||
self.radar_off_can = CP.radarUnavailable
|
||||
self.rcp = get_radar_can_parser(CP)
|
||||
self.corner_objects_available = self.rcp_corner_objects is not None or self.rcp_corner_objects_180 is not None or self.rcp_corner_objects_430 is not None
|
||||
self.radar_off_can = CP.radarUnavailable and not self.corner_objects_available
|
||||
print(
|
||||
"RadarInterface: "
|
||||
f"radarUnavailable={CP.radarUnavailable} radarTracks={self.radar_tracks} "
|
||||
f"group4={self.radar_group4} "
|
||||
f"corner235={self.rcp_corner_objects is not None} corner180={self.rcp_corner_objects_180 is not None} "
|
||||
f"corner430={self.rcp_corner_objects_430 is not None} "
|
||||
f"radarOffCan={self.radar_off_can}"
|
||||
)
|
||||
|
||||
self.vRel_last = 0
|
||||
self.dRel_last = 0
|
||||
self.corner_object_430_prev_d_rel = {}
|
||||
self.corner_object_430_prev_v_rel = {}
|
||||
self.corner_object_430_prev_y_rel = {}
|
||||
self.corner_object_430_prev_yv_rel = {}
|
||||
self.corner_object_430_prev_code = {}
|
||||
self.corner_object_430_history = {}
|
||||
self.corner_object_430_noncenter_inward_frames = {}
|
||||
|
||||
# Initialize pts
|
||||
if self.rcp_tracks is not None:
|
||||
total_tracks = self.radar_msg_count * (2 if self.radar_group1 else 1)
|
||||
for track_id in range(total_tracks):
|
||||
t_id = track_id + 32
|
||||
self.pts[t_id] = structs.RadarData.RadarPoint()
|
||||
self.pts[t_id].measured = False
|
||||
self.pts[t_id].trackId = t_id
|
||||
|
||||
if self.rcp_scc is not None:
|
||||
self.pts[SCC_TID] = structs.RadarData.RadarPoint()
|
||||
self.pts[SCC_TID].trackId = SCC_TID
|
||||
self.pts[SCC_TID].radarSource = "scc"
|
||||
if self.rcp_corner_objects is not None:
|
||||
for slot in range(CORNER_OBJECT_235_MSG_COUNT):
|
||||
t_id = CORNER_OBJECT_235_TRACK_ID_OFFSET + slot
|
||||
self.pts[t_id] = structs.RadarData.RadarPoint()
|
||||
self.pts[t_id].measured = False
|
||||
self.pts[t_id].trackId = t_id
|
||||
self.pts[t_id].radarSource = "corner235"
|
||||
if self.rcp_corner_objects_180 is not None:
|
||||
for slot in range(CORNER_OBJECT_180_MSG_COUNT * CORNER_OBJECT_180_SLOTS_PER_MSG):
|
||||
t_id = CORNER_OBJECT_180_TRACK_ID_OFFSET + slot
|
||||
self.pts[t_id] = structs.RadarData.RadarPoint()
|
||||
self.pts[t_id].measured = False
|
||||
self.pts[t_id].trackId = t_id
|
||||
self.pts[t_id].radarSource = "corner180"
|
||||
if self.rcp_corner_objects_430 is not None:
|
||||
for slot in range(CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * 2 * CORNER_OBJECT_430_SLOTS_PER_MSG):
|
||||
t_id = CORNER_OBJECT_430_TRACK_ID_OFFSET + slot
|
||||
self.pts[t_id] = structs.RadarData.RadarPoint()
|
||||
self.pts[t_id].measured = False
|
||||
self.pts[t_id].trackId = t_id
|
||||
|
||||
self.frame = 0
|
||||
|
||||
if self.rcp is None:
|
||||
self.initialize_radar_ext(self.trigger_msg)
|
||||
|
||||
def update(self, can_strings):
|
||||
if self.radar_off_can or (self.rcp is None):
|
||||
self.frame += 1
|
||||
if self.radar_off_can or (self.rcp_tracks is None and self.rcp_scc is None and self.rcp_corner_objects is None and self.rcp_corner_objects_180 is None and self.rcp_corner_objects_430 is None):
|
||||
return super().update(None)
|
||||
|
||||
vls = self.rcp.update(can_strings)
|
||||
self.updated_messages.update(vls)
|
||||
if self.rcp_scc is not None:
|
||||
vls_s = self.rcp_scc.update(can_strings)
|
||||
self.updated_scc.update(vls_s)
|
||||
|
||||
if self.trigger_msg not in self.updated_messages:
|
||||
track_ready = False
|
||||
if self.radar_tracks and self.rcp_tracks is not None:
|
||||
vls_t = self.rcp_tracks.update(can_strings)
|
||||
self.updated_tracks.update(vls_t)
|
||||
track_ready = self.trigger_msg_tracks in self.updated_tracks
|
||||
|
||||
corner_ready = False
|
||||
if self.rcp_corner_objects is not None:
|
||||
vls_c = self.rcp_corner_objects.update(can_strings)
|
||||
self.updated_corner_objects.update(vls_c)
|
||||
corner_ready = self.trigger_msg_corner_objects in self.updated_corner_objects
|
||||
|
||||
corner_180_ready = False
|
||||
if self.rcp_corner_objects_180 is not None:
|
||||
vls_180 = self.rcp_corner_objects_180.update(can_strings)
|
||||
self.updated_corner_objects_180.update(vls_180)
|
||||
corner_180_ready = self.trigger_msg_corner_objects_180 in self.updated_corner_objects_180
|
||||
|
||||
corner_430_ready = False
|
||||
if self.rcp_corner_objects_430 is not None:
|
||||
vls_430 = self.rcp_corner_objects_430.update(can_strings)
|
||||
self.updated_corner_objects_430.update(vls_430)
|
||||
corner_430_ready = self.trigger_msg_corner_objects_430 in self.updated_corner_objects_430
|
||||
|
||||
scc_ready = not self.radar_tracks and self.frame % 5 == 0 and self.rcp_scc is not None
|
||||
|
||||
if track_ready:
|
||||
self._update(self.updated_tracks)
|
||||
self.updated_tracks.clear()
|
||||
|
||||
if corner_ready:
|
||||
self._update_corner_objects(self.updated_corner_objects)
|
||||
self.corner_object_missed_updates = 0
|
||||
self.updated_corner_objects.clear()
|
||||
|
||||
if corner_180_ready:
|
||||
self._update_corner_objects_180(self.updated_corner_objects_180)
|
||||
self.corner_object_180_missed_updates = 0
|
||||
self.updated_corner_objects_180.clear()
|
||||
|
||||
if corner_430_ready:
|
||||
self._update_corner_objects_430(self.updated_corner_objects_430)
|
||||
self.corner_object_430_missed_updates = 0
|
||||
self.updated_corner_objects_430.clear()
|
||||
|
||||
# Corner radar runs at its own cadence. Do not let corner-only frames publish
|
||||
# RadarData, since liveTracks uses a fixed radarTimeStep for aLead/jLead.
|
||||
publish_ready = track_ready or scc_ready
|
||||
if not publish_ready:
|
||||
return None
|
||||
|
||||
rr = self._update(self.updated_messages)
|
||||
self.updated_messages.clear()
|
||||
if self.rcp_scc is not None:
|
||||
self._update_scc(self.updated_scc)
|
||||
if self.rcp_corner_objects is not None:
|
||||
if self.updated_corner_objects:
|
||||
self._update_corner_objects(self.updated_corner_objects)
|
||||
self.corner_object_missed_updates = 0
|
||||
else:
|
||||
self.corner_object_missed_updates += 1
|
||||
if self.corner_object_missed_updates > 10:
|
||||
self._clear_corner_objects()
|
||||
if self.rcp_corner_objects_180 is not None:
|
||||
if self.updated_corner_objects_180:
|
||||
self._update_corner_objects_180(self.updated_corner_objects_180)
|
||||
self.corner_object_180_missed_updates = 0
|
||||
else:
|
||||
self.corner_object_180_missed_updates += 1
|
||||
if self.corner_object_180_missed_updates > 10:
|
||||
self._clear_corner_objects_180()
|
||||
if self.rcp_corner_objects_430 is not None:
|
||||
if self.updated_corner_objects_430:
|
||||
self._update_corner_objects_430(self.updated_corner_objects_430)
|
||||
self.corner_object_430_missed_updates = 0
|
||||
else:
|
||||
self.corner_object_430_missed_updates += 1
|
||||
if self.corner_object_430_missed_updates > 10:
|
||||
self._clear_corner_objects_430()
|
||||
self.updated_scc.clear()
|
||||
self.updated_corner_objects.clear()
|
||||
self.updated_corner_objects_180.clear()
|
||||
self.updated_corner_objects_430.clear()
|
||||
|
||||
return rr
|
||||
ret = structs.RadarData()
|
||||
if ((self.rcp_tracks is not None and self.radar_tracks and not self.rcp_tracks.can_valid) or
|
||||
(self.rcp_scc is not None and not self.corner_objects_available and not self.rcp_scc.can_valid) or
|
||||
(self.rcp_corner_objects is not None and not self.rcp_corner_objects.can_valid) or
|
||||
(self.rcp_corner_objects_180 is not None and not self.rcp_corner_objects_180.can_valid) or
|
||||
(self.rcp_corner_objects_430 is not None and not self.rcp_corner_objects_430.can_valid)):
|
||||
ret.errors.canError = True
|
||||
ret.points = [point for point in self.pts.values() if point.measured]
|
||||
return ret
|
||||
|
||||
def _update(self, updated_messages):
|
||||
ret = structs.RadarData()
|
||||
if self.rcp is None:
|
||||
return ret
|
||||
|
||||
if not self.rcp.can_valid:
|
||||
ret.errors.canError = True
|
||||
t_id = 32
|
||||
for addr in range(self.radar_start_addr, self.radar_start_addr + self.radar_msg_count):
|
||||
|
||||
if self.use_radar_interface_ext:
|
||||
return self.update_ext(ret)
|
||||
|
||||
for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT):
|
||||
msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
|
||||
|
||||
if addr not in self.pts:
|
||||
self.pts[addr] = structs.RadarData.RadarPoint()
|
||||
self.pts[addr].trackId = self.track_id
|
||||
self.track_id += 1
|
||||
|
||||
valid = msg['STATE'] in (3, 4)
|
||||
if valid:
|
||||
azimuth = math.radians(msg['AZIMUTH'])
|
||||
self.pts[addr].measured = True
|
||||
self.pts[addr].dRel = math.cos(azimuth) * msg['LONG_DIST']
|
||||
self.pts[addr].yRel = 0.5 * -math.sin(azimuth) * msg['LONG_DIST']
|
||||
self.pts[addr].vRel = msg['REL_SPEED']
|
||||
self.pts[addr].aRel = msg['REL_ACCEL']
|
||||
self.pts[addr].yvRel = float('nan')
|
||||
msg = self.rcp_tracks.vl[f"RADAR_TRACK_{addr:x}"]
|
||||
|
||||
if self.radar_group1:
|
||||
valid = msg['VALID_CNT1'] > 10
|
||||
elif self.radar_group3:
|
||||
# Group 3 marks an empty object slot with LONG_DIST raw 0x7ff (204.7 m).
|
||||
valid = msg['LONG_DIST'] < 204.7
|
||||
elif self.canfd:
|
||||
valid = msg['VALID_CNT'] > 10
|
||||
elif self.radar_group4:
|
||||
# EN: DNMWR006 exposes eight stable tracked-object slots at 0x500-0x507.
|
||||
# Messages from 0x508 onward are distance-sorted raw detections without
|
||||
# stable IDs, so they are excluded. OBJECT_STATE 3 is a confirmed track;
|
||||
# empty slots use LONG_DIST raw 0xfff8 (409.55 m). Driving logs reached
|
||||
# 317.80 m, so 325 m preserves every observed confirmed track while
|
||||
# retaining margin from the empty-slot sentinel. Keep the +/-6 m
|
||||
# ego/adjacent-lane envelope to suppress farther roadside reflections.
|
||||
# KO: DNMWR006의 안정적인 추적 객체 슬롯은 0x500~0x507의 8개임.
|
||||
# 0x508 이후 메시지는 고정 ID가 없는 거리순 raw detection이므로 제외함.
|
||||
# OBJECT_STATE 3은 확정 추적 객체이며, 빈 슬롯은 LONG_DIST raw
|
||||
# 0xfff8(409.55m)을 사용함. 주행 로그의 최대값은 317.80m였으므로
|
||||
# 325m 상한으로 관측된 확정 트랙을 모두 보존하면서 빈 슬롯 값과 충분한
|
||||
# 여유를 확보함. 원거리 도로변 반사를 줄이기 위해 좌우 6m 범위를 유지함.
|
||||
valid = (msg['OBJECT_STATE'] == 3 and 0.2 < msg['LONG_DIST'] < RADAR_GROUP4_MAX_LONG_DIST and
|
||||
abs(msg['LAT_DIST']) <= RADAR_GROUP4_MAX_YREL)
|
||||
else:
|
||||
del self.pts[addr]
|
||||
valid = msg['STATE'] in (3, 4)
|
||||
|
||||
ret.points = list(self.pts.values())
|
||||
return ret
|
||||
self.pts[t_id].measured = bool(valid)
|
||||
if not valid:
|
||||
self.pts[t_id].dRel = 0
|
||||
self.pts[t_id].yRel = 0
|
||||
self.pts[t_id].vRel = 0
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0
|
||||
elif self.radar_group1:
|
||||
self.pts[t_id].dRel = msg['LONG_DIST1']
|
||||
self.pts[t_id].yRel = msg['LAT_DIST1']
|
||||
self.pts[t_id].vRel = msg['REL_SPEED1']
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = msg['REL_ACCEL1']
|
||||
self.pts[t_id].yvRel = msg['LAT_SPEED1']
|
||||
elif self.canfd:
|
||||
if self.radar_group3:
|
||||
# Group 3 reports the object's center. Convert it to the rear surface to match SCC/vision dRel.
|
||||
self.pts[t_id].dRel = max(0.0, msg['LONG_DIST'] - msg['OBJECT_LENGTH'] * 0.5 - 0.1)
|
||||
else:
|
||||
self.pts[t_id].dRel = msg['LONG_DIST']
|
||||
self.pts[t_id].yRel = msg['LAT_DIST']
|
||||
self.pts[t_id].vRel = msg['REL_SPEED']
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan') if self.radar_group3 else msg['REL_ACCEL']
|
||||
self.pts[t_id].yvRel = 0.0 if self.radar_group3 else msg['LAT_SPEED']
|
||||
elif self.radar_group4:
|
||||
self.pts[t_id].dRel = msg['LONG_DIST']
|
||||
self.pts[t_id].yRel = -msg['LAT_DIST']
|
||||
self.pts[t_id].vRel = msg['REL_SPEED']
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0.0
|
||||
else:
|
||||
azimuth = math.radians(msg['AZIMUTH'])
|
||||
self.pts[t_id].dRel = math.cos(azimuth) * msg['LONG_DIST']
|
||||
self.pts[t_id].yRel = 0.5 * -math.sin(azimuth) * msg['LONG_DIST']
|
||||
self.pts[t_id].vRel = msg['REL_SPEED']
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = msg['REL_ACCEL']
|
||||
self.pts[t_id].yvRel = 0.0
|
||||
|
||||
t_id += 1
|
||||
# radar group1? ?나??msg??2개의 ?이?? ?어?음.
|
||||
if self.radar_group1:
|
||||
for addr in range(self.radar_start_addr, self.radar_start_addr + self.radar_msg_count):
|
||||
msg = self.rcp_tracks.vl[f"RADAR_TRACK_{addr:x}"]
|
||||
|
||||
valid = msg['VALID_CNT2'] > 10
|
||||
self.pts[t_id].measured = bool(valid)
|
||||
if not valid:
|
||||
self.pts[t_id].dRel = 0
|
||||
self.pts[t_id].yRel = 0
|
||||
self.pts[t_id].vRel = 0
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0
|
||||
else:
|
||||
self.pts[t_id].dRel = msg['LONG_DIST2']
|
||||
self.pts[t_id].yRel = msg['LAT_DIST2']
|
||||
self.pts[t_id].vRel = msg['REL_SPEED2']
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = msg['REL_ACCEL2']
|
||||
self.pts[t_id].yvRel = msg['LAT_SPEED2']
|
||||
|
||||
t_id += 1
|
||||
|
||||
def _update_corner_objects(self, updated_messages):
|
||||
if self.rcp_corner_objects is None:
|
||||
return
|
||||
|
||||
if not updated_messages:
|
||||
self._clear_corner_objects()
|
||||
return
|
||||
|
||||
candidates = []
|
||||
for slot, addr in enumerate(range(CORNER_OBJECT_235_START_ADDR, CORNER_OBJECT_235_START_ADDR + CORNER_OBJECT_235_MSG_COUNT)):
|
||||
t_id = CORNER_OBJECT_235_TRACK_ID_OFFSET + slot
|
||||
msg = self.rcp_corner_objects.vl[f"CORNER_RADAR_235_OBJECTS_{addr:x}"]
|
||||
|
||||
d_rel = msg["OBJ_REL_POS_X"]
|
||||
y_rel = msg["OBJ_REL_POS_Y"]
|
||||
v_rel = msg["OBJ_REL_VEL_X"]
|
||||
yv_rel = msg["OBJ_REL_VEL_Y"]
|
||||
a_rel = msg["OBJ_REL_ACCEL_X"]
|
||||
# Side objects are clipped to x=0 by the corner radar. Quality, identity,
|
||||
# and lateral motion still describe a real object, so keep them for
|
||||
# corner-confirmed front-radar association in radard.
|
||||
valid = msg["OBJ_QUAL_LEVEL"] > 0 and corner_object_position_valid(d_rel, y_rel) and v_rel > -99.0
|
||||
|
||||
if not valid:
|
||||
continue
|
||||
candidates.append((t_id, int(msg["OBJ_OBJECT_ID"]), int(msg["OBJ_AGE"]), int(msg["OBJ_QUAL_LEVEL"]),
|
||||
d_rel, y_rel, v_rel, yv_rel, a_rel))
|
||||
|
||||
self._apply_corner_objects("corner235", candidates,
|
||||
range(CORNER_OBJECT_235_TRACK_ID_OFFSET,
|
||||
CORNER_OBJECT_235_TRACK_ID_OFFSET + CORNER_OBJECT_235_MSG_COUNT))
|
||||
|
||||
def _update_corner_objects_180(self, updated_messages):
|
||||
if self.rcp_corner_objects_180 is None:
|
||||
return
|
||||
|
||||
if not updated_messages:
|
||||
self._clear_corner_objects_180()
|
||||
return
|
||||
|
||||
candidates = []
|
||||
for msg_index, addr in enumerate(range(CORNER_OBJECT_180_START_ADDR, CORNER_OBJECT_180_START_ADDR + CORNER_OBJECT_180_MSG_COUNT)):
|
||||
msg = self.rcp_corner_objects_180.vl[f"CORNER_RADAR_180_OBJECTS_{addr:x}"]
|
||||
for slot_index in range(CORNER_OBJECT_180_SLOTS_PER_MSG):
|
||||
t_id = CORNER_OBJECT_180_TRACK_ID_OFFSET + msg_index * CORNER_OBJECT_180_SLOTS_PER_MSG + slot_index
|
||||
prefix = f"SLOT{slot_index + 1}_"
|
||||
d_rel = msg[f"{prefix}REL_POS_X"]
|
||||
y_rel = msg[f"{prefix}REL_POS_Y"]
|
||||
v_rel = msg[f"{prefix}REL_VEL_X"]
|
||||
yv_rel = msg[f"{prefix}REL_VEL_Y"]
|
||||
a_rel = msg[f"{prefix}REL_ACCEL_X"]
|
||||
valid = msg[f"{prefix}QUAL_LEVEL"] > 0 and corner_object_position_valid(d_rel, y_rel) and v_rel > -99.0
|
||||
|
||||
if not valid:
|
||||
continue
|
||||
candidates.append((t_id, int(msg[f"{prefix}OBJECT_ID"]), int(msg[f"{prefix}AGE"]), int(msg[f"{prefix}QUAL_LEVEL"]),
|
||||
d_rel, y_rel, v_rel, yv_rel, a_rel))
|
||||
|
||||
self._apply_corner_objects("corner180", candidates,
|
||||
range(CORNER_OBJECT_180_TRACK_ID_OFFSET,
|
||||
CORNER_OBJECT_180_TRACK_ID_OFFSET + CORNER_OBJECT_180_MSG_COUNT * CORNER_OBJECT_180_SLOTS_PER_MSG))
|
||||
|
||||
def _apply_corner_objects(self, source, candidates, slot_ids):
|
||||
for t_id in slot_ids:
|
||||
self._clear_point(t_id)
|
||||
|
||||
# The same object can occupy two CAN slots for one cycle during a slot handoff.
|
||||
# Publish only the newest/highest-quality copy so trackId stays unique.
|
||||
objects = {}
|
||||
for candidate in candidates:
|
||||
object_id = candidate[1]
|
||||
previous = objects.get(object_id)
|
||||
if previous is None or (candidate[2], candidate[3]) > (previous[2], previous[3]):
|
||||
objects[object_id] = candidate
|
||||
|
||||
for t_id, object_id, age, _, d_rel, y_rel, v_rel, yv_rel, a_rel in objects.values():
|
||||
point = self.pts[t_id]
|
||||
point.measured = True
|
||||
point.trackId = self.corner_object_track_ids.get_track_id(source, object_id, age)
|
||||
point.radarSource = source
|
||||
point.dRel = d_rel
|
||||
point.yRel = y_rel
|
||||
point.vRel = v_rel
|
||||
point.vLead = v_rel + self.v_ego
|
||||
point.aRel = a_rel
|
||||
point.yvRel = yv_rel
|
||||
|
||||
|
||||
def _update_corner_objects_430(self, updated_messages):
|
||||
if self.rcp_corner_objects_430 is None:
|
||||
return
|
||||
|
||||
if not updated_messages:
|
||||
self._clear_corner_objects_430()
|
||||
return
|
||||
|
||||
bank_defs = (
|
||||
(CORNER_OBJECT_430_LEFT_START_ADDR, 1.0, 0),
|
||||
(CORNER_OBJECT_430_RIGHT_START_ADDR, -1.0, CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * CORNER_OBJECT_430_SLOTS_PER_MSG),
|
||||
)
|
||||
for start_addr, side_sign, track_base in bank_defs:
|
||||
bins = []
|
||||
for msg_index, addr in enumerate(range(start_addr, start_addr + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE)):
|
||||
msg = self.rcp_corner_objects_430.vl[f"CORNER_RADAR_430_OBJECTS_{addr:x}"]
|
||||
for slot_index in range(CORNER_OBJECT_430_SLOTS_PER_MSG):
|
||||
prefix = f"SLOT{slot_index + 1}_"
|
||||
distance_raw = int(msg[f"{prefix}DISTANCE_RAW"])
|
||||
raw = (
|
||||
distance_raw |
|
||||
(int(msg[f"{prefix}META_13_15"]) << 13) |
|
||||
(int(msg[f"{prefix}META_BYTE_2"]) << 16) |
|
||||
(int(msg[f"{prefix}META_BYTE_3"]) << 24)
|
||||
)
|
||||
code = (
|
||||
int(msg[f"{prefix}META_13_15"]),
|
||||
int(msg[f"{prefix}META_BYTE_2"]),
|
||||
int(msg[f"{prefix}META_BYTE_3"]),
|
||||
)
|
||||
d_rel = distance_raw * 0.05
|
||||
default_distance = CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MIN <= distance_raw <= CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MAX
|
||||
base_valid = (
|
||||
raw not in CORNER_OBJECT_430_EMPTY_RAW_VALUES and
|
||||
distance_raw not in (0, 8000, 8191) and
|
||||
not default_distance and
|
||||
0.2 < d_rel < CORNER_OBJECT_430_MAX_DREL
|
||||
)
|
||||
candidate_valid = (
|
||||
base_valid and
|
||||
slot_index + 1 not in CORNER_OBJECT_430_CANDIDATE_EXCLUDED_SLOTS and
|
||||
code[2] in CORNER_OBJECT_430_CANDIDATE_META_BYTE_3 and
|
||||
code[1] in CORNER_OBJECT_430_STRONG_META_BYTE_2 + CORNER_OBJECT_430_WEAK_META_BYTE_2
|
||||
)
|
||||
bins.append({
|
||||
"msg_index": msg_index,
|
||||
"slot_index": slot_index,
|
||||
"distance_raw": distance_raw,
|
||||
"d_rel": d_rel,
|
||||
"code": code,
|
||||
"candidate_valid": candidate_valid,
|
||||
})
|
||||
|
||||
supported_bins = []
|
||||
candidates = [b for b in bins if b["candidate_valid"]]
|
||||
for b in candidates:
|
||||
support = 1
|
||||
for other in candidates:
|
||||
if other is b:
|
||||
continue
|
||||
if abs(other["msg_index"] - b["msg_index"]) > 1:
|
||||
continue
|
||||
if abs(other["slot_index"] - b["slot_index"]) > 2:
|
||||
continue
|
||||
if abs(other["distance_raw"] - b["distance_raw"]) > CORNER_OBJECT_430_CANDIDATE_RAW_DELTA:
|
||||
continue
|
||||
support += 1
|
||||
min_support = (CORNER_OBJECT_430_STRONG_MIN_SUPPORT if b["code"][1] in CORNER_OBJECT_430_STRONG_META_BYTE_2
|
||||
else CORNER_OBJECT_430_WEAK_MIN_SUPPORT)
|
||||
if support >= min_support:
|
||||
supported_bins.append({**b, "support": support})
|
||||
|
||||
clusters = []
|
||||
for b in sorted(supported_bins, key=lambda item: item["distance_raw"]):
|
||||
if not clusters or b["distance_raw"] - clusters[-1][-1]["distance_raw"] > CORNER_OBJECT_430_CLUSTER_RAW_GAP:
|
||||
clusters.append([b])
|
||||
else:
|
||||
clusters[-1].append(b)
|
||||
clusters = sorted(clusters, key=lambda cluster: sum(b["distance_raw"] for b in cluster) / len(cluster))[:CORNER_OBJECT_430_MAX_TRACKS_PER_SIDE]
|
||||
|
||||
cluster_objects = []
|
||||
for cluster in clusters:
|
||||
msg_index = sum(b["msg_index"] for b in cluster) / len(cluster)
|
||||
slot = sum(b["slot_index"] + 1 for b in cluster) / len(cluster)
|
||||
lateral_cell = (CORNER_OBJECT_430_LATERAL_CELL_MSG_WEIGHT * msg_index +
|
||||
CORNER_OBJECT_430_LATERAL_CELL_SLOT_WEIGHT * slot)
|
||||
mapped_cell = lateral_cell if side_sign > 0.0 else CORNER_OBJECT_430_RIGHT_CELL_MIRROR - lateral_cell
|
||||
y_abs = max(CORNER_OBJECT_430_MIN_ABS_YREL,
|
||||
min(CORNER_OBJECT_430_MAX_ABS_YREL,
|
||||
CORNER_OBJECT_430_YREL_OFFSET - CORNER_OBJECT_430_YREL_SCALE * mapped_cell))
|
||||
cluster_objects.append({
|
||||
"d_rel": sum(b["d_rel"] for b in cluster) / len(cluster),
|
||||
"y_rel": side_sign * y_abs,
|
||||
"code": max((b["code"] for b in cluster), key=lambda code: sum(1 for item in cluster if item["code"] == code)),
|
||||
})
|
||||
|
||||
active_t_ids = set()
|
||||
side_track_ids = [
|
||||
CORNER_OBJECT_430_TRACK_ID_OFFSET + track_base + slot
|
||||
for slot in range(CORNER_OBJECT_430_MAX_TRACKS_PER_SIDE)
|
||||
]
|
||||
unmatched_track_ids = {t_id for t_id in side_track_ids if t_id in self.corner_object_430_prev_d_rel}
|
||||
unused_track_ids = [t_id for t_id in side_track_ids if t_id not in unmatched_track_ids]
|
||||
|
||||
for cluster in cluster_objects:
|
||||
d_rel = cluster["d_rel"]
|
||||
code = cluster["code"]
|
||||
matched_t_id = None
|
||||
if unmatched_track_ids:
|
||||
nearest_t_id = min(unmatched_track_ids, key=lambda t_id: abs(d_rel - self.corner_object_430_prev_d_rel[t_id]))
|
||||
if abs(d_rel - self.corner_object_430_prev_d_rel[nearest_t_id]) <= CORNER_OBJECT_430_TRACK_MATCH_MAX_DREL_DELTA:
|
||||
matched_t_id = nearest_t_id
|
||||
unmatched_track_ids.remove(matched_t_id)
|
||||
if matched_t_id is None and unused_track_ids:
|
||||
matched_t_id = unused_track_ids.pop(0)
|
||||
if matched_t_id is None:
|
||||
continue
|
||||
|
||||
t_id = matched_t_id
|
||||
active_t_ids.add(t_id)
|
||||
prev_d_rel = self.corner_object_430_prev_d_rel.get(t_id)
|
||||
prev_code = self.corner_object_430_prev_code.get(t_id)
|
||||
self.corner_object_430_prev_d_rel[t_id] = d_rel
|
||||
self.corner_object_430_prev_y_rel[t_id] = cluster["y_rel"]
|
||||
self.corner_object_430_prev_code[t_id] = code
|
||||
reset_track = prev_d_rel is None or code != prev_code or abs(d_rel - prev_d_rel) > CORNER_OBJECT_430_MAX_DREL_DELTA
|
||||
if reset_track:
|
||||
self.corner_object_430_prev_v_rel.pop(t_id, None)
|
||||
self.corner_object_430_prev_yv_rel.pop(t_id, None)
|
||||
self.corner_object_430_history.pop(t_id, None)
|
||||
self.corner_object_430_noncenter_inward_frames.pop(t_id, None)
|
||||
|
||||
history = self.corner_object_430_history.setdefault(t_id, deque(maxlen=CORNER_OBJECT_430_HISTORY_SIZE))
|
||||
history.append((d_rel, cluster["y_rel"]))
|
||||
if len(history) < CORNER_OBJECT_430_MIN_HISTORY:
|
||||
self._clear_point(t_id)
|
||||
continue
|
||||
|
||||
window_dt = CORNER_OBJECT_430_DT * (len(history) - 1)
|
||||
first_d_rel, first_y_rel = history[0]
|
||||
hist_v_rel = (d_rel - first_d_rel) / window_dt
|
||||
if abs(hist_v_rel) > CORNER_OBJECT_430_MAX_ABS_VREL:
|
||||
self.corner_object_430_prev_v_rel.pop(t_id, None)
|
||||
self.corner_object_430_prev_yv_rel.pop(t_id, None)
|
||||
self.corner_object_430_history.pop(t_id, None)
|
||||
self.corner_object_430_noncenter_inward_frames.pop(t_id, None)
|
||||
self._clear_point(t_id)
|
||||
continue
|
||||
prev_v_rel = self.corner_object_430_prev_v_rel.get(t_id, hist_v_rel)
|
||||
v_rel = (1.0 - CORNER_OBJECT_430_VREL_ALPHA) * prev_v_rel + CORNER_OBJECT_430_VREL_ALPHA * hist_v_rel
|
||||
self.corner_object_430_prev_v_rel[t_id] = v_rel
|
||||
|
||||
inward_steps = 0
|
||||
usable_steps = 0
|
||||
prev_abs_y = abs(history[0][1])
|
||||
for _, y_rel in list(history)[1:]:
|
||||
abs_y = abs(y_rel)
|
||||
delta = prev_abs_y - abs_y
|
||||
if abs(delta) > 1e-3:
|
||||
usable_steps += 1
|
||||
if delta > 0.0:
|
||||
inward_steps += 1
|
||||
prev_abs_y = abs_y
|
||||
net_inward_y = abs(first_y_rel) - abs(cluster["y_rel"])
|
||||
inward_ratio = inward_steps / usable_steps if usable_steps > 0 else 0.0
|
||||
hist_yv_rel = (cluster["y_rel"] - first_y_rel) / window_dt
|
||||
recent_inward_y = abs(history[-3][1]) - abs(cluster["y_rel"]) if len(history) >= 3 else net_inward_y
|
||||
if (net_inward_y < CORNER_OBJECT_430_MIN_INWARD_YREL_DELTA or
|
||||
recent_inward_y < CORNER_OBJECT_430_MIN_RECENT_INWARD_YREL_DELTA or
|
||||
inward_ratio < CORNER_OBJECT_430_MIN_INWARD_RATIO or
|
||||
abs(hist_yv_rel) > CORNER_OBJECT_430_MAX_ABS_YVREL):
|
||||
hist_yv_rel = 0.0
|
||||
inward_motion_candidate = hist_yv_rel != 0.0 and abs(cluster["y_rel"]) <= CORNER_OBJECT_430_INWARD_KEEP_YVREL_ABS_YREL
|
||||
inward_center_candidate = inward_motion_candidate and abs(cluster["y_rel"]) <= CORNER_OBJECT_430_INWARD_CENTER_ABS_YREL
|
||||
y_rel = cluster["y_rel"]
|
||||
if inward_motion_candidate:
|
||||
if inward_center_candidate:
|
||||
self.corner_object_430_noncenter_inward_frames[t_id] = 0
|
||||
prev_yv_rel = self.corner_object_430_prev_yv_rel.get(t_id, hist_yv_rel)
|
||||
yv_rel = (1.0 - CORNER_OBJECT_430_YVREL_ALPHA) * prev_yv_rel + CORNER_OBJECT_430_YVREL_ALPHA * hist_yv_rel
|
||||
else:
|
||||
noncenter_frames = self.corner_object_430_noncenter_inward_frames.get(t_id, 0) + 1
|
||||
self.corner_object_430_noncenter_inward_frames[t_id] = noncenter_frames
|
||||
if noncenter_frames <= CORNER_OBJECT_430_EARLY_INWARD_NONCENTER_FRAMES:
|
||||
prev_yv_rel = self.corner_object_430_prev_yv_rel.get(t_id, hist_yv_rel)
|
||||
yv_rel = (1.0 - CORNER_OBJECT_430_YVREL_ALPHA) * prev_yv_rel + CORNER_OBJECT_430_YVREL_ALPHA * hist_yv_rel
|
||||
else:
|
||||
yv_rel = 0.0
|
||||
if not inward_center_candidate and abs(y_rel) < CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL:
|
||||
y_rel = math.copysign(CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL, y_rel)
|
||||
else:
|
||||
hist_yv_rel = 0.0
|
||||
yv_rel = 0.0
|
||||
self.corner_object_430_noncenter_inward_frames[t_id] = 0
|
||||
if abs(y_rel) < CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL:
|
||||
y_rel = math.copysign(CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL, y_rel)
|
||||
self.corner_object_430_prev_yv_rel[t_id] = yv_rel
|
||||
|
||||
self.pts[t_id].measured = True
|
||||
self.pts[t_id].trackId = t_id
|
||||
self.pts[t_id].dRel = d_rel
|
||||
self.pts[t_id].yRel = y_rel
|
||||
self.pts[t_id].vRel = v_rel
|
||||
self.pts[t_id].vLead = v_rel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = yv_rel
|
||||
|
||||
side_track_count = CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * CORNER_OBJECT_430_SLOTS_PER_MSG
|
||||
for slot in range(side_track_count):
|
||||
t_id = CORNER_OBJECT_430_TRACK_ID_OFFSET + track_base + slot
|
||||
if t_id in active_t_ids:
|
||||
continue
|
||||
self.corner_object_430_prev_d_rel.pop(t_id, None)
|
||||
self.corner_object_430_prev_v_rel.pop(t_id, None)
|
||||
self.corner_object_430_prev_y_rel.pop(t_id, None)
|
||||
self.corner_object_430_prev_yv_rel.pop(t_id, None)
|
||||
self.corner_object_430_prev_code.pop(t_id, None)
|
||||
self.corner_object_430_history.pop(t_id, None)
|
||||
self.corner_object_430_noncenter_inward_frames.pop(t_id, None)
|
||||
self._clear_point(t_id)
|
||||
|
||||
|
||||
def _clear_point(self, t_id):
|
||||
self.pts[t_id].measured = False
|
||||
self.pts[t_id].dRel = 0
|
||||
self.pts[t_id].yRel = 0
|
||||
self.pts[t_id].vRel = 0
|
||||
self.pts[t_id].vLead = self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0
|
||||
|
||||
def _clear_corner_objects(self):
|
||||
for slot in range(CORNER_OBJECT_235_MSG_COUNT):
|
||||
self._clear_point(CORNER_OBJECT_235_TRACK_ID_OFFSET + slot)
|
||||
self.corner_object_track_ids.clear_source("corner235")
|
||||
|
||||
def _clear_corner_objects_180(self):
|
||||
for slot in range(CORNER_OBJECT_180_MSG_COUNT * CORNER_OBJECT_180_SLOTS_PER_MSG):
|
||||
self._clear_point(CORNER_OBJECT_180_TRACK_ID_OFFSET + slot)
|
||||
self.corner_object_track_ids.clear_source("corner180")
|
||||
|
||||
def _clear_corner_objects_430(self):
|
||||
self.corner_object_430_prev_d_rel.clear()
|
||||
self.corner_object_430_prev_v_rel.clear()
|
||||
self.corner_object_430_prev_y_rel.clear()
|
||||
self.corner_object_430_prev_yv_rel.clear()
|
||||
self.corner_object_430_prev_code.clear()
|
||||
self.corner_object_430_history.clear()
|
||||
self.corner_object_430_noncenter_inward_frames.clear()
|
||||
for slot in range(CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * 2 * CORNER_OBJECT_430_SLOTS_PER_MSG):
|
||||
self._clear_point(CORNER_OBJECT_430_TRACK_ID_OFFSET + slot)
|
||||
|
||||
def _update_scc(self, updated_messages):
|
||||
cpt = self.rcp_scc.vl
|
||||
t_id = SCC_TID
|
||||
if self.canfd:
|
||||
dRel = cpt["SCC_CONTROL"]['ACC_ObjDist']
|
||||
vRel = cpt["SCC_CONTROL"]['ACC_ObjRelSpd']
|
||||
new_pts = abs(dRel - self.dRel_last) > 3 or abs(vRel - self.vRel_last) > 1
|
||||
vLead = vRel + self.v_ego
|
||||
valid = 0 < dRel < 150 and not new_pts #cpt["SCC_CONTROL"]['OBJ_STATUS'] and dRel < 150
|
||||
self.pts[t_id].measured = bool(valid)
|
||||
if not valid:
|
||||
self.pts[t_id].dRel = 0
|
||||
self.pts[t_id].yRel = 0
|
||||
self.pts[t_id].vRel = 0
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0
|
||||
else:
|
||||
self.pts[t_id].dRel = dRel
|
||||
self.pts[t_id].yRel = 0
|
||||
self.pts[t_id].vRel = vRel
|
||||
self.pts[t_id].vLead = vLead
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0 #float('nan')
|
||||
else:
|
||||
dRel = cpt["SCC11"]['ACC_ObjDist']
|
||||
vRel = cpt["SCC11"]['ACC_ObjRelSpd']
|
||||
new_pts = abs(dRel - self.dRel_last) > 3 or abs(vRel - self.vRel_last) > 1
|
||||
vLead = vRel + self.v_ego
|
||||
valid = cpt["SCC11"]['ACC_ObjStatus'] and dRel < 150 and not new_pts
|
||||
self.pts[t_id].measured = bool(valid)
|
||||
if not valid:
|
||||
self.pts[t_id].dRel = 0
|
||||
self.pts[t_id].yRel = 0
|
||||
self.pts[t_id].vRel = 0
|
||||
self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0
|
||||
else:
|
||||
self.pts[t_id].dRel = dRel
|
||||
self.pts[t_id].yRel = -cpt["SCC11"]['ACC_ObjLatPos'] # in car frame's y axis, left is negative
|
||||
self.pts[t_id].vRel = vRel
|
||||
self.pts[t_id].vLead = vLead
|
||||
self.pts[t_id].aRel = float('nan')
|
||||
self.pts[t_id].yvRel = 0 #float('nan')
|
||||
|
||||
self.dRel_last = dRel
|
||||
self.vRel_last = vRel
|
||||
|
||||
0
iqdbc_repo/iqdbc/car/hyundai/tests/print_platform_codes.py
Executable file → Normal file
0
iqdbc_repo/iqdbc/car/hyundai/tests/print_platform_codes.py
Executable file → Normal file
194
iqdbc_repo/iqdbc/car/hyundai/tests/test_ev_mode.py
Normal file
194
iqdbc_repo/iqdbc/car/hyundai/tests/test_ev_mode.py
Normal file
@@ -0,0 +1,194 @@
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
from iqdbc.can import CANPacker, CANParser
|
||||
from iqdbc.car import Bus, gen_empty_fingerprint, structs
|
||||
from iqdbc.car.hyundai.carstate import CarState, EV_MODE_STATUS_TIMEOUT_NS, _get_ev_mode_state
|
||||
from iqdbc.car.hyundai.interface import CarInterface
|
||||
from iqdbc.car.hyundai.values import CANFD_HYBRID_STATUS_ADDR, CANFD_HYBRID_STATUS_DLC, CAR, DBC, EV_MODE_ACTIVE_VALUES, \
|
||||
EV_MODE_STATUS_ADDR, EV_MODE_STATUS_DLC, EV_MODE_STATUS_MSG, EV_MODE_STATUS_SIGNAL, \
|
||||
HyundaiExtFlags, HyundaiFlags
|
||||
from openpilot.common.params import Params
|
||||
|
||||
|
||||
def get_params(candidate, *, hybrid=True, hybrid_bus=0, hybrid_status=None, hybrid_status_bus=0,
|
||||
hybrid_status_dlc=CANFD_HYBRID_STATUS_DLC, status_bus=0, status_dlc=EV_MODE_STATUS_DLC):
|
||||
Params().put_int("HyundaiCameraSCC", 1)
|
||||
Params().put_int("CanfdHDA2", 1)
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if hybrid:
|
||||
fingerprint[hybrid_bus][0x105] = 32
|
||||
if hybrid_status is None:
|
||||
hybrid_status = hybrid
|
||||
if hybrid_status:
|
||||
fingerprint[hybrid_status_bus][CANFD_HYBRID_STATUS_ADDR] = hybrid_status_dlc
|
||||
if status_bus is not None:
|
||||
fingerprint[status_bus][EV_MODE_STATUS_ADDR] = status_dlc
|
||||
return CarInterface.get_params(candidate, fingerprint, [], False, False, False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("candidate", "hybrid", "status_bus", "status_dlc", "expected"), (
|
||||
(CAR.HYUNDAI_SANTAFE_MX5_HEV, True, 0, 32, True),
|
||||
(CAR.HYUNDAI_SANTAFE_MX5_HEV, False, 0, 32, False),
|
||||
(CAR.HYUNDAI_SANTAFE_MX5_HEV, True, None, 32, False),
|
||||
(CAR.HYUNDAI_SANTAFE_MX5_HEV, True, 1, 32, False),
|
||||
(CAR.HYUNDAI_SANTAFE_MX5_HEV, True, 0, 16, False),
|
||||
(CAR.KIA_SORENTO_4TH_GEN, False, None, 32, False),
|
||||
# Shared ICE/HEV/PHEV candidates rely on the observed ECAN capability frames, not their model name.
|
||||
(CAR.HYUNDAI_TUCSON_4TH_GEN, True, 0, 32, True),
|
||||
(CAR.HYUNDAI_TUCSON_4TH_GEN, False, 0, 32, False),
|
||||
(CAR.KIA_SORENTO_HEV_4TH_GEN, True, 0, 32, True),
|
||||
(CAR.HYUNDAI_KONA_HEV_2ND_GEN, True, 0, 32, True),
|
||||
(CAR.HYUNDAI_KONA_HEV_2ND_GEN, False, 0, 32, False),
|
||||
(CAR.HYUNDAI_ELANTRA_HEV_2021, True, 0, 32, False),
|
||||
))
|
||||
def test_ev_mode_capability(candidate, hybrid, status_bus, status_dlc, expected):
|
||||
CP = get_params(candidate, hybrid=hybrid, status_bus=status_bus, status_dlc=status_dlc)
|
||||
assert bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("hybrid_status_bus", "hybrid_status_dlc"), (
|
||||
(1, CANFD_HYBRID_STATUS_DLC),
|
||||
(0, 16),
|
||||
))
|
||||
def test_ev_mode_capability_requires_ecan_hybrid_status_dlc32(hybrid_status_bus, hybrid_status_dlc):
|
||||
CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV, hybrid_status_bus=hybrid_status_bus,
|
||||
hybrid_status_dlc=hybrid_status_dlc)
|
||||
|
||||
assert not bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
|
||||
|
||||
|
||||
def test_0x105_and_ev_status_without_0xfa_do_not_enable_ev_mode():
|
||||
CP = get_params(CAR.HYUNDAI_TUCSON_4TH_GEN, hybrid=True, hybrid_status=False)
|
||||
|
||||
assert bool(CP.flags & HyundaiFlags.HYBRID)
|
||||
assert not bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
|
||||
|
||||
|
||||
def test_ev_mode_display_capability_does_not_change_hybrid_safety_classification():
|
||||
CP = get_params(CAR.HYUNDAI_TUCSON_4TH_GEN, hybrid=False, hybrid_status=True)
|
||||
|
||||
assert not bool(CP.flags & HyundaiFlags.HYBRID)
|
||||
assert bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
|
||||
|
||||
|
||||
def test_ev_mode_capability_uses_the_detected_ecan_offset():
|
||||
CP = get_params(CAR.KIA_SORENTO_HEV_4TH_GEN, hybrid_bus=4, hybrid_status_bus=4, status_bus=4)
|
||||
|
||||
assert bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
|
||||
|
||||
|
||||
def test_ev_mode_parser_registration_is_capability_gated():
|
||||
supported = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
|
||||
unsupported = get_params(CAR.KIA_SORENTO_4TH_GEN, hybrid=False, status_bus=1, status_dlc=16)
|
||||
|
||||
supported_parser = CarState.get_can_parsers_canfd(None, supported)[Bus.pt]
|
||||
unsupported_parser = CarState.get_can_parsers_canfd(None, unsupported)[Bus.pt]
|
||||
|
||||
assert EV_MODE_STATUS_ADDR in supported_parser.addresses
|
||||
assert supported_parser.message_states[EV_MODE_STATUS_ADDR].ignore_alive
|
||||
assert supported_parser.message_states[EV_MODE_STATUS_ADDR].ignore_counter
|
||||
assert EV_MODE_STATUS_ADDR not in unsupported_parser.addresses
|
||||
|
||||
|
||||
def test_sorento_ice_corner_radar_status_does_not_enable_ev_mode():
|
||||
Params().put_int("HyundaiCameraSCC", 1)
|
||||
Params().put_int("CanfdHDA2", 1)
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[1][0x230] = 16 # Actual Sorento ICE ACAN corner-radar status frame.
|
||||
CP = CarInterface.get_params(CAR.KIA_SORENTO_4TH_GEN, fingerprint, [], False, False, False)
|
||||
parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
|
||||
|
||||
assert not bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
|
||||
assert EV_MODE_STATUS_ADDR not in parser.addresses
|
||||
|
||||
|
||||
def test_ev_mode_state_requires_a_fresh_dlc32_frame():
|
||||
CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
|
||||
parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
assert _get_ev_mode_state(parser) == (False, False)
|
||||
|
||||
timestamp = 1_000_000_000
|
||||
wrong_bus_short_status = (EV_MODE_STATUS_ADDR, b"\x00" * 16, 1)
|
||||
parser.update([timestamp, [wrong_bus_short_status]])
|
||||
assert _get_ev_mode_state(parser) == (False, False)
|
||||
|
||||
ev_active = packer.make_can_msg(EV_MODE_STATUS_MSG, parser.bus, {"COUNTER": 1, EV_MODE_STATUS_SIGNAL: 6})
|
||||
parser.update([timestamp + 100_000_000, [ev_active]])
|
||||
assert _get_ev_mode_state(parser) == (True, True)
|
||||
|
||||
ev_inactive = packer.make_can_msg(EV_MODE_STATUS_MSG, parser.bus, {"COUNTER": 2, EV_MODE_STATUS_SIGNAL: 3})
|
||||
parser.update([timestamp + 200_000_000, [ev_inactive]])
|
||||
assert _get_ev_mode_state(parser) == (False, True)
|
||||
|
||||
parser.dat[EV_MODE_STATUS_ADDR] = b"\x00" * 16
|
||||
assert _get_ev_mode_state(parser) == (False, False)
|
||||
|
||||
parser.dat[EV_MODE_STATUS_ADDR] = ev_inactive[1]
|
||||
parser.update([timestamp + 200_000_000 + EV_MODE_STATUS_TIMEOUT_NS + 1, []])
|
||||
assert not parser.bus_timeout
|
||||
assert _get_ev_mode_state(parser) == (False, False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", range(16))
|
||||
def test_ev_mode_enum_mapping(mode):
|
||||
CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
|
||||
parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
msg = packer.make_can_msg(EV_MODE_STATUS_MSG, parser.bus, {"COUNTER": mode, EV_MODE_STATUS_SIGNAL: mode})
|
||||
|
||||
parser.update([1_000_000_000, [msg]])
|
||||
|
||||
assert int(parser.vl[EV_MODE_STATUS_MSG][EV_MODE_STATUS_SIGNAL]) == mode
|
||||
assert _get_ev_mode_state(parser) == (mode in EV_MODE_ACTIVE_VALUES, True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("payload", "expected_mode", "expected_active"), (
|
||||
("758139048402000000000000000000000000d3009805001c24000000c05dc80f", 1, True),
|
||||
("4d466f048402000000000000000000000000bf007408001c24000000c05dc80f", 2, True),
|
||||
("32206e048402000000000000000000000000c9007418001c24000000c05dc80f", 6, True),
|
||||
# Route 455 mode 3 was a false positive with the old single-bit 0x230 interpretation.
|
||||
("4f935e0484020000000000000000000000004400640d001c10000000c05dc40f", 3, False),
|
||||
("066558048402000000000000000000000000c4003020001c24000000c05dc80f", 8, False),
|
||||
("059683048402000000000000000000000000a1008425001c24000000c05dc80f", 9, False),
|
||||
("011305048402000000000000000000000000d600a829001c24000000c05dc80f", 10, False),
|
||||
))
|
||||
def test_ev_mode_dbc_decodes_real_mx5_frames(payload, expected_mode, expected_active):
|
||||
parser = CANParser("hyundai_canfd_generated", [(EV_MODE_STATUS_MSG, math.nan)], 0)
|
||||
updated = parser.update([1_000_000_000, [(EV_MODE_STATUS_ADDR, bytes.fromhex(payload), 0)]])
|
||||
|
||||
assert updated == {EV_MODE_STATUS_ADDR}
|
||||
assert int(parser.vl[EV_MODE_STATUS_MSG][EV_MODE_STATUS_SIGNAL]) == expected_mode
|
||||
assert _get_ev_mode_state(parser) == (expected_active, True)
|
||||
|
||||
|
||||
def test_ev_mode_rejects_checksum_corruption():
|
||||
CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
|
||||
parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
|
||||
payload = bytearray.fromhex("32206e048402000000000000000000000000c9007418001c24000000c05dc80f")
|
||||
payload[-1] ^= 1
|
||||
|
||||
parser.update([1_000_000_000, [(EV_MODE_STATUS_ADDR, bytes(payload), parser.bus)]])
|
||||
|
||||
assert EV_MODE_STATUS_ADDR not in parser.dat
|
||||
assert _get_ev_mode_state(parser) == (False, False)
|
||||
|
||||
|
||||
def test_ev_mode_fields_default_invalid():
|
||||
state = structs.CarState()
|
||||
assert not state.evModeActive
|
||||
assert not state.evModeValid
|
||||
|
||||
|
||||
def test_ev_mode_parser_is_optional_for_can_validity():
|
||||
CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
|
||||
parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
|
||||
state = parser.message_states[EV_MODE_STATUS_ADDR]
|
||||
|
||||
assert state.ignore_alive
|
||||
assert state.ignore_counter
|
||||
@@ -6,13 +6,11 @@ from iqdbc.car import gen_empty_fingerprint
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.fw_versions import build_fw_dict
|
||||
from iqdbc.car.hyundai.interface import CarInterface
|
||||
from iqdbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from iqdbc.car.hyundai.radar_interface import RADAR_START_ADDR
|
||||
from iqdbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
|
||||
HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, CANFD_FUZZY_WHITELIST, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
|
||||
HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
|
||||
NON_SCC_CAR
|
||||
from iqdbc.car.hyundai.values import CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
|
||||
HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, \
|
||||
PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
|
||||
HyundaiFlags, get_platform_codes, HyundaiSafetyFlags
|
||||
from iqdbc.car.hyundai.fingerprints import FW_VERSIONS
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
@@ -45,16 +43,8 @@ CANFD_EXPECTED_ECUS = {Ecu.fwdCamera, Ecu.fwdRadar}
|
||||
|
||||
|
||||
class TestHyundaiFingerprint:
|
||||
def test_feature_detection(self):
|
||||
# LKA steering
|
||||
for lka_steering in (True, False):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if lka_steering:
|
||||
cam_can = CanBus(None, fingerprint).CAM
|
||||
fingerprint[cam_can] = [0x50, 0x110] # LKA steering messages
|
||||
CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False)
|
||||
assert bool(CP.flags & HyundaiFlags.CANFD_LKA_STEERING) == lka_steering
|
||||
|
||||
def test_feature_detection(self, monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
|
||||
# radar available
|
||||
for radar in (True, False):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
@@ -74,19 +64,20 @@ class TestHyundaiFingerprint:
|
||||
# Test no EV/HEV in any gear lists (should all use ELECT_GEAR)
|
||||
assert set.union(*CAN_GEARS.values()) & (HYBRID_CAR | EV_CAR) == set()
|
||||
|
||||
# Test CAN FD car not in CAN feature lists
|
||||
can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR, UNSUPPORTED_LONGITUDINAL_CAR, CAMERA_SCC_CAR)
|
||||
# Test CAN FD cars are not classified with classic-CAN-only parsing or safety modes.
|
||||
can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR)
|
||||
for car_model in CANFD_CAR:
|
||||
assert car_model not in can_specific_feature_list, "CAN FD car unexpectedly found in a CAN feature list"
|
||||
|
||||
def test_hybrid_ev_sets(self):
|
||||
assert HYBRID_CAR & EV_CAR == set(), "Shared cars between hybrid and EV"
|
||||
assert CANFD_CAR & HYBRID_CAR == set(), "Hard coding CAN FD cars as hybrid is no longer supported"
|
||||
assert HYBRID_CAR <= set(CAR)
|
||||
assert EV_CAR <= set(CAR)
|
||||
|
||||
def test_canfd_ecu_whitelist(self):
|
||||
# Asserts only expected Ecus can exist in database for CAN-FD cars
|
||||
for car_model in CANFD_CAR:
|
||||
ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()}
|
||||
ecus = {fw[0] for fw in FW_VERSIONS.get(car_model, {}).keys()}
|
||||
ecus_not_in_whitelist = ecus - CANFD_EXPECTED_ECUS
|
||||
ecu_strings = ", ".join([f"Ecu.{ecu}" for ecu in ecus_not_in_whitelist])
|
||||
assert len(ecus_not_in_whitelist) == 0, \
|
||||
@@ -158,8 +149,6 @@ class TestHyundaiFingerprint:
|
||||
continue
|
||||
if platform_code_ecu == Ecu.eps and car_model in no_eps_platforms:
|
||||
continue
|
||||
if car_model in NON_SCC_CAR:
|
||||
continue
|
||||
assert platform_code_ecu in [e[0] for e in ecus]
|
||||
|
||||
def test_fw_format(self, subtests):
|
||||
@@ -174,9 +163,6 @@ class TestHyundaiFingerprint:
|
||||
if ecu[0] not in PLATFORM_CODE_ECUS:
|
||||
continue
|
||||
|
||||
if car_model in NON_SCC_CAR:
|
||||
continue
|
||||
|
||||
codes = set()
|
||||
for fw in fws:
|
||||
result = get_platform_codes([fw])
|
||||
@@ -225,15 +211,6 @@ class TestHyundaiFingerprint:
|
||||
(b"ON-S9100", b"190405"), (b"ON-S9100", b"190720")}
|
||||
|
||||
def test_fuzzy_excluded_platforms(self):
|
||||
# Asserts a list of platforms that will not fuzzy fingerprint with platform codes due to them being shared.
|
||||
# This list can be shrunk as we combine platforms and detect features
|
||||
excluded_platforms = {
|
||||
CAR.GENESIS_G70, # shared platform code, part number, and date
|
||||
CAR.GENESIS_G70_2020,
|
||||
}
|
||||
excluded_platforms |= CANFD_CAR - EV_CAR - CANFD_FUZZY_WHITELIST # shared platform codes
|
||||
excluded_platforms |= NO_DATES_PLATFORMS # date codes are required to match
|
||||
|
||||
platforms_with_shared_codes = set()
|
||||
for platform, fw_by_addr in FW_VERSIONS.items():
|
||||
car_fw = []
|
||||
@@ -243,9 +220,6 @@ class TestHyundaiFingerprint:
|
||||
car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr,
|
||||
subAddress=0 if sub_addr is None else sub_addr))
|
||||
|
||||
if platform in NON_SCC_CAR:
|
||||
continue
|
||||
|
||||
CP = CarParams(carFw=car_fw)
|
||||
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS)
|
||||
if len(matches) == 1:
|
||||
@@ -253,4 +227,6 @@ class TestHyundaiFingerprint:
|
||||
else:
|
||||
platforms_with_shared_codes.add(platform)
|
||||
|
||||
assert platforms_with_shared_codes == excluded_platforms
|
||||
# A unique fuzzy match must always resolve back to the platform that supplied the firmware.
|
||||
# Ambiguity is expected for shared platform codes and for platforms without parseable dates.
|
||||
assert {CAR.GENESIS_G70, CAR.GENESIS_G70_2020} <= platforms_with_shared_codes
|
||||
|
||||
53
iqdbc_repo/iqdbc/car/hyundai/tests/test_integration.py
Normal file
53
iqdbc_repo/iqdbc/car/hyundai/tests/test_integration.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
|
||||
from iqdbc.car import gen_empty_fingerprint, structs
|
||||
from iqdbc.car.hyundai.interface import CarInterface
|
||||
from iqdbc.car.hyundai.values import CAR, HyundaiFlagsIQ, HyundaiSafetyFlagsIQ
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate", list(CAR), ids=lambda candidate: candidate.value)
|
||||
@pytest.mark.parametrize("alpha_long", (False, True), ids=("stock_long", "openpilot_long"))
|
||||
def test_all_platform_state_controller_and_radar(candidate, alpha_long, monkeypatch, tmp_path):
|
||||
"""Every declared HKG platform must initialize and execute one complete interface cycle."""
|
||||
monkeypatch.setenv("PARAMS_ROOT", str(tmp_path / candidate.value))
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
|
||||
cp = CarInterface.get_params(candidate, fingerprint, [], alpha_long, False, False)
|
||||
cp_iq = CarInterface.get_params_iq(cp, candidate, fingerprint, [], alpha_long, False, False)
|
||||
interface = CarInterface(cp, cp_iq)
|
||||
|
||||
state, state_iq = interface.update([])
|
||||
actuators, can_sends = interface.apply(structs.CarControl().as_reader(), structs.IQCarControl())
|
||||
radar = interface.RadarInterface(cp, cp_iq)
|
||||
radar_result = radar.update([])
|
||||
|
||||
assert state.vEgo == 0.0
|
||||
assert state_iq is not None
|
||||
assert actuators is not None
|
||||
assert isinstance(can_sends, list)
|
||||
assert radar_result is None
|
||||
|
||||
|
||||
def test_parameter_defaults_do_not_require_persisted_fingerprint(monkeypatch, tmp_path):
|
||||
"""A clean installation must not crash when carrotpilot-specific Params have not been written yet."""
|
||||
monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
|
||||
cp = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
|
||||
cp_iq = CarInterface.get_params_iq(cp, CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
|
||||
interface = CarInterface(cp, cp_iq)
|
||||
|
||||
state, _ = interface.update([])
|
||||
assert state.vEgo == 0.0
|
||||
|
||||
|
||||
def test_classic_lfa_button_capability_survives_iq_module_removal(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
|
||||
cp = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
|
||||
cp_iq = CarInterface.get_params_iq(cp, CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
|
||||
|
||||
assert cp_iq.flags & HyundaiFlagsIQ.HAS_LFA_BUTTON
|
||||
assert cp_iq.iqSafetyFlags & HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON
|
||||
326
iqdbc_repo/iqdbc/car/hyundai/tests/test_radar.py
Normal file
326
iqdbc_repo/iqdbc/car/hyundai/tests/test_radar.py
Normal file
@@ -0,0 +1,326 @@
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
from iqdbc.can import CANParser
|
||||
from iqdbc.car import Bus, structs
|
||||
import iqdbc.car.hyundai.hyundaicanfd as hyundaicanfd
|
||||
import iqdbc.car.hyundai.radar_interface as radar_interface_module
|
||||
from iqdbc.car.hyundai.radar_interface import (
|
||||
CORNER_OBJECT_STABLE_TRACK_ID_START,
|
||||
RADAR_MSG_COUNT3,
|
||||
RADAR_MSG_COUNT4,
|
||||
RADAR_START_ADDR_CANFD3,
|
||||
CornerObjectTrackIdManager,
|
||||
RadarInterface,
|
||||
corner_object_position_valid,
|
||||
)
|
||||
from iqdbc.car.hyundai.values import CAR, HyundaiExtFlags, HyundaiFlags
|
||||
|
||||
|
||||
class TestDensoRadar:
|
||||
@staticmethod
|
||||
def parse(addr, dat):
|
||||
name = f"RADAR_TRACK_{addr:x}"
|
||||
parser = CANParser("hyundai_kia_denso_front_radar_generated", [(name, 20)], 1)
|
||||
parser.update([0, [(addr, bytes.fromhex(dat), 1)]])
|
||||
return parser.vl[name]
|
||||
|
||||
def test_active_track_signals(self):
|
||||
# Person walking toward the parked car, left of the camera center.
|
||||
track = self.parse(0x503, "bc047efcc1fe8b00")
|
||||
|
||||
assert track["LONG_DIST"] == pytest.approx(7.1875)
|
||||
assert track["LAT_DIST"] == pytest.approx(-1.625)
|
||||
assert track["REL_SPEED"] == pytest.approx(-0.734375)
|
||||
assert track["OBJECT_STATE"] == 3
|
||||
|
||||
def test_empty_track(self):
|
||||
track = self.parse(0x507, "53fff80000000081")
|
||||
|
||||
assert track["LONG_DIST"] == pytest.approx(409.55)
|
||||
assert track["LAT_DIST"] == 0
|
||||
assert track["REL_SPEED"] == 0
|
||||
assert track["OBJECT_STATE"] == 0
|
||||
|
||||
def test_long_range_lateral_distance(self):
|
||||
# Real driving sample: treating the signed field as -12 degrees would put
|
||||
# this target about 34 m sideways at 161 m. It is instead -3.0 m lateral.
|
||||
track = self.parse(0x506, "b664eafa00cd230b")
|
||||
|
||||
assert track["LONG_DIST"] == pytest.approx(161.4625)
|
||||
assert track["LAT_DIST"] == pytest.approx(-3.0)
|
||||
assert track["OBJECT_STATE"] == 3
|
||||
|
||||
def test_parser_selection_and_point_conversion(self, monkeypatch):
|
||||
class FakeParams:
|
||||
def get_int(self, key):
|
||||
return 1 if key == "EnableRadarTracks" else 0
|
||||
|
||||
monkeypatch.setattr(radar_interface_module, "Params", FakeParams)
|
||||
cp = structs.CarParams()
|
||||
cp.carFingerprint = CAR.KIA_SORENTO
|
||||
cp.flags = 0
|
||||
cp.extFlags = HyundaiExtFlags.RADAR_GROUP4.value
|
||||
cp.radarUnavailable = False
|
||||
cp.safetyConfigs = [structs.CarParams.SafetyConfig()]
|
||||
|
||||
radar_interface = RadarInterface(cp)
|
||||
|
||||
assert radar_interface.radar_group4
|
||||
assert RADAR_MSG_COUNT4 == 8
|
||||
assert radar_interface.radar_msg_count == RADAR_MSG_COUNT4
|
||||
assert radar_interface.trigger_msg_tracks == 0x507
|
||||
|
||||
active_dat = bytes.fromhex("bc047efcc1fe8b00")
|
||||
empty_dat = bytes.fromhex("bcfff80000000081")
|
||||
packets = [(addr, active_dat if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
point = next(point for point in radar_data.points if point.trackId == 35)
|
||||
|
||||
assert point.measured
|
||||
assert point.dRel == pytest.approx(7.1875)
|
||||
assert point.yRel == pytest.approx(1.625)
|
||||
assert point.vRel == pytest.approx(-0.734375)
|
||||
assert math.isnan(point.aRel)
|
||||
|
||||
# EN: Confirm that the long-range sample survives the filter and converts
|
||||
# radar-left-negative to openpilot-left-positive coordinates.
|
||||
# KO: 장거리 샘플의 필터 통과와 레이더 좌측 음수 좌표가 openpilot 좌측
|
||||
# 양수 좌표로 변환되는지 확인함.
|
||||
long_range_dat = bytes.fromhex("b664eafa00cd230b")
|
||||
packets = [(addr, long_range_dat if addr == 0x506 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
point = next(point for point in radar_data.points if point.trackId == 38)
|
||||
|
||||
assert point.dRel == pytest.approx(161.4625)
|
||||
assert point.yRel == pytest.approx(3.0)
|
||||
|
||||
# EN: A state-0 raw detection must not enter a stable tracked-object slot.
|
||||
# KO: 상태 0인 raw detection이 안정적인 추적 객체 슬롯에 들어오지 않음을 확인함.
|
||||
raw_detection = bytes.fromhex("d702f4fc200000e4")
|
||||
packets = [(addr, raw_detection if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
assert not radar_data.points
|
||||
|
||||
# EN: A real confirmed track beyond the former 205 m limit remains valid.
|
||||
# KO: 기존 205m 상한을 넘는 실제 확정 트랙도 유효하게 유지됨.
|
||||
confirmed_213m_track = bytes.fromhex("35854c0780f163e0")
|
||||
packets = [(addr, confirmed_213m_track if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
point = next(point for point in radar_data.points if point.trackId == 35)
|
||||
assert point.dRel == pytest.approx(213.275)
|
||||
assert point.yRel == pytest.approx(-3.75)
|
||||
|
||||
# EN: The 325 m boundary is rejected, leaving ample separation from the
|
||||
# 409.55 m empty-slot sentinel.
|
||||
# KO: 325m 경계값을 제외해 409.55m 빈 슬롯 값과 충분한 간격을 확보함.
|
||||
boundary_track = bytes.fromhex("bccb200000000300")
|
||||
packets = [(addr, boundary_track if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
assert not radar_data.points
|
||||
|
||||
# EN: The wider profile keeps a real stable track at 4.875 m, covering more
|
||||
# of the outer adjacent lane than the conservative 4.5 m profile.
|
||||
# KO: 넓어진 필터에서 4.875m의 실제 안정 트랙을 유지해 보수적인 4.5m
|
||||
# 설정보다 바깥쪽 인접 차선을 더 넓게 포함함.
|
||||
outer_lane_track = bytes.fromhex("d80b66f640000300")
|
||||
packets = [(addr, outer_lane_track if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
point = next(point for point in radar_data.points if point.trackId == 35)
|
||||
assert point.yRel == pytest.approx(4.875)
|
||||
|
||||
# EN: Tracks beyond the widened envelope are rejected as roadside clutter;
|
||||
# this payload differs only in lateral distance (-7.0 m).
|
||||
# KO: 넓어진 범위를 벗어난 트랙은 도로변 잡음으로 제외함. 이 payload는
|
||||
# 횡방향 거리(-7.0m)만 다름.
|
||||
far_side_reflection = bytes.fromhex("d80b66f200000300")
|
||||
packets = [(addr, far_side_reflection if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
assert not radar_data.points
|
||||
|
||||
|
||||
class TestRadarGroup3:
|
||||
@staticmethod
|
||||
def parse(addr, dat):
|
||||
name = f"RADAR_TRACK_{addr:x}"
|
||||
parser = CANParser("hyundai_canfd_radar_generated", [(name, 20)], 1)
|
||||
parser.update([0, [(addr, bytes.fromhex(dat), 1)]])
|
||||
return parser.vl[name]
|
||||
|
||||
def test_group3_active_track(self):
|
||||
track = self.parse(0x406, "e1043b0f02590e692a227e16f80fe00f28fcc753a20a0000")
|
||||
|
||||
assert track["OBJECT_LENGTH"] == pytest.approx(4.4)
|
||||
assert track["LONG_DIST"] == pytest.approx(55.4)
|
||||
assert track["LAT_DIST"] == pytest.approx(-3.0)
|
||||
assert track["REL_SPEED"] == pytest.approx(4.4)
|
||||
|
||||
def test_group3_empty_track(self):
|
||||
track = self.parse(0x407, "c03d3b0000000000ff0700000000000000d0020000000000")
|
||||
|
||||
assert track["OBJECT_LENGTH"] == 0
|
||||
assert track["LONG_DIST"] == pytest.approx(204.7)
|
||||
assert track["LAT_DIST"] == 0
|
||||
assert track["REL_SPEED"] == 0
|
||||
|
||||
def test_group3_parser_selection(self, monkeypatch):
|
||||
class FakeParams:
|
||||
def get_int(self, key):
|
||||
return 1 if key == "EnableRadarTracks" else 0
|
||||
|
||||
monkeypatch.setattr(radar_interface_module, "Params", FakeParams)
|
||||
monkeypatch.setattr(hyundaicanfd, "Params", FakeParams)
|
||||
cp = structs.CarParams()
|
||||
cp.carFingerprint = next(car for car, dbc in radar_interface_module.DBC.items() if "hyundai_canfd" in dbc[Bus.pt])
|
||||
cp.flags = HyundaiFlags.CANFD.value
|
||||
cp.extFlags = HyundaiExtFlags.RADAR_GROUP3.value
|
||||
cp.radarUnavailable = False
|
||||
cp.safetyConfigs = [structs.CarParams.SafetyConfig()]
|
||||
|
||||
radar_interface = RadarInterface(cp)
|
||||
|
||||
assert radar_interface.radar_group3
|
||||
assert radar_interface.radar_start_addr == RADAR_START_ADDR_CANFD3
|
||||
assert radar_interface.radar_msg_count == RADAR_MSG_COUNT3
|
||||
assert radar_interface.trigger_msg_tracks == 0x41D
|
||||
|
||||
active_dat = bytes.fromhex("e1043b0f02590e692a227e16f80fe00f28fcc753a20a0000")
|
||||
empty_dat = bytes.fromhex("c03d3b0000000000ff0700000000000000d0020000000000")
|
||||
packets = [(addr, active_dat if addr == 0x406 else empty_dat, 1) for addr in range(0x400, 0x41E)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
point = next(point for point in radar_data.points if point.trackId == 38)
|
||||
|
||||
assert point.measured
|
||||
assert point.dRel == pytest.approx(53.1)
|
||||
assert point.yRel == pytest.approx(-3.0)
|
||||
assert point.vRel == pytest.approx(4.4)
|
||||
|
||||
|
||||
class TestCornerRadarObjectIdentity:
|
||||
@staticmethod
|
||||
def set_bits(data, start, size, value):
|
||||
for offset in range(size):
|
||||
bit = start + offset
|
||||
data[bit // 8] |= ((value >> offset) & 1) << (bit % 8)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dbc,msg_name,addr,age_signal,id_signal,age_start,id_start",
|
||||
(
|
||||
("hyundai_canfd_corner_radar_180_generated", "CORNER_RADAR_180_OBJECTS_180", 0x180,
|
||||
"SLOT1_AGE", "SLOT1_OBJECT_ID", 32, 44),
|
||||
("hyundai_canfd_corner_radar_235_generated", "CORNER_RADAR_235_OBJECTS_235", 0x235,
|
||||
"OBJ_AGE", "OBJ_OBJECT_ID", 32, 44),
|
||||
),
|
||||
)
|
||||
def test_object_identity_signals(self, dbc, msg_name, addr, age_signal, id_signal, age_start, id_start):
|
||||
data = bytearray(32)
|
||||
self.set_bits(data, age_start, 8, 23)
|
||||
self.set_bits(data, id_start, 7, 46)
|
||||
parser = CANParser(dbc, [(msg_name, 33)], 1)
|
||||
parser.update([0, [(addr, bytes(data), 1)]])
|
||||
|
||||
assert parser.vl[msg_name][age_signal] == 23
|
||||
assert parser.vl[msg_name][id_signal] == 46
|
||||
|
||||
def test_track_id_survives_slot_move_and_resets_with_age(self):
|
||||
manager = CornerObjectTrackIdManager()
|
||||
first_id = manager.get_track_id("corner180", object_id=108, age=240)
|
||||
|
||||
assert first_id == CORNER_OBJECT_STABLE_TRACK_ID_START
|
||||
assert manager.get_track_id("corner180", object_id=108, age=241) == first_id
|
||||
assert manager.get_track_id("corner235", object_id=108, age=241) != first_id
|
||||
assert manager.get_track_id("corner180", object_id=108, age=2) != first_id
|
||||
|
||||
def test_clipped_side_object_position_is_valid(self):
|
||||
assert corner_object_position_valid(0.0, 2.8)
|
||||
assert corner_object_position_valid(25.0, 0.2)
|
||||
assert not corner_object_position_valid(0.0, 0.0)
|
||||
assert not corner_object_position_valid(0.0, 5.0)
|
||||
|
||||
|
||||
class TestCornerRadar430CandidateFilter:
|
||||
@staticmethod
|
||||
def slot_word(distance_raw, meta13=0, b2=10, b3=2):
|
||||
return distance_raw | (meta13 << 13) | (b2 << 16) | (b3 << 24)
|
||||
|
||||
@classmethod
|
||||
def message(cls, slots):
|
||||
words = [0x010d1f40] * 7
|
||||
for slot, word in slots.items():
|
||||
words[slot - 1] = word
|
||||
|
||||
dat = bytearray(32)
|
||||
for idx, word in enumerate(words):
|
||||
dat[4 + idx * 4:8 + idx * 4] = int(word).to_bytes(4, "little")
|
||||
return bytes(dat)
|
||||
|
||||
@staticmethod
|
||||
def build_interface(monkeypatch):
|
||||
class FakeParams:
|
||||
def get_int(self, key):
|
||||
return 1 if key == "EnableCornerRadar" else 0
|
||||
|
||||
monkeypatch.setattr(radar_interface_module, "Params", FakeParams)
|
||||
monkeypatch.setattr(hyundaicanfd, "Params", FakeParams)
|
||||
cp = structs.CarParams()
|
||||
cp.carFingerprint = next(car for car, dbc in radar_interface_module.DBC.items() if "hyundai_canfd" in dbc[Bus.pt])
|
||||
cp.flags = HyundaiFlags.CANFD.value
|
||||
cp.extFlags = HyundaiExtFlags.CORNER_RADAR_OBJECTS_430.value
|
||||
cp.radarUnavailable = True
|
||||
cp.safetyConfigs = [structs.CarParams.SafetyConfig()]
|
||||
return RadarInterface(cp)
|
||||
|
||||
@staticmethod
|
||||
def update_frames(radar_interface, packets, frames=5):
|
||||
radar_data = None
|
||||
for _ in range(frames):
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
return radar_data
|
||||
|
||||
def test_430_promotes_supported_neighbor_bins(self, monkeypatch):
|
||||
radar_interface = self.build_interface(monkeypatch)
|
||||
empty = self.message({})
|
||||
supported_bins = self.message({
|
||||
6: self.slot_word(1000),
|
||||
7: self.slot_word(1004),
|
||||
})
|
||||
packets = [(addr, supported_bins if addr == 0x436 else empty, 1) for addr in range(0x430, 0x438)]
|
||||
packets += [(addr, empty, 1) for addr in range(0x440, 0x448)]
|
||||
|
||||
radar_data = self.update_frames(radar_interface, packets)
|
||||
points = {point.trackId: point for point in radar_data.points}
|
||||
|
||||
assert points[300].measured
|
||||
assert points[300].dRel == pytest.approx(50.1)
|
||||
assert points[300].yRel == pytest.approx(2.0)
|
||||
assert points[300].yvRel == 0.0
|
||||
|
||||
def test_430_expires_noncenter_inward_yvrel(self, monkeypatch):
|
||||
radar_interface = self.build_interface(monkeypatch)
|
||||
empty = self.message({})
|
||||
frame_defs = (
|
||||
(0x431, 4, 5),
|
||||
(0x433, 3, 4),
|
||||
(0x435, 2, 3),
|
||||
(0x430, 5, 6),
|
||||
(0x432, 4, 5),
|
||||
(0x434, 3, 4),
|
||||
(0x436, 2, 3),
|
||||
)
|
||||
|
||||
radar_data = None
|
||||
for addr, first_slot, second_slot in frame_defs:
|
||||
msg = self.message({
|
||||
first_slot: self.slot_word(1000),
|
||||
second_slot: self.slot_word(1004),
|
||||
})
|
||||
packets = [(a, msg if a == addr else empty, 1) for a in range(0x430, 0x438)]
|
||||
packets += [(a, empty, 1) for a in range(0x440, 0x448)]
|
||||
radar_data = radar_interface.update([0, packets])
|
||||
radar_data = self.update_frames(radar_interface, packets, frames=3)
|
||||
points = {point.trackId: point for point in radar_data.points}
|
||||
|
||||
assert points[300].measured
|
||||
assert points[300].yRel == pytest.approx(2.0)
|
||||
assert points[300].yvRel == 0.0
|
||||
@@ -1,21 +1,37 @@
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from enum import IntFlag
|
||||
from enum import Enum, IntFlag
|
||||
|
||||
from iqdbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, uds
|
||||
from iqdbc.car.lateral import AngleSteeringLimits
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.docs_definitions import CarHarness, CarDocs, CarParts, SupportType
|
||||
from iqdbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
|
||||
from iqdbc.car.fw_query_definitions import FwQueryConfig, Request, p16
|
||||
|
||||
from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
|
||||
class CarControllerParams:
|
||||
ACCEL_MIN = -3.5 # m/s
|
||||
ACCEL_MAX = 2.0 # m/s
|
||||
ACCEL_MIN = -4.0 # m/s
|
||||
ACCEL_MAX = 2.5 # m/s
|
||||
ANGLE_LIMITS: AngleSteeringLimits = AngleSteeringLimits(
|
||||
# LKAS angle command is unlimited, but LFA is limited to 176.7 deg (but does not fault if requesting above)
|
||||
175, # deg
|
||||
# stock comma's
|
||||
#([0, 9, 16, 25], [1.4, 0.6, 0.4, 0.1]),
|
||||
#([0, 9, 16, 25], [1.4, 0.7, 0.5, 0.1]),
|
||||
([0, 9, 16, 25], [1.8, 1.6, 1.3, 0.8]),
|
||||
([0, 9, 16, 25], [2.4, 2.0, 1.6, 1.0]),
|
||||
#([0, 9, 16, 25], [1.6, 1.0, 0.6, 0.15]),
|
||||
#([0, 9, 16, 25], [2.0, 1.2, 0.8, 0.28]),
|
||||
)
|
||||
# Stock LFA system is seen sending 250 max, but for LKAS events it's 175 max.
|
||||
# 250 can at least achieve 4 m/s^2, 80 corresponds to ~2.5 m/s^2
|
||||
ANGLE_MAX_TORQUE = 200 # The maximum amount of torque that will be allowed
|
||||
ANGLE_MIN_TORQUE = 25 # equivalent to ~0.8 m/s^2 of torque (based on ANGLE_MAX_TORQUE) when overriding
|
||||
ANGLE_TORQUE_UP_RATE = 8 #2 # Indicates how fast the torque ramps up after user intervention.
|
||||
ANGLE_TORQUE_DOWN_RATE = 12 #4 Indicates how fast the torque ramps down during user intervention (handing off).
|
||||
|
||||
def __init__(self, CP):
|
||||
self.STEER_DELTA_UP = 3
|
||||
@@ -41,20 +57,17 @@ class CarControllerParams:
|
||||
CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.KIA_SORENTO):
|
||||
self.STEER_MAX = 255
|
||||
|
||||
elif CP.carFingerprint in (CAR.HYUNDAI_SANTA_FE_PHEV_2022):
|
||||
self.STEER_MAX = 409
|
||||
# these cars have significantly more torque than most HKG; limit to 70% of max
|
||||
elif CP.flags & HyundaiFlags.ALT_LIMITS:
|
||||
self.STEER_MAX = 270
|
||||
self.STEER_DELTA_UP = 2
|
||||
self.STEER_DELTA_DOWN = 3
|
||||
|
||||
elif CP.flags & HyundaiFlags.ALT_LIMITS_2:
|
||||
self.STEER_MAX = 170
|
||||
self.STEER_MAX = 384
|
||||
self.STEER_DELTA_UP = 2
|
||||
self.STEER_DELTA_DOWN = 3
|
||||
|
||||
# Default for most HKG
|
||||
else:
|
||||
self.STEER_MAX = 384
|
||||
self.STEER_MAX = 409
|
||||
|
||||
|
||||
class HyundaiSafetyFlags(IntFlag):
|
||||
@@ -94,12 +107,7 @@ class HyundaiFlagsIQ(IntFlag):
|
||||
|
||||
class HyundaiFlags(IntFlag):
|
||||
# Dynamic Flags
|
||||
|
||||
# Default assumption: all cars use LFA (ADAS) steering from the camera.
|
||||
# CANFD_LKA_STEERING/CANFD_LKA_STEERING_ALT cars typically have both LKA (camera) and LFA (ADAS) steering messages,
|
||||
# with LKA commands forwarded to the ADAS DRV ECU.
|
||||
# Most HDA2 trims are assumed to be equipped with the ADAS DRV ECU, though some variants may not be equipped with one.
|
||||
CANFD_LKA_STEERING = 1
|
||||
CANFD_HDA2 = 1
|
||||
CANFD_ALT_BUTTONS = 2
|
||||
CANFD_ALT_GEARS = 2 ** 2
|
||||
CANFD_CAMERA_SCC = 2 ** 3
|
||||
@@ -109,7 +117,7 @@ class HyundaiFlags(IntFlag):
|
||||
CANFD_ALT_GEARS_2 = 2 ** 6
|
||||
SEND_LFA = 2 ** 7
|
||||
USE_FCA = 2 ** 8
|
||||
CANFD_LKA_STEERING_ALT = 2 ** 9
|
||||
CANFD_HDA2_ALT_STEERING = 2 ** 9
|
||||
|
||||
# these cars use a different gas signal
|
||||
HYBRID = 2 ** 10
|
||||
@@ -125,7 +133,7 @@ class HyundaiFlags(IntFlag):
|
||||
# The radar does SCC on these cars when HDA I, rather than the camera
|
||||
RADAR_SCC = 2 ** 14
|
||||
# The camera does SCC on these cars, rather than the radar
|
||||
CAMERA_SCC = 2 ** 15
|
||||
CAMERA_SCC = CANFD_CAMERA_SCC #2 ** 15
|
||||
CHECKSUM_CRC8 = 2 ** 16
|
||||
CHECKSUM_6B = 2 ** 17
|
||||
|
||||
@@ -144,23 +152,41 @@ class HyundaiFlags(IntFlag):
|
||||
|
||||
MIN_STEER_32_MPH = 2 ** 23
|
||||
|
||||
HAS_LDA_BUTTON = 2 ** 24
|
||||
ANGLE_CONTROL = 2 ** 24
|
||||
|
||||
FCEV = 2 ** 25
|
||||
|
||||
ALT_LIMITS_2 = 2 ** 26
|
||||
|
||||
CC_ONLY_CAR = 2 ** 31
|
||||
|
||||
class HyundaiExtFlags(IntFlag):
|
||||
NAVI_CLUSTER = 2 ** 2
|
||||
HAS_LFAHDA = 2 ** 4
|
||||
CANFD_GEARS_NONE = 2 ** 6
|
||||
RADAR_GROUP1 = 2 ** 7 # 0x210 radar group 1, 0x3A5 radar group 2
|
||||
CANFD_GEARS_69 = 2 ** 10
|
||||
RADAR_GROUP3 = 2 ** 11 # 0x400-0x41D radar object group
|
||||
CORNER_RADAR_OBJECTS_235 = 2 ** 12 # 0x230 status + 0x235-0x248 raw corner radar objects
|
||||
CORNER_RADAR_OBJECTS_180 = 2 ** 13 # 0x180-0x184 bus 1 two-slot raw corner/front radar objects
|
||||
CORNER_RADAR_OBJECTS_430 = 2 ** 14 # 0x430-0x437 left + 0x440-0x447 right IONIQ 9 corner radar bins
|
||||
RADAR_GROUP4 = 2 ** 15 # 0x500-0x507 Denso DNMWR006 stable radar tracks
|
||||
EV_MODE_STATUS_230 = 2 ** 16 # ECAN 0x230/DLC32 exposes the hybrid power-flow mode used for the EV indicator
|
||||
|
||||
class Footnote(Enum):
|
||||
CANFD = CarFootnote(
|
||||
"Requires a <a href=\"https://comma.ai/shop/can-fd-panda-kit\" target=\"_blank\">CAN FD panda kit</a> if not using " +
|
||||
"comma 3X for this <a href=\"https://en.wikipedia.org/wiki/CAN_FD\" target=\"_blank\">CAN FD car</a>.",
|
||||
Column.MODEL)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiCarDocs(CarDocs):
|
||||
package: str = "Smart Cruise Control (SCC)"
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiNonSccCarDocs(CarDocs):
|
||||
package: str = "No Smart Cruise Control (Non-SCC)"
|
||||
support_type: SupportType = SupportType.COMMUNITY
|
||||
support_link: str = "community"
|
||||
def init_make(self, CP: CarParams):
|
||||
if CP.flags & HyundaiFlags.CANFD:
|
||||
self.footnotes.insert(0, Footnote.CANFD)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -175,20 +201,9 @@ class HyundaiPlatformConfig(PlatformConfig):
|
||||
self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiNonSccPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_kia_generic"})
|
||||
|
||||
def init(self):
|
||||
self.iq_flags |= HyundaiFlagsIQ.NON_SCC
|
||||
|
||||
if self.flags & HyundaiFlags.MIN_STEER_32_MPH:
|
||||
self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiCanFDPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated"})
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated", Bus.radar: 'hyundai_canfd_radar_generated'})
|
||||
|
||||
def init(self):
|
||||
self.flags |= HyundaiFlags.CANFD
|
||||
@@ -196,6 +211,10 @@ class HyundaiCanFDPlatformConfig(PlatformConfig):
|
||||
|
||||
class CAR(Platforms):
|
||||
# Hyundai
|
||||
HYUNDAI_AZERA_7TH_GEN = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Azera 2023-2024", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
|
||||
CarSpecs(mass=1700, wheelbase=2.895, steerRatio=16.5),
|
||||
)
|
||||
HYUNDAI_AZERA_6TH_GEN = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Azera 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
CarSpecs(mass=1600, wheelbase=2.885, steerRatio=14.5),
|
||||
@@ -282,9 +301,9 @@ class CAR(Platforms):
|
||||
flags=HyundaiFlags.CLUSTER_GEARS | HyundaiFlags.ALT_LIMITS,
|
||||
)
|
||||
HYUNDAI_KONA_2022 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Kona 2022-23", car_parts=CarParts.common([CarHarness.hyundai_o]))],
|
||||
[HyundaiCarDocs("Hyundai Kona 2022", car_parts=CarParts.common([CarHarness.hyundai_o]))],
|
||||
CarSpecs(mass=1491, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
|
||||
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.ALT_LIMITS_2,
|
||||
flags=HyundaiFlags.CAMERA_SCC,
|
||||
)
|
||||
HYUNDAI_KONA_EV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
@@ -307,6 +326,11 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=1425, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
|
||||
flags=HyundaiFlags.HYBRID | HyundaiFlags.ALT_LIMITS,
|
||||
)
|
||||
HYUNDAI_KONA_HEV_2ND_GEN = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Kona Hybrid 2024", car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
CarSpecs(mass=1590, wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
|
||||
flags=HyundaiFlags.HYBRID,
|
||||
)
|
||||
HYUNDAI_NEXO_1ST_GEN = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Nexo 2021", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
||||
CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.79, steerRatio=14.19), # https://www.hyundainews.com/assets/documents/original/42768-2021NEXOProductGuideSpecs.pdf
|
||||
@@ -322,17 +346,17 @@ class CAR(Platforms):
|
||||
[HyundaiCarDocs("Hyundai Santa Fe 2021-23", "All", video="https://youtu.be/VnHzSTygTS4",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
HYUNDAI_SANTA_FE.specs,
|
||||
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
)
|
||||
HYUNDAI_SANTA_FE_HEV_2022 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
HYUNDAI_SANTA_FE.specs,
|
||||
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
|
||||
)
|
||||
HYUNDAI_SANTA_FE_PHEV_2022 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Santa Fe Plug-in Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
HYUNDAI_SANTA_FE.specs,
|
||||
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
|
||||
)
|
||||
HYUNDAI_SONATA = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Sonata 2020-23", "All", video="https://www.youtube.com/watch?v=ix63r9kE3Fw",
|
||||
@@ -343,8 +367,14 @@ class CAR(Platforms):
|
||||
HYUNDAI_SONATA_LF = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarHarness.hyundai_e]))],
|
||||
CarSpecs(mass=1536, wheelbase=2.804, steerRatio=13.27 * 1.15), # 15% higher at the center seems reasonable
|
||||
|
||||
flags=HyundaiFlags.UNSUPPORTED_LONGITUDINAL | HyundaiFlags.TCU_GEARS,
|
||||
)
|
||||
HYUNDAI_SONATA_2024 = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Sonata 2024-25", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
|
||||
CarSpecs(mass=1556, wheelbase=2.84, steerRatio=12.81),
|
||||
flags=HyundaiFlags.CAMERA_SCC,
|
||||
)
|
||||
HYUNDAI_STARIA_4TH_GEN = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Staria 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
CarSpecs(mass=2205, wheelbase=3.273, steerRatio=11.94), # https://www.hyundai.com/content/dam/hyundai/au/en/models/staria-load/premium-pip-update-2023/spec-sheet/STARIA_Load_Spec-Table_March_2023_v3.1.pdf
|
||||
@@ -384,11 +414,32 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=1948, wheelbase=2.97, steerRatio=14.26, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
HYUNDAI_IONIQ_5_PE = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Hyundai IONIQ 5 PE (NE1)", car_parts=CarParts.common([CarHarness.hyundai_q])),
|
||||
HyundaiCarDocs("Hyundai Ioniq 5 PE (with HDA II) 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
|
||||
],
|
||||
#CarSpecs(mass=2012, wheelbase=3.0, steerRatio=14.26, tireStiffnessFactor=0.65),
|
||||
CarSpecs(mass=2012, wheelbase=3.0, steerRatio=14.26, tireStiffnessFactor=1.0),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
|
||||
)
|
||||
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_m]))],
|
||||
CarSpecs(mass=2200, wheelbase=3.00, steerRatio=12.54),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
|
||||
HYUNDAI_IONIQ_5.specs,
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
|
||||
)
|
||||
HYUNDAI_IONIQ_9 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Hyundai Ioniq 9", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
|
||||
],
|
||||
CarSpecs(mass=2505, wheelbase=3.13, steerRatio=16.02),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
|
||||
)
|
||||
HYUNDAI_TUCSON_4TH_GEN = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||
@@ -408,6 +459,36 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=1690, wheelbase=3.055, steerRatio=17), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
)
|
||||
HYUNDAI_CASPER = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Casper 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
CarSpecs(mass=1060, wheelbase=2.4, steerRatio=14.3), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
|
||||
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.CHECKSUM_CRC8,
|
||||
)
|
||||
|
||||
HYUNDAI_CASPER_EV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Casper EV 2024", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
CarSpecs(mass=1355, wheelbase=2.58, steerRatio=14.3), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
|
||||
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.EV
|
||||
)
|
||||
HYUNDAI_PORTER_II_EV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Porter II EV 2024", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
||||
CarSpecs(mass=1970, wheelbase=2.64, steerRatio=14.5),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.CC_ONLY_CAR,
|
||||
)
|
||||
HYUNDAI_SANTAFE_MX5 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Hyundai SANTAFE (MX5)", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||
],
|
||||
CarSpecs(mass=1910, wheelbase=2.76, steerRatio=15.8, tireStiffnessFactor=0.82),
|
||||
flags=HyundaiFlags.ANGLE_CONTROL,
|
||||
)
|
||||
HYUNDAI_SANTAFE_MX5_HEV = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Hyundai SANTAFE HYBRID (MX5)", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||
],
|
||||
HYUNDAI_SANTAFE_MX5.specs,
|
||||
flags=HyundaiFlags.ANGLE_CONTROL,
|
||||
)
|
||||
|
||||
# Kia
|
||||
KIA_FORTE = HyundaiPlatformConfig(
|
||||
@@ -427,6 +508,18 @@ class CAR(Platforms):
|
||||
KIA_K5_2021.specs,
|
||||
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
|
||||
)
|
||||
KIA_K5_DL3_24 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia K5 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||
],
|
||||
CarSpecs(mass=1553, wheelbase=2.85, steerRatio=13.27, tireStiffnessFactor=0.5),
|
||||
)
|
||||
KIA_K5_DL3_24_HEV = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia K5 Hybrid 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||
],
|
||||
CarSpecs(mass=1553, wheelbase=2.85, steerRatio=13.27, tireStiffnessFactor=0.5),
|
||||
)
|
||||
KIA_K8_HEV_1ST_GEN = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K8 Hybrid (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q]))],
|
||||
# mass: https://carprices.ae/brands/kia/2023/k8/1.6-turbo-hybrid, steerRatio: guesstimate from K5 platform
|
||||
@@ -443,16 +536,13 @@ class CAR(Platforms):
|
||||
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.EV,
|
||||
)
|
||||
KIA_NIRO_EV_2ND_GEN = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia Niro EV (without HDA II) 2023-25", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||
HyundaiCarDocs("Kia Niro EV (with HDA II) 2025", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_r])),
|
||||
],
|
||||
[HyundaiCarDocs("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
|
||||
KIA_NIRO_EV.specs,
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
KIA_NIRO_PHEV = HyundaiPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia Niro Hybrid 2018", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||
HyundaiCarDocs("Kia Niro Hybrid 2018", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||
HyundaiCarDocs("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||
HyundaiCarDocs("Kia Niro Plug-in Hybrid 2020", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||
],
|
||||
@@ -493,7 +583,7 @@ class CAR(Platforms):
|
||||
# TODO: may support adjacent years. may have a non-zero minimum steering speed
|
||||
KIA_OPTIMA_H = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Optima Hybrid 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=3558 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
CarSpecs(mass=3758 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_OPTIMA_H_G4_FL = HyundaiPlatformConfig(
|
||||
@@ -521,6 +611,7 @@ class CAR(Platforms):
|
||||
HyundaiCarDocs("Kia Sorento 2019", video="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||
],
|
||||
CarSpecs(mass=1985, wheelbase=2.78, steerRatio=14.4 * 1.1), # 10% higher at the center seems reasonable
|
||||
dbc_dict={Bus.pt: "hyundai_kia_generic", Bus.radar: "hyundai_kia_denso_front_radar_generated"},
|
||||
flags=HyundaiFlags.CHECKSUM_6B | HyundaiFlags.UNSUPPORTED_LONGITUDINAL,
|
||||
)
|
||||
KIA_SORENTO_4TH_GEN = HyundaiCanFDPlatformConfig(
|
||||
@@ -550,6 +641,11 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=1450, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_EV4 = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Kia EV4 2025", "All", car_parts=CarParts.common([CarHarness.hyundai_q]))],
|
||||
CarSpecs(mass=1710, wheelbase=2.83, steerRatio=14.5, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
KIA_EV6 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
|
||||
@@ -559,6 +655,14 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
KIA_EV6_PE = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia EV6 PE (CV1)", car_parts=CarParts.common([CarHarness.hyundai_p])),
|
||||
HyundaiCarDocs("Kia EV6 PE (with HDA II) 2025", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
|
||||
],
|
||||
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
|
||||
)
|
||||
KIA_CARNIVAL_4TH_GEN = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia Carnival 2022-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||
@@ -627,54 +731,116 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=2258, wheelbase=2.95, steerRatio=14.14),
|
||||
flags=HyundaiFlags.RADAR_SCC,
|
||||
)
|
||||
|
||||
# port extensions
|
||||
HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Bayon Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_n]))],
|
||||
CarSpecs(mass=1150, wheelbase=2.58, steerRatio=13.27 * 1.15),
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
GENESIS_GV70_EV_1ST_GEN = HyundaiCanFDPlatformConfig(
|
||||
[HyundaiCarDocs("Genesis GV70 EV 2020-2023", "All", car_parts=CarParts.common([CarHarness.hyundai_m]))],
|
||||
CarSpecs(mass=2230, wheelbase=2.87, steerRatio=14.6),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.RADAR_SCC,
|
||||
)
|
||||
HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Elantra Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
HYUNDAI_ELANTRA_2021.specs,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
HYUNDAI_GRANDEUR_IG = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Grandeur 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1570, wheelbase=2.845, steerRatio=16., tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY | HyundaiFlags.CLUSTER_GEARS,
|
||||
)
|
||||
HYUNDAI_KONA_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Kona Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_b]))],
|
||||
HYUNDAI_KONA.specs,
|
||||
flags=HyundaiFlags.ALT_LIMITS,
|
||||
HYUNDAI_GRANDEUR_IG_HEV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Grandeur HEV 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1570, wheelbase=2.845, steerRatio=16., tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
|
||||
)
|
||||
HYUNDAI_KONA_EV_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Kona Electric Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
HYUNDAI_KONA_EV.specs,
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
|
||||
GENESIS_EQ900 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Genesis EQ900 2017", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=2200, wheelbase=3.15, steerRatio=16., tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))],
|
||||
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
GENESIS_EQ900_L = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Genesis EQ900 LIMOUSINE", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=2290, wheelbase=3.45, steerRatio=16., tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
GENESIS_G90_2019 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Genesis G90 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=2150, wheelbase=3.16, steerRatio=16., tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
HYUNDAI_NEXO = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Nexo", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
|
||||
CarSpecs(mass=1885, wheelbase=2.79, steerRatio=15.3, tireStiffnessFactor=0.385),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
KIA_MOHAVE = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Mohave 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
CarSpecs(mass=2285, wheelbase=2.895, steerRatio=16., tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_K5 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K5 2019 & 2016", "All", car_parts=CarParts.common([CarHarness.hyundai_b]))],
|
||||
CarSpecs(mass=1515, wheelbase=2.80, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY | HyundaiFlags.TCU_GEARS,
|
||||
)
|
||||
KIA_K5_HEV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K5 Hybrid 2017", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1705, wheelbase=2.80, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_K5_HEV_2022 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K5 Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1515, wheelbase=2.85, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_K7 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K7 2016-2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1850, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY | HyundaiFlags.CLUSTER_GEARS,
|
||||
)
|
||||
KIA_K7_HEV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K7 Hybrid 2016-2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1515, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_K7_PE = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K7 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1850, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
)
|
||||
KIA_K7_HEV_PE = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K7 Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1515, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.HYBRID,
|
||||
)
|
||||
KIA_FORTE_2019_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Forte Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
KIA_FORTE.specs,
|
||||
iq_flags=HyundaiFlagsIQ.NON_SCC_NO_FCA,
|
||||
KIA_K9 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia K9 2016-2019", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
||||
CarSpecs(mass=2075, wheelbase=3.15, steerRatio=14.5, tireStiffnessFactor=0.7),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_FORTE_2021_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Forte Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
KIA_FORTE.specs,
|
||||
KIA_EV_SK3 = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Soul EV 2019", car_parts=CarParts.common([CarHarness.hyundai_c]))],
|
||||
CarSpecs(mass=1695, wheelbase=2.6, steerRatio=13.75),
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.EV,
|
||||
)
|
||||
KIA_SELTOS_2023_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Seltos Non-SCC 2023-24", car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
KIA_SELTOS.specs,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
KIA_EV9 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia EV9 (MV)", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||
],
|
||||
CarSpecs(mass=2625, wheelbase=3.1, steerRatio=16.02),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
|
||||
)
|
||||
GENESIS_G70_2021_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Genesis G70 Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_f]))],
|
||||
GENESIS_G70_2020.specs,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
iq_flags=HyundaiFlagsIQ.NON_SCC_RADAR_FCA,
|
||||
KIA_EV3 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia EV3 (SV1)", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||
],
|
||||
CarSpecs(mass=2055, wheelbase=2.90, steerRatio=16.0, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
KIA_PV5 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia PV5 (SW1)", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||
],
|
||||
CarSpecs(mass=2600, wheelbase=2.995, steerRatio=16.0, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV,
|
||||
)
|
||||
KIA_RAY_EV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Ray EV", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
||||
CarSpecs(mass=1295, wheelbase=2.520, steerRatio=14.5),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.CC_ONLY_CAR | HyundaiFlags.CHECKSUM_CRC8,
|
||||
)
|
||||
|
||||
|
||||
class Buttons:
|
||||
NONE = 0
|
||||
@@ -682,6 +848,7 @@ class Buttons:
|
||||
SET_DECEL = 2
|
||||
GAP_DIST = 3
|
||||
CANCEL = 4 # on newer models, this is a pause/resume button
|
||||
LFA_BUTTON = 5
|
||||
|
||||
|
||||
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
|
||||
@@ -862,11 +1029,21 @@ CAN_GEARS = {
|
||||
# which message has the gear. hybrid and EV use ELECT_GEAR
|
||||
"use_cluster_gears": CAR.with_flags(HyundaiFlags.CLUSTER_GEARS),
|
||||
"use_tcu_gears": CAR.with_flags(HyundaiFlags.TCU_GEARS),
|
||||
"send_mdps12": {CAR.GENESIS_G90, CAR.GENESIS_G90_2019, CAR.KIA_K9, CAR.KIA_K7},
|
||||
}
|
||||
|
||||
CANFD_CAR = CAR.with_flags(HyundaiFlags.CANFD)
|
||||
CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
|
||||
|
||||
CANFD_HYBRID_STATUS_ADDR = 0xFA
|
||||
CANFD_HYBRID_STATUS_DLC = 32
|
||||
|
||||
EV_MODE_STATUS_ADDR = 0x230
|
||||
EV_MODE_STATUS_DLC = 32
|
||||
EV_MODE_STATUS_MSG = "HCU_STATUS_230"
|
||||
EV_MODE_STATUS_SIGNAL = "HYBRID_POWER_FLOW_MODE"
|
||||
EV_MODE_ACTIVE_VALUES = frozenset((1, 2, 6))
|
||||
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
|
||||
|
||||
CAMERA_SCC_CAR = CAR.with_flags(HyundaiFlags.CAMERA_SCC)
|
||||
@@ -881,7 +1058,13 @@ LEGACY_SAFETY_MODE_CAR = CAR.with_flags(HyundaiFlags.LEGACY)
|
||||
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
|
||||
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
|
||||
|
||||
# port extensions
|
||||
NON_SCC_CAR = CAR.with_iq_flags(HyundaiFlagsIQ.NON_SCC)
|
||||
|
||||
DBC = CAR.create_dbc_map()
|
||||
|
||||
if __name__ == "__main__":
|
||||
cars = []
|
||||
for platform in CAR:
|
||||
for doc in platform.config.car_docs:
|
||||
cars.append(doc.name)
|
||||
cars.sort()
|
||||
for c in cars:
|
||||
print(c)
|
||||
|
||||
@@ -253,9 +253,6 @@ class CarInterfaceBase(ABC, CarInterfaceBaseIQ):
|
||||
ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA
|
||||
ret.openpilotLongitudinalControl = False
|
||||
ret.stopAccel = -2.0
|
||||
ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop
|
||||
ret.vEgoStopping = 0.5
|
||||
ret.vEgoStarting = 0.5
|
||||
ret.longitudinalTuning.kpBP = [0.]
|
||||
ret.longitudinalTuning.kpV = [0.]
|
||||
ret.longitudinalTuning.kiBP = [0.]
|
||||
@@ -335,6 +332,12 @@ class CarStateBase(ABC):
|
||||
x0=[[0.0], [0.0]]
|
||||
K = get_kalman_gain(DT_CTRL, np.array(A), np.array(C), np.array(Q), R)
|
||||
self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
|
||||
self.v_ego_clu_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
|
||||
|
||||
self.softHoldActive = 0
|
||||
self.is_metric = True
|
||||
self.lkas_enabled = False
|
||||
self.modelV2 = None
|
||||
|
||||
@abstractmethod
|
||||
def update(self, can_parsers) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
@@ -351,6 +354,22 @@ class CarStateBase(ABC):
|
||||
v_ego_x = self.v_ego_kf.update(v_ego_raw)
|
||||
return float(v_ego_x[0]), float(v_ego_x[1])
|
||||
|
||||
def update_clu_speed_kf(self, v_ego_raw):
|
||||
if abs(v_ego_raw - self.v_ego_clu_kf.x[0][0]) > 2.0:
|
||||
self.v_ego_clu_kf.set_x([[v_ego_raw], [0.0]])
|
||||
|
||||
v_ego_x = self.v_ego_clu_kf.update(v_ego_raw)
|
||||
return float(v_ego_x[0]), float(v_ego_x[1])
|
||||
|
||||
def get_wheel_speeds(self, fl, fr, rl, rr, unit=CV.KPH_TO_MS):
|
||||
factor = unit * self.CP.wheelSpeedFactor
|
||||
wheel_speeds = structs.CarState.WheelSpeeds()
|
||||
wheel_speeds.fl = fl * factor
|
||||
wheel_speeds.fr = fr * factor
|
||||
wheel_speeds.rl = rl * factor
|
||||
wheel_speeds.rr = rr * factor
|
||||
return wheel_speeds
|
||||
|
||||
def update_blinker_from_lamp(self, blinker_time: int, left_blinker_lamp: bool, right_blinker_lamp: bool):
|
||||
"""Update blinkers from lights. Enable output when light was seen within the last `blinker_time`
|
||||
iterations"""
|
||||
|
||||
@@ -6,7 +6,6 @@ from iqdbc.car.vehicle_model import VehicleModel
|
||||
|
||||
FRICTION_THRESHOLD = 0.2
|
||||
|
||||
# ISO 11270
|
||||
ISO_LATERAL_ACCEL = 3.0 # m/s^2
|
||||
ISO_LATERAL_JERK = 5.0 # m/s^3
|
||||
AVERAGE_ROAD_ROLL = 0.06 # ~3.4 degrees
|
||||
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
import capnp
|
||||
import urllib.parse
|
||||
import warnings
|
||||
from urllib.request import urlopen
|
||||
from urllib.request import urlopen, Request
|
||||
import zstandard as zstd
|
||||
|
||||
from iqdbc.car.common.basedir import BASEDIR
|
||||
@@ -27,7 +27,7 @@ class LogReader:
|
||||
_, ext = os.path.splitext(urllib.parse.urlparse(fn).path)
|
||||
|
||||
if fn.startswith("http"):
|
||||
with urlopen(fn) as f:
|
||||
with urlopen(Request(fn, headers={"User-Agent": "iqdbc"})) as f:
|
||||
dat = f.read()
|
||||
else:
|
||||
with open(fn, "rb") as f:
|
||||
|
||||
@@ -5,17 +5,18 @@ from iqdbc.car import Bus, create_button_events, structs
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.nissan.values import CAR, DBC, CarControllerParams
|
||||
from iqdbc.lvbs.car.nissan.carstate_ext import CarStateExt
|
||||
|
||||
from iqdbc.lvbs.car.nissan.iq_carstate import IQCarState
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
TORQUE_SAMPLES = 12
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
self.lkas_hud_msg = {}
|
||||
@@ -129,7 +130,7 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.lkas_hud_msg = copy.copy(cp_adas.vl["PROPILOT_HUD"])
|
||||
self.lkas_hud_info_msg = copy.copy(cp_adas.vl["PROPILOT_HUD_INFO_MSG"])
|
||||
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers)
|
||||
IQCarState.update(self, ret, ret_iq, can_parsers)
|
||||
|
||||
ret.buttonEvents = [
|
||||
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
|
||||
|
||||
@@ -4,15 +4,15 @@ from iqdbc.car import Bus, structs
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.rivian.values import DBC, GEAR_MAP
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.lvbs.car.rivian.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.rivian.iq_carstate import IQCarState
|
||||
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
self.last_speed = 30
|
||||
|
||||
self.acm_lka_hba_cmd = None
|
||||
@@ -95,7 +95,7 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.sccm_wheel_touch = copy.copy(cp.vl["SCCM_WheelTouch"])
|
||||
self.vdm_adas_status = copy.copy(cp.vl["VDM_AdasSts"])
|
||||
|
||||
CarStateExt.update(self, ret, can_parsers)
|
||||
IQCarState.update(self, ret, can_parsers)
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
@@ -105,5 +105,5 @@ class CarState(CarStateBase, CarStateExt):
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
|
||||
Bus.adas: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 1),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
|
||||
**CarStateExt.get_parser(CP, CP_IQ),
|
||||
**IQCarState.get_parser(CP, CP_IQ),
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.safetyConfigs[0].safetyParam |= RivianSafetyFlags.LONG_CONTROL.value
|
||||
|
||||
ret.longitudinalActuatorDelay = 0.35
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.stopAccel = 0
|
||||
|
||||
return ret
|
||||
@@ -40,6 +39,8 @@ class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams, candidate, fingerprint: dict[int, dict[int, int]],
|
||||
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
|
||||
# Longitudinal harness upgrade advertises msg 0x31a on bus 5; when present it
|
||||
# unlocks radar, blind-spot and openpilot longitudinal on Rivian.
|
||||
if 0x31a in fingerprint[5]:
|
||||
ret.flags |= RivianFlagsIQ.LONGITUDINAL_HARNESS_UPGRADE.value
|
||||
stock_cp.radarUnavailable = False
|
||||
|
||||
@@ -52,6 +52,7 @@ class IQCarParams:
|
||||
pcmCruiseSpeed: bool = auto_field()
|
||||
enableGasInterceptor: bool = auto_field()
|
||||
longitudinalStoppingSpeedOverride: float = auto_field()
|
||||
stoppingDecelRateOverride: float = auto_field()
|
||||
|
||||
iqLateralNet: 'IQCarParams.LateralNet' = field(default_factory=lambda: IQCarParams.LateralNet())
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# FIXME: gate by FingerPrint
|
||||
TESLA_BLINKERS = False
|
||||
|
||||
@@ -3,11 +3,13 @@ from iqdbc.can import CANPacker
|
||||
from iqdbc.car import Bus
|
||||
from iqdbc.car.lateral import apply_steer_angle_limits_vm
|
||||
from iqdbc.car.interfaces import CarControllerBase
|
||||
from iqdbc.car.tesla import TESLA_BLINKERS
|
||||
from iqdbc.car.tesla.teslacan import TeslaCAN
|
||||
from iqdbc.car.tesla.values import CarControllerParams
|
||||
from iqdbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.iqpilot.selfdrive.car.enhanced_stock_longitudinal_control import get_set_speed_kph_from_params
|
||||
from iqdbc.lvbs.car.tesla.torque_blend import TorqueBlendController
|
||||
from iqdbc.lvbs.car.tesla.values import TeslaFlagsIQ
|
||||
|
||||
|
||||
def get_safety_CP():
|
||||
@@ -28,6 +30,11 @@ class CarController(CarControllerBase):
|
||||
# Vehicle model used for lateral limiting
|
||||
self.VM = VehicleModel(get_safety_CP())
|
||||
|
||||
self.has_vehicle_bus = bool(CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS)
|
||||
self.body_controls_counter_last = -1
|
||||
self.blinker_request_prev = False
|
||||
self.blinker_cancel_frame = 0
|
||||
|
||||
def update(self, CC, CC_IQ, CS, now_nanos):
|
||||
actuators = CC.actuators
|
||||
can_sends = []
|
||||
@@ -52,6 +59,8 @@ class CarController(CarControllerBase):
|
||||
if self.frame % 4 == 0:
|
||||
state = 13 if CC.cruiseControl.cancel or CS.das_accCancel else 4 # 4=ACC_ON, 13=ACC_CANCEL_GENERIC_SILENT
|
||||
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
|
||||
if not CC.longActive:
|
||||
accel = 0.
|
||||
cntr = (self.frame // 4) % 8
|
||||
set_speed_kph = get_set_speed_kph_from_params(CC_IQ.params)
|
||||
can_sends.append(self.tesla_can.create_longitudinal_command(state, accel, cntr, CS.out.vEgo, CC.longActive,
|
||||
@@ -63,6 +72,30 @@ class CarController(CarControllerBase):
|
||||
cntr = (CS.das_control["DAS_controlCounter"] + 1) % 8
|
||||
can_sends.append(self.tesla_can.create_longitudinal_command(13, 0, cntr, CS.out.vEgo, False, True))
|
||||
|
||||
# Nav blinker control via DAS_bodyControls on the vehicle bus, phase-locked to the car's
|
||||
# counter. Cancel on the trailing edge since the body controller latches the signal.
|
||||
stock_dat = getattr(CS, 'das_body_controls_dat', b"")
|
||||
# FIXME: gate by FingerPrint
|
||||
if TESLA_BLINKERS and self.has_vehicle_bus and len(stock_dat) >= 8:
|
||||
left_blinker = CC.leftBlinker
|
||||
right_blinker = CC.rightBlinker
|
||||
|
||||
driver_opposes = (left_blinker and CS.out.rightBlinker) or (right_blinker and CS.out.leftBlinker)
|
||||
if driver_opposes:
|
||||
left_blinker = right_blinker = False
|
||||
|
||||
nav_requesting = left_blinker or right_blinker
|
||||
|
||||
if self.blinker_request_prev and not nav_requesting and not driver_opposes:
|
||||
self.blinker_cancel_frame = self.frame + 150 # ~1.5 s
|
||||
self.blinker_request_prev = nav_requesting
|
||||
cancel = not nav_requesting and not driver_opposes and self.frame < self.blinker_cancel_frame
|
||||
|
||||
body_counter = stock_dat[6] >> 4
|
||||
if body_counter != self.body_controls_counter_last:
|
||||
can_sends.append(self.tesla_can.create_body_controls(stock_dat, left_blinker, right_blinker, cancel))
|
||||
self.body_controls_counter_last = body_counter
|
||||
|
||||
# TODO: HUD control
|
||||
new_actuators = actuators.as_builder()
|
||||
new_actuators.steeringAngleDeg = self.apply_angle_last
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
import copy
|
||||
from iqdbc.can import CANDefine, CANParser
|
||||
from iqdbc.car import Bus, create_button_events, structs
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.tesla.teslacan import get_steer_ctrl_type
|
||||
from iqdbc.car.tesla import TESLA_BLINKERS
|
||||
from iqdbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, TeslaFlags
|
||||
|
||||
from iqdbc.lvbs.car.tesla.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.tesla.iq_carstate import IQCarState
|
||||
from iqdbc.lvbs.car.tesla.values import TeslaFlagsIQ
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
vehicle_state = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.vehicle_state")
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
self.can_define = CANDefine(DBC[CP.carFingerprint][Bus.party])
|
||||
self.shifter_values = self.can_define.dv["DI_systemStatus"]["DI_gear"]
|
||||
|
||||
self.summon = False
|
||||
self.summon_prev = False
|
||||
self.cruise_enabled_prev = False
|
||||
self.fsd14_error_logged = False
|
||||
self.suspected_fsd14 = False
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
|
||||
self.hands_on_level = 0
|
||||
self.acc_state_last = 0
|
||||
self.das_control = None
|
||||
self.das_body_controls_dat = b""
|
||||
self._odometer_store = vehicle_state.VehicleOdometerStore(CP, Params())
|
||||
self.cruise_override = False
|
||||
|
||||
def update_summon_state(self, summon_state: str, cruise_enabled: bool):
|
||||
@@ -136,54 +139,40 @@ class CarState(CarStateBase, CarStateExt):
|
||||
ret.stockAeb = cp_ap_party.vl["DAS_control"]["DAS_aebEvent"] == 1
|
||||
|
||||
# LKAS
|
||||
# On FSD 14+, ANGLE_CONTROL behavior changed to allow user winddown while actuating.
|
||||
# FSD switched from using ANGLE_CONTROL to LANE_KEEP_ASSIST to likely keep the old steering override disengage logic.
|
||||
# LKAS switched from LANE_KEEP_ASSIST to ANGLE_CONTROL to likely allow overriding LKAS events smoothly
|
||||
lkas_ctrl_type = get_steer_ctrl_type(self.CP.flags, 2)
|
||||
ret.stockLkas = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == lkas_ctrl_type # LANE_KEEP_ASSIST
|
||||
steer_control_type = int(cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"])
|
||||
if self.CP.flags & TeslaFlags.LEGACY_DAS_STEERING:
|
||||
steer_control_type >>= 1 # legacy firmware uses a 2-bit field, one bit up from the 3-bit signal
|
||||
ret.stockLkas = steer_control_type == 2 # LANE_KEEP_ASSIST
|
||||
|
||||
# Stock Autosteer should be disengaged (includes FSD)
|
||||
# TODO: find for TESLA_MODEL_X and HW2.5 vehicles
|
||||
if not (self.CP.flags & TeslaFlags.MISSING_DAS_SETTINGS):
|
||||
ret.invalidLkasSetting = cp_ap_party.vl["DAS_status"]["DAS_autopilotState"] not in (0, 1, 2) # DISABLED, UNAVAILABLE, AVAILABLE
|
||||
|
||||
# Because we don't have FSD 14 detection outside of a set of FW, we should check if this FW is accidentally missing from FSD_14_FW
|
||||
# 1. If in Autosteer or FSD, already caught by invalidLkasSetting
|
||||
# 2. If in TACC and DAS ever sends ANGLE_CONTROL (1), we can infer it's trying to do LKAS on FSD 14+
|
||||
# NOTE: Tesla's latest firmware changed ELDA (Emergency Lane Departure Assist) to use ANGLE_CONTROL (1)
|
||||
# instead of EMERGENCY_LANE_KEEP (3). Exclude ELDA by checking eac_status so it doesn't latch suspected_fsd14.
|
||||
eac_is_emergency = eac_status == "EMERGENCY_LANE_KEEP"
|
||||
angle_control = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == 1 and not eac_is_emergency # ANGLE_CONTROL, excluding ELDA
|
||||
if not ret.invalidLkasSetting and angle_control and not self.CP.flags & TeslaFlags.FSD_14:
|
||||
self.suspected_fsd14 = True
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
|
||||
if self.suspected_fsd14:
|
||||
ret.invalidLkasSetting = True
|
||||
if not self.fsd14_error_logged:
|
||||
carlog.error("FSD 14 detected, but FW not in FSD_14_FW set")
|
||||
self.fsd14_error_logged = True
|
||||
# Un-latch if ANGLE_CONTROL has been absent for ~3 s (100 frames @ ~33 Hz).
|
||||
# This allows re-engagement after transient triggers (e.g. if ELDA slips through on new FW variants).
|
||||
if not angle_control:
|
||||
self.suspected_fsd14_clear_frames += 1
|
||||
if self.suspected_fsd14_clear_frames >= 100:
|
||||
self.suspected_fsd14 = False
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
else:
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
|
||||
# Buttons # ToDo: add Gap adjust button
|
||||
|
||||
# Messages needed by carcontroller
|
||||
self.das_control = copy.copy(cp_ap_party.vl["DAS_control"])
|
||||
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers)
|
||||
# Raw stock DAS_bodyControls bytes (bus 2), used to ride the blinker on the vehicle bus.
|
||||
# FIXME: gate by FingerPrint
|
||||
if TESLA_BLINKERS and Bus.cam in can_parsers:
|
||||
self.das_body_controls_dat = bytes(can_parsers[Bus.cam].dat.get(0x3E9, b""))
|
||||
|
||||
IQCarState.update(self, ret, ret_iq, can_parsers)
|
||||
if ret.odometer > 0.0:
|
||||
ret.odometer = self._odometer_store.record(ret.odometer) or 0.0
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers(CP, CP_IQ):
|
||||
return {
|
||||
parsers = {
|
||||
Bus.party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.party),
|
||||
Bus.ap_party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.autopilot_party),
|
||||
**CarStateExt.get_parser(CP, CP_IQ),
|
||||
**IQCarState.get_parser(CP, CP_IQ),
|
||||
}
|
||||
# Stock DAS_bodyControls from the AP bus (bus 2) for the nav blinker.
|
||||
if TESLA_BLINKERS and CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS and Bus.adas in DBC[CP.carFingerprint]:
|
||||
parsers[Bus.cam] = CANParser(DBC[CP.carFingerprint][Bus.adas], [("DAS_bodyControls", 2)], CANBUS.autopilot_party)
|
||||
return parsers
|
||||
|
||||
@@ -2,7 +2,7 @@ from iqdbc.car import Bus, get_safety_config, structs
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
from iqdbc.car.tesla.carcontroller import CarController
|
||||
from iqdbc.car.tesla.carstate import CarState
|
||||
from iqdbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, FSD_14_FW, Ecu
|
||||
from iqdbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, LEGACY_DAS_STEERING_FW, Ecu
|
||||
from iqdbc.car.tesla.radar_interface import RadarInterface, RADAR_START_ADDR
|
||||
|
||||
from iqdbc.lvbs.car.tesla.values import TeslaFlagsIQ, TeslaSafetyFlagsIQ
|
||||
@@ -41,14 +41,10 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.openpilotLongitudinalControl = True
|
||||
ret.safetyConfigs[0].safetyParam |= TeslaSafetyFlags.LONG_CONTROL.value
|
||||
|
||||
ret.vEgoStopping = 0.1
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.stoppingDecelRate = 0.3
|
||||
|
||||
fsd_14 = any(fw.ecu == Ecu.eps and fw.fwVersion in FSD_14_FW.get(candidate, []) for fw in car_fw)
|
||||
if fsd_14:
|
||||
ret.flags |= TeslaFlags.FSD_14.value
|
||||
ret.safetyConfigs[0].safetyParam |= TeslaSafetyFlags.FSD_14.value
|
||||
legacy_das = any(fw.ecu == Ecu.eps and fw.fwVersion in LEGACY_DAS_STEERING_FW.get(candidate, []) for fw in car_fw)
|
||||
if legacy_das:
|
||||
ret.flags |= TeslaFlags.LEGACY_DAS_STEERING.value
|
||||
ret.safetyConfigs[0].safetyParam |= TeslaSafetyFlags.LEGACY_DAS_STEERING.value
|
||||
|
||||
ret.dashcamOnly = candidate in (CAR.TESLA_MODEL_X,) # dashcam only, pending find invalidLkasSetting signal
|
||||
|
||||
@@ -63,7 +59,10 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate == CAR.TESLA_MODEL_X:
|
||||
stock_cp.dashcamOnly = False
|
||||
|
||||
if 0x3DF in fingerprint[1]:
|
||||
# Vehicle-bus messages can be slow enough to miss the initial capture window.
|
||||
# Accept either the established 0x3DF marker or the absolute odometer frame.
|
||||
vehicle_bus_seen = any(0x3DF in bus or 0x3B6 in bus for bus in fingerprint.values())
|
||||
if vehicle_bus_seen:
|
||||
ret.flags |= TeslaFlagsIQ.HAS_VEHICLE_BUS.value
|
||||
ret.iqSafetyFlags |= TeslaSafetyFlagsIQ.HAS_VEHICLE_BUS
|
||||
|
||||
|
||||
@@ -3,14 +3,6 @@ from iqdbc.car.tesla.values import CANBUS, CarControllerParams, TeslaFlags
|
||||
from iqdbc.car import DT_CTRL
|
||||
|
||||
|
||||
def get_steer_ctrl_type(flags: int, ctrl_type: int) -> int:
|
||||
# Returns the flipped signal value for DAS_steeringControlType on FSD 14
|
||||
if flags & TeslaFlags.FSD_14:
|
||||
return {1: 2, 2: 1}.get(ctrl_type, ctrl_type)
|
||||
else:
|
||||
return ctrl_type
|
||||
|
||||
|
||||
class TeslaCAN:
|
||||
def __init__(self, CP, packer):
|
||||
self.CP = CP
|
||||
@@ -18,14 +10,15 @@ class TeslaCAN:
|
||||
self.l_jerk = 0.0
|
||||
|
||||
def create_steering_control(self, angle, enabled, control_type):
|
||||
# On FSD 14+, ANGLE_CONTROL behavior changed to allow user winddown while actuating.
|
||||
# with openpilot, after overriding w/ ANGLE_CONTROL the wheel snaps back to the original angle abruptly
|
||||
# so we now use LANE_KEEP_ASSIST to match stock FSD.
|
||||
# see carstate.py for more details
|
||||
# control_type comes from torque_blend: ANGLE_CONTROL (1) normally, LANE_KEEP_ASSIST (2) when cooperative steering is enabled
|
||||
control_type = control_type if enabled else 0
|
||||
if self.CP.flags & TeslaFlags.LEGACY_DAS_STEERING:
|
||||
control_type <<= 1 # legacy firmware uses a 2-bit field, one bit up from the 3-bit signal
|
||||
|
||||
values = {
|
||||
"DAS_steeringAngleRequest": -angle,
|
||||
"DAS_steeringHapticRequest": 0,
|
||||
"DAS_steeringControlType": get_steer_ctrl_type(self.CP.flags, control_type if enabled else 0),
|
||||
"DAS_steeringControlType": control_type,
|
||||
}
|
||||
|
||||
return self.packer.make_can_msg("DAS_steeringControl", CANBUS.party, values)
|
||||
@@ -60,6 +53,32 @@ class TeslaCAN:
|
||||
|
||||
return self.packer.make_can_msg("APS_eacMonitor", CANBUS.party, values)
|
||||
|
||||
def create_body_controls(self, stock_dat, left_blinker, right_blinker, cancel=False):
|
||||
# Ride alongside the car's native DAS_bodyControls: copy the raw frame, override only the
|
||||
# turn-indicator bits, and stamp counter + 1 so our frame supersedes the stock one.
|
||||
dat = bytearray(stock_dat)
|
||||
if len(dat) < 8:
|
||||
dat.extend(b"\x00" * (8 - len(dat)))
|
||||
|
||||
if left_blinker or right_blinker:
|
||||
turn_req = 1 if left_blinker else 2 # DAS_TURN_INDICATOR_LEFT / _RIGHT
|
||||
dat[1] = (dat[1] & ~0x07) | (turn_req & 0x07)
|
||||
dat[2] = (dat[2] & ~0x3C) | (1 << 2) # DAS_ACTIVE_NAV_LANE_CHANGE
|
||||
elif cancel:
|
||||
dat[1] = (dat[1] & ~0x07) | 0x03 # DAS_TURN_INDICATOR_CANCEL
|
||||
dat[2] = (dat[2] & ~0x3C) | (4 << 2) # DAS_CANCEL_LANE_CHANGE
|
||||
|
||||
counter = (((dat[6] >> 4) + 1) & 0x0F)
|
||||
dat[6] = (dat[6] & ~0xF0) | (counter << 4)
|
||||
|
||||
addr = 0x3E9
|
||||
checksum = (addr & 0xFF) + ((addr >> 8) & 0xFF)
|
||||
for i in range(7):
|
||||
checksum += dat[i]
|
||||
dat[7] = checksum & 0xFF
|
||||
|
||||
return addr, bytes(dat), CANBUS.vehicle
|
||||
|
||||
|
||||
def tesla_checksum(address: int, sig, d: bytearray) -> int:
|
||||
checksum = (address & 0xFF) + ((address >> 8) & 0xFF)
|
||||
|
||||
@@ -4,6 +4,7 @@ from iqdbc.car.tesla.teslacan import TeslaCAN
|
||||
from iqdbc.car.tesla.radar_interface import RADAR_START_ADDR
|
||||
from iqdbc.car.tesla.carcontroller import CarController
|
||||
from iqdbc.car.tesla.values import CAR
|
||||
from iqdbc.can import CANPacker, CANParser
|
||||
|
||||
|
||||
class TestTeslaFingerprint:
|
||||
@@ -31,6 +32,19 @@ class TestTeslaCan:
|
||||
def make_can_msg(self, name, bus, values):
|
||||
return name, bus, values
|
||||
|
||||
def test_vehicle_bus_odometer_decodes_kilometers(self):
|
||||
packer = CANPacker("tesla_model3_vehicle")
|
||||
parser = CANParser("tesla_model3_vehicle", [("ID3B6UI_odometer", 1)], 1)
|
||||
|
||||
message = packer.make_can_msg("ID3B6UI_odometer", 1, {
|
||||
"UI_odometer": 29150.377,
|
||||
"UI_odometerCounter": 1,
|
||||
"UI_odometerChecksum": 0,
|
||||
})
|
||||
parser.update([1_000_000_000, [message]])
|
||||
|
||||
assert parser.vl["ID3B6UI_odometer"]["UI_odometer"] == 29150.377
|
||||
|
||||
def test_longitudinal_command_does_not_reference_missing_jerk_attr(self):
|
||||
CP = CarInterface.get_non_essential_params(CAR.TESLA_MODEL_3)
|
||||
tesla_can = TeslaCAN(CP, self.DummyPacker())
|
||||
|
||||
@@ -79,16 +79,41 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
]
|
||||
)
|
||||
|
||||
# Cars with this EPS FW have FSD 14 and use TeslaFlags.FSD_14
|
||||
FSD_14_FW = {
|
||||
# Cars with this EPS FW have a 2-bit DAS_steeringControlType and use TeslaFlags.LEGACY_DAS_STEERING
|
||||
LEGACY_DAS_STEERING_FW = {
|
||||
CAR.TESLA_MODEL_3: [
|
||||
b'TeMYG4_Main_0.0.0 (77),E4HP015.04.5',
|
||||
b'TeMYG4_Main_0.0.0 (78),E4HP015.05.0',
|
||||
b'TeM3_E014p10_0.0.0 (16),E014.17.00',
|
||||
b'TeM3_E014p10_0.0.0 (16),EL014.17.00',
|
||||
b'TeM3_ES014p11_0.0.0 (25),ES014.19.0',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (13),E4014.28.1',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (9),E4014.26.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (2),E4015.02.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),E4015.03.2',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),E4L015.03.2',
|
||||
b'TeMYG4_Main_0.0.0 (59),E4H014.29.0',
|
||||
b'TeMYG4_Main_0.0.0 (65),E4H015.01.0',
|
||||
b'TeMYG4_Main_0.0.0 (67),E4H015.02.1',
|
||||
b'TeMYG4_SingleECU_0.0.0 (33),E4S014.27',
|
||||
],
|
||||
CAR.TESLA_MODEL_Y: [
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (6),Y4003.04.0',
|
||||
b'TeMYG4_Main_0.0.0 (77),Y4003.05.4',
|
||||
]
|
||||
b'TeM3_E014p10_0.0.0 (16),Y002.18.00',
|
||||
b'TeM3_E014p10_0.0.0 (16),YP002.18.00',
|
||||
b'TeM3_ES014p11_0.0.0 (16),YS002.17',
|
||||
b'TeM3_ES014p11_0.0.0 (25),YS002.19.0',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (13),Y4002.27.1',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (13),Y4P002.27.1',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (9),Y4P002.25.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4003.02.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4P003.02.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4003.03.2',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4P003.03.2',
|
||||
b'TeMYG4_SingleECU_0.0.0 (28),Y4S002.23.0',
|
||||
b'TeMYG4_SingleECU_0.0.0 (33),Y4S002.26',
|
||||
],
|
||||
CAR.TESLA_MODEL_X: [
|
||||
b'TeM3_SP_XP002p2_0.0.0 (23),XPR003.6.0',
|
||||
b'TeM3_SP_XP002p2_0.0.0 (36),XPR003.10.0',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -139,12 +164,12 @@ class CarControllerParams:
|
||||
|
||||
class TeslaSafetyFlags(IntFlag):
|
||||
LONG_CONTROL = 1
|
||||
FSD_14 = 2
|
||||
LEGACY_DAS_STEERING = 2
|
||||
|
||||
|
||||
class TeslaFlags(IntFlag):
|
||||
LONG_CONTROL = 1
|
||||
FSD_14 = 2
|
||||
LEGACY_DAS_STEERING = 2
|
||||
MISSING_DAS_SETTINGS = 4
|
||||
|
||||
|
||||
|
||||
@@ -301,7 +301,8 @@ routes = [
|
||||
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("b29ee8c5a0a735d1|000000dc--a384e9083e", VOLKSWAGEN.VOLKSWAGEN_PASSAT_NMS, segment=0),
|
||||
CarTestRoute("0f53129ed44f6920|00000287--3efbddeb96", VOLKSWAGEN.VOLKSWAGEN_PASSAT_NMS, segment=0),
|
||||
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),
|
||||
|
||||
133
iqdbc_repo/iqdbc/car/tests/test_vw_real_can.py
Normal file
133
iqdbc_repo/iqdbc/car/tests/test_vw_real_can.py
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Real-CAN replay invariant tests for VW torque platforms (PQ / MQB / MLB).
|
||||
|
||||
Replays real konn3kt routes through the car interface with openpilot lateral
|
||||
INACTIVE (latActive=False) and asserts openpilot never transmits an active-steering
|
||||
HCA command (active status or non-zero torque). Re-transmitting the stock camera's
|
||||
active HCA while not in control (stock-LKAS forwarding) leaves the EPS faulted for
|
||||
the whole drive (LH2_Sta_HCA=FAULT) - the regression that bricked steering on a PQ
|
||||
Passat NMS with a factory LKAS camera. Panda accepts these frames, so only a replay
|
||||
invariant like this catches it.
|
||||
|
||||
Self-contained within iqdbc: routes are resolved through konn3kt's public
|
||||
/v1/route/<id>/files endpoint (URLs are signed server-side, no auth/token needed).
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from collections import Counter
|
||||
|
||||
import pytest
|
||||
|
||||
from iqdbc.can.parser import CANParser
|
||||
from iqdbc.car import Bus, structs
|
||||
from iqdbc.car.can_definitions import CanData
|
||||
from iqdbc.car.car_helpers import can_fingerprint, interfaces
|
||||
from iqdbc.car.logreader import LogReader
|
||||
from iqdbc.car.volkswagen.values import CAR, DBC, VolkswagenFlags
|
||||
|
||||
API_HOST = os.environ.get("API_HOST", "https://api-iqlabs.konn3kt.com")
|
||||
|
||||
# konn3kt-hosted VW routes. (route_id, segment, platform, label)
|
||||
# Add MQB routes here as konn3kt-hosted MQB logs become available.
|
||||
VW_ROUTES = [
|
||||
("b29ee8c5a0a735d1|000000dc--a384e9083e", 0, CAR.VOLKSWAGEN_PASSAT_NMS, "PQ with stock LKAS camera"),
|
||||
("0f53129ed44f6920|00000287--3efbddeb96", 0, CAR.VOLKSWAGEN_PASSAT_NMS, "PQ without stock LKAS camera"),
|
||||
]
|
||||
|
||||
# Per-platform HCA message: (address, msg, status signal, torque signal, active-status values)
|
||||
HCA_INFO = {
|
||||
"pq": (0xD2, "HCA_1", "HCA_Status", "LM_Offset", (5, 7)),
|
||||
"mqb": (0x126, "HCA_01", "HCA_01_Status_HCA", "HCA_01_LM_Offset", (5, 6, 7)),
|
||||
}
|
||||
|
||||
|
||||
def _request_headers() -> dict[str, str]:
|
||||
# konn3kt's edge rejects the default urllib User-Agent with 403. The routes are public
|
||||
# (access returns early for public routes), but IQ.Pilot/Cabana tooling conventionally
|
||||
# sends a Konn3kt user JWT, so include one when available (env or ~/.comma/auth.json).
|
||||
headers = {"User-Agent": "iqdbc"}
|
||||
token = os.environ.get("KONN3KT_ACCESS_TOKEN")
|
||||
if not token:
|
||||
try:
|
||||
with open(os.path.expanduser("~/.comma/auth.json")) as f:
|
||||
token = json.load(f).get("access_token")
|
||||
except (OSError, ValueError):
|
||||
token = None
|
||||
if token:
|
||||
headers["Authorization"] = f"JWT {token}"
|
||||
return headers
|
||||
|
||||
|
||||
def _rlog_url(route_id: str, segment: int) -> str:
|
||||
req = urllib.request.Request(f"{API_HOST}/v1/route/{urllib.parse.quote(route_id, safe='|')}/files",
|
||||
headers=_request_headers())
|
||||
with urllib.request.urlopen(req, timeout=30) as f:
|
||||
files = json.load(f)
|
||||
for url in files.get("logs", []):
|
||||
# path looks like /connectdata/<dongle>/<log>/<seg>/rlog.zst
|
||||
parts = urllib.parse.urlparse(url).path.rstrip("/").split("/")
|
||||
if len(parts) >= 2 and parts[-2] == str(segment):
|
||||
return url
|
||||
raise RuntimeError(f"no rlog for {route_id} segment {segment} (uploaded & public?)")
|
||||
|
||||
|
||||
def _load_can(route_id: str, segment: int):
|
||||
lr = LogReader(_rlog_url(route_id, segment), only_union_types=True, sort_by_time=True)
|
||||
return [(m.logMonoTime, [CanData(c.address, c.dat, c.src) for c in m.can]) for m in lr if m.which() == "can"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("route_id,segment,platform,label", VW_ROUTES)
|
||||
def test_vw_inactive_steering_invariant(route_id, segment, platform, label):
|
||||
can_msgs = _load_can(route_id, segment)
|
||||
assert len(can_msgs) > 1000, f"insufficient CAN data for {label}: {len(can_msgs)} frames"
|
||||
|
||||
# fingerprint from a fresh iterator over the (unmutated) frame list
|
||||
frame_iter = (frames for _, frames in can_msgs)
|
||||
def can_recv(wait_for_one: bool = False):
|
||||
return [next(frame_iter, [])]
|
||||
_, fingerprint = can_fingerprint(can_recv)
|
||||
|
||||
CarInterface = interfaces[platform]
|
||||
CP = CarInterface.get_params(platform, fingerprint, [], False, False, False)
|
||||
CP_IQ = CarInterface.get_params_iq(CP, platform, fingerprint, [], False, False, False)
|
||||
|
||||
if CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
pytest.skip("invariant covers torque-based VW platforms (PQ/MQB/MLB)")
|
||||
|
||||
key = "pq" if CP.flags & VolkswagenFlags.PQ else "mqb"
|
||||
hca_addr, hca_msg, status_sig, torque_sig, active_status = HCA_INFO[key]
|
||||
cp = CANParser(DBC[platform][Bus.pt], [(hca_msg, 0)], 0)
|
||||
|
||||
CI = CarInterface(CP, CP_IQ)
|
||||
CC = structs.CarControl().as_reader() # latActive defaults to False
|
||||
CC_IQ = structs.IQCarControl()
|
||||
|
||||
hca_seen = 0
|
||||
violations = Counter()
|
||||
for i, (mono, frames) in enumerate(can_msgs):
|
||||
CI.update([(mono, frames)])
|
||||
_, sendcan = CI.apply(CC, CC_IQ, mono)
|
||||
|
||||
if i < 300: # CarController / CANParser warmup
|
||||
continue
|
||||
|
||||
for addr, dat, bus in sendcan:
|
||||
if addr != hca_addr or bus != 0:
|
||||
continue
|
||||
hca_seen += 1
|
||||
cp.update([(mono, [(addr, bytes(dat), 0)])])
|
||||
if int(cp.vl[hca_msg][status_sig]) in active_status:
|
||||
violations["active_status"] += 1
|
||||
if abs(cp.vl[hca_msg][torque_sig]) > 0:
|
||||
violations["nonzero_torque"] += 1
|
||||
|
||||
assert hca_seen > 50, f"{label}: no HCA steering messages transmitted to inspect"
|
||||
assert not len(violations), \
|
||||
f"{label}: openpilot TX'd active HCA while latActive=False: {dict(violations)}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(pytest.main([__file__, "-v"]))
|
||||
@@ -7,9 +7,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"NISSAN_LEAF" = [nan, 1.5, nan]
|
||||
"NISSAN_ROGUE" = [nan, 1.5, nan]
|
||||
|
||||
# PSA angle based controllers
|
||||
"PSA_PEUGEOT_208" = [nan, 2.0, nan]
|
||||
|
||||
# New subarus angle based controllers
|
||||
"SUBARU_FORESTER_2022" = [nan, 3.0, nan]
|
||||
"SUBARU_OUTBACK_2023" = [nan, 3.0, nan]
|
||||
@@ -21,14 +18,11 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
# Tesla angle based controllers
|
||||
"TESLA_MODEL_3" = [nan, 2.5, nan]
|
||||
"TESLA_MODEL_Y" = [nan, 2.5, nan]
|
||||
"TESLA_MODEL_X" = [nan, 2.5, nan]
|
||||
|
||||
# Guess
|
||||
"FORD_BRONCO_SPORT_MK1" = [nan, 1.5, nan]
|
||||
"FORD_ESCAPE_MK4" = [nan, 1.5, nan]
|
||||
"FORD_ESCAPE_MK4_5" = [nan, 1.5, nan]
|
||||
"FORD_EXPLORER_MK6" = [nan, 1.5, nan]
|
||||
"FORD_EXPEDITION_MK4" = [nan, 1.5, nan]
|
||||
"FORD_F_150_MK14" = [nan, 1.5, nan]
|
||||
"FORD_FOCUS_MK4" = [nan, 1.5, nan]
|
||||
"FORD_MAVERICK_MK1" = [nan, 1.5, nan]
|
||||
@@ -44,26 +38,20 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"RAM_1500_5TH_GEN" = [2.0, 2.0, 0.05]
|
||||
"RAM_HD_5TH_GEN" = [1.4, 1.4, 0.05]
|
||||
"SUBARU_OUTBACK" = [2.0, 1.5, 0.2]
|
||||
"BUICK_BABYENCLAVE" = [1.45, 1.6, 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" = [1.0, 2.0, 0.175]
|
||||
"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.05]
|
||||
"CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075]
|
||||
"CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
|
||||
"CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16]
|
||||
"CHEVROLET_TRAVERSE" = [1.33, 1.33, 0.18]
|
||||
"CHEVROLET_EQUINOX" = [2.5, 2.5, 0.05]
|
||||
"CHEVROLET_VOLT_2019" = [1.4, 1.4, 0.16]
|
||||
"VOLKSWAGEN_GOLF_MK8" = [nan, 2.5, nan]
|
||||
"CUPRA_BORN_MK1" = [nan, 2.5, nan]
|
||||
"VOLKSWAGEN_ID3_MK1" = [nan, 2.5, nan]
|
||||
"VOLKSWAGEN_ID3_MK2" = [nan, 2.5, nan]
|
||||
"VOLKSWAGEN_ID4_MK1" = [nan, 2.5, nan]
|
||||
"VOLKSWAGEN_ID4_MK2" = [nan, 2.5, nan]
|
||||
"AUDI_Q4_MK1" = [nan, 2.5, nan]
|
||||
"AUDI_Q4_MK2" = [nan, 2.5, nan]
|
||||
"SEAT_LEON_MK4" = [nan, 2.5, nan]
|
||||
"SKODA_ENYAQ_MK1" = [nan, 2.5, nan]
|
||||
"SKODA_ENYAQ_MK2" = [nan, 2.5, nan]
|
||||
"CHEVROLET_TRAX" = [1.33, 1.9, 0.16]
|
||||
"VOLKSWAGEN_ID4_MK1" = [2.0, 2.0, 0.1]
|
||||
"VOLKSWAGEN_ID4_MK2" = [2.0, 2.0, 0.1]
|
||||
"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]
|
||||
@@ -81,33 +69,22 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"GMC_ACADIA" = [1.6, 1.6, 0.2]
|
||||
"LEXUS_IS_TSS2" = [2.0, 2.0, 0.1]
|
||||
"HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_KONA_HEV_2ND_GEN" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.005]
|
||||
"HYUNDAI_IONIQ_9" = [1.75, 1.75, 0.15]
|
||||
"HYUNDAI_AZERA_7TH_GEN" = [1.8, 1.8, 0.1]
|
||||
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
|
||||
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
|
||||
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_CUSTIN_1ST_GEN" = [2.5, 2.5, 0.1]
|
||||
"LEXUS_GS_F" = [2.5, 2.5, 0.08]
|
||||
"HYUNDAI_STARIA_4TH_GEN" = [1.8, 2.0, 0.15]
|
||||
"HYUNDAI_PORTER_II_EV" = [1.8, 2.0, 0.15]
|
||||
"KIA_RAY_EV" = [1.8, 2.0, 0.15]
|
||||
"GENESIS_GV70_ELECTRIFIED_1ST_GEN" = [1.9, 1.9, 0.09]
|
||||
"GENESIS_G80_2ND_GEN_FL" = [2.5819356441497803, 2.5, 0.11244568973779678]
|
||||
# Note that some Rivians achieve significantly less lateral acceleration than this
|
||||
"RIVIAN_R1_GEN1" = [2.8, 2.5, 0.07]
|
||||
"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1]
|
||||
"HONDA_ACCORD_11G" = [1.35, 1.35, 0.17]
|
||||
"HONDA_PILOT_4G" = [1.25, 1.25, 0.21]
|
||||
"HONDA_PASSPORT_4G" = [1.2, 1.2, 0.16]
|
||||
"ACURA_MDX_4G_MMR" = [1.25, 1.25, 0.15]
|
||||
"HONDA_CRV_6G" = [1.3, 1.3, 0.2]
|
||||
"HONDA_CITY_7G" = [1.2, 1.2, 0.23]
|
||||
"HONDA_ODYSSEY_5G_MMR" = [0.9, 0.9, 0.2]
|
||||
"HONDA_NBOX_2G" = [1.2, 1.2, 0.2]
|
||||
"ACURA_TLX_2G" = [1.2, 1.2, 0.15]
|
||||
"ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16]
|
||||
"PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2]
|
||||
"AUDI_Q5_MK1" = [1.8, 1.8, 0.18]
|
||||
"LEXUS_LS" = [1.35, 1.7, 0.17]
|
||||
"TOYOTA_RAV4_PRIME" = [1.7, 2.0, 0.14]
|
||||
"TOYOTA_RAV4_TSS2_2022" = [1.9, 1.9304407208090029, 0.112174]
|
||||
|
||||
# Dashcam or fallback configured as ideal car
|
||||
"MOCK" = [10.0, 10, 0.0]
|
||||
@@ -116,6 +93,46 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"HONDA_CIVIC_2022" = [2.5, 1.2, 0.15]
|
||||
"HONDA_HRV_3G" = [2.5, 1.2, 0.2]
|
||||
|
||||
# port extensions
|
||||
"HONDA_CLARITY" = [0.96, 0.4018518740819229, 0.19]
|
||||
"CHEVROLET_MALIBU_NON_ACC_9TH_GEN" = [1.85, 1.85, 0.075]
|
||||
# Community
|
||||
"HYUNDAI_GRANDEUR_IG" = [2.3, 2.3, 0.1]
|
||||
"HYUNDAI_GRANDEUR_IG_HEV" = [2.3, 2.3, 0.1]
|
||||
"GENESIS_EQ900" = [2.3, 2.3, 0.1]
|
||||
"GENESIS_EQ900_L" = [2.3, 2.3, 0.1]
|
||||
"GENESIS_G90_2019" = [2.3, 2.3, 0.1]
|
||||
"KIA_MOHAVE" = [2.3, 2.3, 0.1]
|
||||
"KIA_K5" = [2.3, 2.3, 0.1]
|
||||
"KIA_K5_HEV" = [2.3, 2.3, 0.1]
|
||||
"KIA_K5_HEV_2022" = [2.3, 2.3, 0.1]
|
||||
"KIA_K7" = [2.3, 2.3, 0.1]
|
||||
"KIA_K7_HEV" = [2.3, 2.3, 0.1]
|
||||
"KIA_K7_PE" = [2.3, 2.3, 0.1]
|
||||
"KIA_K7_HEV_PE" = [2.3, 2.3, 0.1]
|
||||
"KIA_K9" = [2.3, 2.3, 0.1]
|
||||
"GENESIS_GV70_EV_1ST_GEN" = [2.42, 2.42, 0.1]
|
||||
"HYUNDAI_NEXO" = [2.7, 2.7, 0.1]
|
||||
"KIA_EV_SK3" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_CASPER"= [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_CASPER_EV"= [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_IONIQ_5_N" = [3.17, 2.71, 0.097]
|
||||
"HYUNDAI_IONIQ_5_PE" = [1.75, 1.75, 0.15]
|
||||
|
||||
# Synced verbatim from comma opendbc torque_data/override.toml — these platforms
|
||||
# exist upstream and were simply never carried over when iqdbc forked.
|
||||
ACURA_MDX_4G_MMR = [1.25, 1.25, 0.15]
|
||||
ACURA_TLX_2G = [1.2, 1.2, 0.15]
|
||||
ACURA_TLX_2G_MMR = [1.7, 1.7, 0.16]
|
||||
AUDI_Q5_MK1 = [1.8, 1.8, 0.18]
|
||||
CUPRA_BORN_MK1 = [nan, 2.5, nan]
|
||||
FORD_ESCAPE_MK4_5 = [nan, 1.5, nan]
|
||||
FORD_EXPEDITION_MK4 = [nan, 1.5, nan]
|
||||
HONDA_ACCORD_11G = [1.35, 1.35, 0.17]
|
||||
HONDA_CITY_7G = [1.2, 1.2, 0.23]
|
||||
HONDA_CRV_6G = [1.3, 1.3, 0.2]
|
||||
HONDA_NBOX_2G = [1.2, 1.2, 0.2]
|
||||
HONDA_ODYSSEY_5G_MMR = [0.9, 0.9, 0.2]
|
||||
HONDA_PASSPORT_4G = [1.2, 1.2, 0.16]
|
||||
HONDA_PILOT_4G = [1.25, 1.25, 0.21]
|
||||
LEXUS_LS = [1.35, 1.7, 0.17]
|
||||
PORSCHE_MACAN_MK1 = [2.0, 2.0, 0.2]
|
||||
PSA_PEUGEOT_208 = [nan, 2.0, nan]
|
||||
TESLA_MODEL_X = [nan, 2.5, nan]
|
||||
|
||||
@@ -37,13 +37,21 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"HYUNDAI_SONATA" = [2.9638737459977467, 2.1259108157250735, 0.07813665616927593]
|
||||
"HYUNDAI_SONATA_HYBRID" = [2.8990264092395734, 2.061410192222139, 0.0899805488717382]
|
||||
"HYUNDAI_TUCSON_4TH_GEN" = [2.960174, 2.860284, 0.108745]
|
||||
"HYUNDAI_SANTAFE_MX5" = [3.2, 3.0, 0.05]
|
||||
"HYUNDAI_SANTAFE_MX5_HEV" = [3.2, 3.0, 0.05]
|
||||
"JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048]
|
||||
"JEEP_GRAND_CHEROKEE" = [2.27116, 1.4057367824262523, 0.11725947414922003]
|
||||
"KIA_EV6" = [3.2, 2.093457, 0.005]
|
||||
"KIA_EV6_PE" = [3.2, 2.093457, 0.005]
|
||||
"KIA_K5_2021" = [2.405339728085138, 1.460032270828705, 0.11650989850813716]
|
||||
"KIA_K5_DL3_24" = [2.5, 2.5, 0.1]
|
||||
"KIA_K5_DL3_24_HEV" = [2.5, 2.5, 0.1]
|
||||
"KIA_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267]
|
||||
"KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558]
|
||||
"KIA_STINGER" = [2.7499043387418967, 1.849652021986449, 0.12048334239559202]
|
||||
"KIA_EV9" = [1.75, 1.75, 0.15]
|
||||
"KIA_EV3" = [3.2, 2.093457, 0.005]
|
||||
"KIA_PV5" = [3.2, 2.093457, 0.005]
|
||||
"LEXUS_ES_TSS2" = [2.0357564999999997, 1.999082295195227, 0.101533]
|
||||
"LEXUS_NX" = [2.3525924753753613, 1.9731412277641067, 0.15168101064205927]
|
||||
"LEXUS_NX_TSS2" = [2.4331999786982936, 2.1045680431705414, 0.14099899317761067]
|
||||
@@ -69,8 +77,9 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"TOYOTA_PRIUS" = [1.60, 1.5023147650693636, 0.151515]
|
||||
"TOYOTA_PRIUS_TSS2" = [1.972600, 1.9104337425537743, 0.170968]
|
||||
"TOYOTA_RAV4" = [2.085695074355425, 2.2142832316984733, 0.13339165270103975]
|
||||
"TOYOTA_RAV4_TSS2" = [1.9557514786720276, 2.087101966779332, 0.12075843289494514]
|
||||
"TOYOTA_RAV4_TSS2" = [2.279239424615458, 2.087101966779332, 0.13682208413446817]
|
||||
"TOYOTA_RAV4H" = [1.9796257271652042, 1.7503987331707576, 0.14628860048885406]
|
||||
"TOYOTA_RAV4_TSS2_2022" = [2.241883248393209, 1.9304407208090029, 0.112174]
|
||||
"TOYOTA_SIENNA" = [1.689726, 1.3208264576110418, 0.140456]
|
||||
"TOYOTA_YARIS" = [2.22984, 1.86145, 0.168189]
|
||||
"VOLKSWAGEN_ARTEON_MK1" = [1.45136518053819, 1.3639364049316804, 0.23806361745695032]
|
||||
|
||||
@@ -9,12 +9,12 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
|
||||
"TOYOTA_ALPHARD_TSS2" = "TOYOTA_SIENNA"
|
||||
"TOYOTA_PRIUS_V" = "TOYOTA_PRIUS"
|
||||
"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_PRIME"
|
||||
"TOYOTA_RAV4_PRIME" = "TOYOTA_RAV4_TSS2"
|
||||
"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_TSS2"
|
||||
"LEXUS_IS" = "LEXUS_NX"
|
||||
"LEXUS_CTH" = "LEXUS_NX"
|
||||
"LEXUS_ES" = "TOYOTA_CAMRY"
|
||||
"LEXUS_RC" = "LEXUS_NX_TSS2"
|
||||
"LEXUS_RC_TSS2" = "LEXUS_NX_TSS2"
|
||||
"LEXUS_LC_TSS2" = "LEXUS_NX_TSS2"
|
||||
|
||||
"KIA_OPTIMA_G4" = "HYUNDAI_SONATA"
|
||||
@@ -25,6 +25,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"KIA_CEED" = "HYUNDAI_SONATA"
|
||||
"KIA_SELTOS" = "HYUNDAI_SONATA"
|
||||
"KIA_NIRO_PHEV" = "KIA_NIRO_EV"
|
||||
"KIA_EV4" = "KIA_EV6"
|
||||
"KIA_NIRO_PHEV_2022" = "KIA_NIRO_EV"
|
||||
"KIA_NIRO_HEV_2021" = "KIA_NIRO_EV"
|
||||
"HYUNDAI_VELOSTER" = "HYUNDAI_SONATA_LF"
|
||||
@@ -45,12 +46,13 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"GENESIS_G90" = "GENESIS_G70"
|
||||
"GENESIS_G80" = "GENESIS_G70"
|
||||
"GENESIS_G70_2020" = "HYUNDAI_SONATA"
|
||||
"HYUNDAI_SONATA_2024" = "HYUNDAI_SONATA"
|
||||
|
||||
"HONDA_FREED" = "HONDA_ODYSSEY"
|
||||
"HONDA_CRV_EU" = "HONDA_CRV"
|
||||
"HONDA_CIVIC_BOSCH_DIESEL" = "HONDA_CIVIC_BOSCH"
|
||||
"HONDA_E" = "HONDA_CIVIC_BOSCH"
|
||||
"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY"
|
||||
"HONDA_ODYSSEY_CHN" = "HONDA_ODYSSEY"
|
||||
|
||||
"BUICK_LACROSSE" = "CHEVROLET_VOLT"
|
||||
"BUICK_REGAL" = "CHEVROLET_VOLT"
|
||||
@@ -58,6 +60,18 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"CADILLAC_ATS" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_MALIBU" = "CHEVROLET_VOLT"
|
||||
"HOLDEN_ASTRA" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_VOLT_CC" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_BOLT_CC" = "CHEVROLET_BOLT_EUV"
|
||||
"CHEVROLET_BOLT_2017" = "CHEVROLET_BOLT_EUV"
|
||||
"CHEVROLET_BOLT_2018" = "CHEVROLET_BOLT_EUV"
|
||||
"CHEVROLET_EQUINOX_CC" = "CHEVROLET_EQUINOX"
|
||||
"CHEVROLET_SUBURBAN" = "CHEVROLET_SILVERADO"
|
||||
"CHEVROLET_SUBURBAN_CC" = "CHEVROLET_SILVERADO"
|
||||
"CHEVROLET_TRAX_2024" = "CHEVROLET_VOLT"
|
||||
"CADILLAC_CT6_CC" = "CHEVROLET_VOLT"
|
||||
"CADILLAC_CT6_ACC" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_TRAILBLAZER_CC" = "CHEVROLET_TRAILBLAZER"
|
||||
"CADILLAC_XT5_CC" = "GMC_ACADIA"
|
||||
|
||||
"SKODA_FABIA_MK4" = "VOLKSWAGEN_GOLF_MK7"
|
||||
"SKODA_OCTAVIA_MK3" = "SKODA_SUPERB_MK3"
|
||||
@@ -74,8 +88,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"VOLKSWAGEN_POLO_MK6" = "VOLKSWAGEN_GOLF_MK7"
|
||||
"SEAT_ATECA_MK1" = "VOLKSWAGEN_GOLF_MK7"
|
||||
"VOLKSWAGEN_JETTA_MK6" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_PASSAT_MK7" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_PASSAT_NMS_PLUS" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
|
||||
"SUBARU_CROSSTREK_HYBRID" = "SUBARU_IMPREZA_2020"
|
||||
"SUBARU_FORESTER_HYBRID" = "SUBARU_IMPREZA_2020"
|
||||
@@ -88,21 +100,34 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"SUBARU_LEGACY_PREGLOBAL" = "SUBARU_IMPREZA"
|
||||
"SUBARU_ASCENT" = "SUBARU_FORESTER"
|
||||
|
||||
# port extensions
|
||||
"KIA_CEED_PHEV_2022_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"HYUNDAI_KONA_EV_NON_SCC" = "HYUNDAI_KONA_EV"
|
||||
"KIA_FORTE_2019_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"KIA_FORTE_2021_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"KIA_SELTOS_2023_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"HYUNDAI_KONA_NON_SCC" = "HYUNDAI_KONA_EV"
|
||||
"HYUNDAI_ELANTRA_2022_NON_SCC" = "HYUNDAI_ELANTRA_2021"
|
||||
"GENESIS_G70_2021_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"HYUNDAI_BAYON_1ST_GEN_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"CHEVROLET_BOLT_NON_ACC_2ND_GEN" = "CHEVROLET_BOLT_EUV"
|
||||
# IQ.Pilot GM Non-ACC ports borrow their base platform's lateral tune
|
||||
"CHEVROLET_BOLT_NON_ACC" = "CHEVROLET_BOLT_EUV"
|
||||
"CHEVROLET_BOLT_NON_ACC_1ST_GEN" = "CHEVROLET_BOLT_EUV"
|
||||
"CHEVROLET_BOLT_NON_ACC_2ND_GEN" = "CHEVROLET_BOLT_EUV"
|
||||
"CHEVROLET_EQUINOX_NON_ACC_3RD_GEN" = "CHEVROLET_EQUINOX"
|
||||
"CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN" = "CHEVROLET_SILVERADO"
|
||||
"CADILLAC_CT6_NON_ACC_1ST_GEN" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN" = "CHEVROLET_TRAILBLAZER"
|
||||
"CADILLAC_XT5_NON_ACC_1ST_GEN" = "GMC_ACADIA"
|
||||
"CHEVROLET_MALIBU_NON_ACC_9TH_GEN" = "CHEVROLET_VOLT"
|
||||
"CADILLAC_XT5_NON_ACC_1ST_GEN" = "CADILLAC_XT4"
|
||||
|
||||
# Synced verbatim from comma opendbc torque_data/substitute.toml
|
||||
"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY"
|
||||
"LEXUS_RC_TSS2" = "LEXUS_NX_TSS2"
|
||||
|
||||
# Platform-sibling substitutes: comma has never shipped torque data for these,
|
||||
# so rather than invent lateral-accel figures they borrow the tune of the closest
|
||||
# platform twin. REVIEW: replace with measured values when available.
|
||||
"SEAT_ALHAMBRA_MK1" = "VOLKSWAGEN_SHARAN_MK2"
|
||||
"VOLKSWAGEN_PASSAT_NMS_PLUS" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_ID3_MK1" = "VOLKSWAGEN_ID4_MK1"
|
||||
"VOLKSWAGEN_ID3_MK2" = "VOLKSWAGEN_ID4_MK2"
|
||||
"SKODA_ENYAQ_MK1" = "VOLKSWAGEN_ID4_MK1"
|
||||
"SKODA_ENYAQ_MK2" = "VOLKSWAGEN_ID4_MK2"
|
||||
"AUDI_Q4_MK1" = "VOLKSWAGEN_ID4_MK1"
|
||||
"AUDI_Q4_MK2" = "VOLKSWAGEN_ID4_MK2"
|
||||
"VOLKSWAGEN_GOLF_MK8" = "VOLKSWAGEN_GOLF_MK7"
|
||||
"SEAT_LEON_MK4" = "VOLKSWAGEN_GOLF_MK7"
|
||||
"VOLKSWAGEN_PASSAT_MK7" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_PASSAT_B7" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"HONDA_CLARITY" = "HONDA_ACCORD"
|
||||
|
||||
@@ -260,6 +260,7 @@ class CarController(CarControllerBase, GasInterceptorCarController):
|
||||
freeze_integrator=actuators.longControlState != LongCtrlState.pid)
|
||||
else:
|
||||
self.long_pid.reset()
|
||||
pcm_accel_cmd = 0.
|
||||
|
||||
# Along with rate limiting positive jerk above, this greatly improves gas response time
|
||||
# Consider the net acceleration request that the PCM should be applying (pitch included)
|
||||
@@ -269,7 +270,9 @@ class CarController(CarControllerBase, GasInterceptorCarController):
|
||||
elif net_acceleration_request_min > 0.3:
|
||||
self.permit_braking = False
|
||||
|
||||
pcm_accel_cmd = pcm_accel_cmd if self.CP.carFingerprint in TSS2_CAR else actuators.accel
|
||||
sdsu_tssp_long_active = bool(self.CP_IQ.flags & ToyotaFlagsIQ.SMART_DSU) and \
|
||||
(self.CP.carFingerprint not in TSS2_CAR) and CC.longActive
|
||||
pcm_accel_cmd = actuators.accel if sdsu_tssp_long_active else pcm_accel_cmd
|
||||
pcm_accel_cmd = float(np.clip(pcm_accel_cmd, self.params.ACCEL_MIN, self.params.ACCEL_MAX))
|
||||
|
||||
main_accel_cmd = 0. if self.CP.flags & ToyotaFlags.SECOC.value else pcm_accel_cmd
|
||||
|
||||
@@ -8,7 +8,7 @@ from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \
|
||||
TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR, \
|
||||
SECOC_CAR
|
||||
from iqdbc.lvbs.car.toyota.carstate_ext import CarStateExt
|
||||
from iqdbc.lvbs.car.toyota.iq_carstate import IQCarState
|
||||
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
@@ -26,10 +26,10 @@ TEMP_STEER_FAULTS = (0, 9, 11, 21, 25)
|
||||
PERM_STEER_FAULTS = (3, 17)
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase, IQCarState):
|
||||
def __init__(self, CP, CP_IQ):
|
||||
CarStateBase.__init__(self, CP, CP_IQ)
|
||||
CarStateExt.__init__(self, CP, CP_IQ)
|
||||
IQCarState.__init__(self, CP, CP_IQ)
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
self.eps_torque_scale = EPS_SCALE[CP.carFingerprint] / 100.
|
||||
self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2.
|
||||
@@ -210,7 +210,7 @@ class CarState(CarStateBase, CarStateExt):
|
||||
|
||||
ret.buttonEvents = buttonEvents
|
||||
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers)
|
||||
IQCarState.update(self, ret, ret_iq, can_parsers)
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
from iqdbc.car.structs import CarParams
|
||||
from iqdbc.car.toyota.values import CAR
|
||||
|
||||
from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
|
||||
from iqdbc.lvbs.car.toyota.fingerprints_ext import FW_VERSIONS_EXT
|
||||
from iqdbc.lvbs.car.iq_fingerprints import extend_fw_versions
|
||||
from iqdbc.lvbs.car.toyota.iq_fingerprints import FW_VERSIONS_EXT
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if ret.flags & ToyotaFlags.SECOC.value:
|
||||
ret.secOcRequired = True
|
||||
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.SECOC.value
|
||||
ret.dashcamOnly = is_release
|
||||
|
||||
if candidate in ANGLE_CONTROL_CAR:
|
||||
ret.steerControlType = SteerControlType.angle
|
||||
@@ -119,10 +118,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate in TSS2_CAR:
|
||||
ret.flags |= ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.vEgoStarting = 0.25
|
||||
ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
|
||||
|
||||
# Hybrids have much quicker longitudinal actuator response
|
||||
if ret.flags & ToyotaFlags.HYBRID.value:
|
||||
ret.longitudinalActuatorDelay = 0.05
|
||||
@@ -132,9 +127,6 @@ class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams, candidate, fingerprint: dict[int, dict[int, int]],
|
||||
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
|
||||
if stock_cp.flags & ToyotaFlags.SECOC.value and stock_cp.fingerprintSource == structs.CarParams.FingerprintSource.fixed:
|
||||
stock_cp.dashcamOnly = False
|
||||
|
||||
if candidate in UNSUPPORTED_DSU_CAR:
|
||||
ret.iqSafetyFlags |= ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU
|
||||
|
||||
|
||||
@@ -4,26 +4,20 @@ from iqdbc.car.toyota.values import CAR, ToyotaFlags
|
||||
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ
|
||||
|
||||
|
||||
def test_forced_secoc_toyota_clears_dashcam_mode():
|
||||
def test_secoc_toyota_not_dashcam_on_release():
|
||||
# SecOC Toyotas are controllable regardless of branch or fingerprint source.
|
||||
candidate = CAR.TOYOTA_SIENNA_4TH_GEN
|
||||
|
||||
# is_release=True (release branch) must not force dashcam mode
|
||||
cp = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
assert cp.dashcamOnly
|
||||
|
||||
cp.fingerprintSource = structs.CarParams.FingerprintSource.fixed
|
||||
CarInterface.get_params_iq(cp, candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
|
||||
assert cp.flags & ToyotaFlags.SECOC.value
|
||||
assert cp.secOcRequired
|
||||
assert not cp.dashcamOnly
|
||||
|
||||
|
||||
def test_automatic_secoc_toyota_release_stays_dashcam():
|
||||
candidate = CAR.TOYOTA_SIENNA_4TH_GEN
|
||||
cp = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
assert cp.dashcamOnly
|
||||
|
||||
# fw/can-sourced fingerprint (not forced) must also stay controllable
|
||||
cp.fingerprintSource = structs.CarParams.FingerprintSource.can
|
||||
CarInterface.get_params_iq(cp, candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
|
||||
assert cp.dashcamOnly
|
||||
assert not cp.dashcamOnly
|
||||
|
||||
|
||||
def test_smart_dsu_clears_disable_radar_on_radar_acc_toyota():
|
||||
|
||||
@@ -14,10 +14,16 @@ from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.common.numpy_fast import clip, interp
|
||||
from iqdbc.car.interfaces import CarControllerBase
|
||||
from iqdbc.car.volkswagen import mlbcan, mqbcan, pqcan, mebcan
|
||||
from iqdbc.car.volkswagen.values import CanBus, CarControllerParams, VolkswagenFlags, VolkswagenFlagsIQ
|
||||
from iqdbc.car.volkswagen.pq_radar_handler import PQRadarHandler
|
||||
from iqdbc.car.volkswagen.values import (
|
||||
CanBus, CarControllerParams, MQB_A0_CARS, VolkswagenFlags, VolkswagenFlagsIQ, apply_pq_stopping_accel,
|
||||
)
|
||||
from iqdbc.car.volkswagen.mebutils import LongControlJerk, LongControlLimit, LatControlCurvature
|
||||
from iqdbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.iqpilot.konn3kt.iqlvbs import alc as iq_lvbs_alc
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
iq_lvbs_alc = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.alc")
|
||||
iq_lvbs_commander = import_verified_module("iqpilot_commander_private", "iqpilot_private.konn3kt.iqlvbs.iqlvbs_commander")
|
||||
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
sys.path.insert(0, iqpilot_path)
|
||||
@@ -27,9 +33,19 @@ except ImportError:
|
||||
pass
|
||||
|
||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||
AudibleAlert = structs.CarControl.HUDControl.AudibleAlert
|
||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||
|
||||
|
||||
def dVisual(CCS, CS):
|
||||
if CCS == mqbcan:
|
||||
decelV = CS.tsk_verzoeg_anf
|
||||
elif CCS == pqcan:
|
||||
decelV = CS.br8_acc_anf
|
||||
else:
|
||||
decelV = False
|
||||
return decelV
|
||||
|
||||
class MQBStandstillManager:
|
||||
BRAKE_TORQUE_RAMP_RATE = 2000.0 # Nm/s
|
||||
ASSUMED_WHEEL_RADIUS = 0.328 # m, typical tire rolling radius
|
||||
@@ -176,7 +192,6 @@ class MQBStandstillManager:
|
||||
self.prev_accel = accel
|
||||
return long_active, accel, stopping, starting, esp_starting_override, esp_stopping_override
|
||||
|
||||
|
||||
class CarController(CarControllerBase):
|
||||
def __init__(self, dbc_names, CP, CP_IQ):
|
||||
super().__init__(dbc_names, CP, CP_IQ)
|
||||
@@ -185,8 +200,11 @@ class CarController(CarControllerBase):
|
||||
self.CAN = CanBus(CP)
|
||||
self.packer_pt = CANPacker(dbc_names[Bus.pt])
|
||||
|
||||
self._pt_tx_bus = self.CAN.pt
|
||||
if CP.flags & VolkswagenFlags.PQ:
|
||||
self.CCS = pqcan
|
||||
if CP.flags & VolkswagenFlagsIQ.IQ_PQ_LOWLINE:
|
||||
self._pt_tx_bus = self.CAN.aux
|
||||
elif CP.flags & VolkswagenFlags.MLB:
|
||||
self.CCS = mlbcan
|
||||
elif CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
@@ -211,13 +229,16 @@ class CarController(CarControllerBase):
|
||||
self.long_jerk_control = LongControlJerk(dt=(DT_CTRL * self.CCP.ACC_CONTROL_STEP)) if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO) else None
|
||||
self.long_limit_control = LongControlLimit(dt=(DT_CTRL * self.CCP.ACC_CONTROL_STEP)) if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO) else None
|
||||
self.gra_acc_counter_last = None
|
||||
self.motor3_frame_last = None
|
||||
self.motor3_was_stopping = False
|
||||
self.motor3_resuming = False
|
||||
self.sng_handoff_active = False
|
||||
self.acc_counter_seeded = False
|
||||
self.klr_counter_last = None
|
||||
self.eps_timer_soft_disable_alert = False
|
||||
self.hca_frame_timer_running = 0
|
||||
self.hca_frame_same_torque = 0
|
||||
self.accel_last = 0
|
||||
self.accel_diff = 0
|
||||
self.long_deviation = 0
|
||||
self.long_jerklimit = 0
|
||||
self.HCA_Status = 3
|
||||
@@ -231,19 +252,43 @@ class CarController(CarControllerBase):
|
||||
self.radar_disabled_warning_timer = 0
|
||||
# Check once at init whether the DBC includes MEB_AWV_01 (AEB HUD for radar-disabled camera harness cars)
|
||||
self._has_aeb_hud_msg = "MEB_AWV_01" in self.packer_pt.dbc.name_to_msg
|
||||
self.eps_timer_workaround = bool(CP.flags & VolkswagenFlags.MLB)
|
||||
self.eps_timer_workaround = bool(CP.flags & (VolkswagenFlags.MLB | VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB))
|
||||
self._pq_patch_checked = not bool(CP.flags & VolkswagenFlags.PQ) or self.eps_timer_workaround
|
||||
self.hca_frame_timer_resetting = 0
|
||||
self.hca_frame_low_torque = 0
|
||||
self.long_override_counter = 0
|
||||
self.long_disabled_counter = 0
|
||||
self.standstill_manager = MQBStandstillManager(CP.mass, self.CCP.ACCEL_MIN) if self.CCS == mqbcan else None
|
||||
self.radar_handler = PQRadarHandler(self.CAN) if self.CCS is pqcan else None
|
||||
self.blend_stock_radar = False
|
||||
self.unavailable = False
|
||||
self.unavailable_hold = 0
|
||||
self.VM = VehicleModel(CP)
|
||||
self.is_mqb_a0 = self._is_mqb_a0_car(CP.carFingerprint)
|
||||
self.LateralController = (
|
||||
LatControlCurvature(self.CCP.CURVATURE_PID, self.CCP.CURVATURE_LIMITS.CURVATURE_MAX, 1 / (DT_CTRL * self.CCP.STEER_STEP))
|
||||
if (CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO))
|
||||
else None
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _is_mqb_a0_car(candidate) -> bool:
|
||||
return candidate in MQB_A0_CARS
|
||||
|
||||
def _get_mqb_steering_torque_scale(self, v_ego: float, enabled: bool) -> float:
|
||||
if enabled and self.CCS == mqbcan:
|
||||
return float(np.interp(v_ego, [0.4, 3.5, 4.0], [0.8, 0.95, 1.0]))
|
||||
return 1.0
|
||||
|
||||
def _should_spam_mqb_a0_resume(self, CS, enabled: bool) -> bool:
|
||||
return bool(
|
||||
enabled and
|
||||
self.is_mqb_a0 and
|
||||
self.CCS == mqbcan and
|
||||
CS.out.standstill and
|
||||
self.frame % 50 < 15
|
||||
)
|
||||
|
||||
def update(self, CC, CC_IQ, CS, now_nanos):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
@@ -252,10 +297,23 @@ class CarController(CarControllerBase):
|
||||
apply_torque = 0
|
||||
pqhca5or7Toggle = self._params.get_bool("pqhca5or7Toggle")
|
||||
eBrakeActive = self._params.get_bool("eBrakeActive")
|
||||
iq_mqb_steering_lockout = self._params.get_bool("iqMqbSteeringLockout")
|
||||
iq_mqb_acc_resume = self._params.get_bool("iqMqbAccResume")
|
||||
self.blend_stock_radar = self._params.get_bool("IQDynamicBlendStockRadar")
|
||||
if not self._pq_patch_checked:
|
||||
self._pq_patch_checked = True
|
||||
self.eps_timer_workaround = not self._params.get_bool("VwPqEpsPatched")
|
||||
blend_active = bool(self.blend_stock_radar and self.radar_handler is not None and self.CP.openpilotLongitudinalControl)
|
||||
AngleLateralControl = iq_lvbs_alc.angle_lateral_control_enabled(self, CS)
|
||||
self.entering = CS.vw_iq_lvbs_alc_entering
|
||||
self.active = CS.vw_iq_lvbs_alc_active
|
||||
|
||||
if hud_control.audibleAlert == AudibleAlert.refuse:
|
||||
self.unavailable_hold = self.CCP.IQ_PQ_UNAVAILABLE_HUD_FRAMES
|
||||
else:
|
||||
self.unavailable_hold = max(0, self.unavailable_hold - 1)
|
||||
self.unavailable = self.unavailable_hold > 0
|
||||
|
||||
CS.force_rhd_for_bsm = getattr(CC, "forceRHDForBSM", False)
|
||||
CS.enable_predicative_speed_limit = getattr(CC.cruiseControl, "speedLimitPredicative", False)
|
||||
CS.enable_pred_react_to_speed_limits = getattr(CC.cruiseControl, "speedLimitPredReactToSL", False)
|
||||
@@ -296,7 +354,8 @@ class CarController(CarControllerBase):
|
||||
self.steering_power_last = steering_power
|
||||
else:
|
||||
if CC.latActive and not AngleLateralControl:
|
||||
new_torque = int(round(actuators.torque * self.CCP.STEER_MAX))
|
||||
torque_scale = self._get_mqb_steering_torque_scale(CS.out.vEgo, iq_mqb_steering_lockout)
|
||||
new_torque = int(round(actuators.torque * self.CCP.STEER_MAX * torque_scale))
|
||||
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, self.CCP)
|
||||
self.hca_frame_timer_running += self.CCP.STEER_STEP
|
||||
if self.apply_torque_last == apply_torque:
|
||||
@@ -341,10 +400,10 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.eps_timer_soft_disable_alert = self.hca_frame_timer_running > self.CCP.STEER_TIME_ALERT / DT_CTRL
|
||||
self.apply_torque_last = apply_torque
|
||||
if not (AngleLateralControl and self.CCS in (mqbcan, pqcan)):
|
||||
can_sends.append(self.CCS.create_hca_steering_control(self.packer_pt, self.CAN.pt, output_torque, self.HCA_Status))
|
||||
if not (AngleLateralControl and self.CCS in (mqbcan, pqcan, mlbcan)):
|
||||
can_sends.append(self.CCS.create_hca_steering_control(self.packer_pt, self._pt_tx_bus, output_torque, self.HCA_Status))
|
||||
|
||||
if self.CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
|
||||
if self.CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT and self.CCS == mqbcan:
|
||||
ea_simulated_torque = float(np.clip(apply_torque * 2, -self.CCP.STEER_MAX, self.CCP.STEER_MAX))
|
||||
if abs(CS.out.steeringTorque) > abs(ea_simulated_torque):
|
||||
ea_simulated_torque = CS.out.steeringTorque
|
||||
@@ -379,7 +438,7 @@ class CarController(CarControllerBase):
|
||||
if self.frame % self.CCP.ACC_CONTROL_STEP == 0 and self.CP.openpilotLongitudinalControl and not CS.out.radarDisableFailed:
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
starting = actuators.longControlState == LongCtrlState.starting and CS.out.vEgo <= self.CP.vEgoStarting
|
||||
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < 0.25)
|
||||
accel = float(np.clip(actuators.accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if CC.enabled else 0)
|
||||
|
||||
long_override = CC.cruiseControl.override or CS.out.gasPressed
|
||||
@@ -409,7 +468,7 @@ class CarController(CarControllerBase):
|
||||
self.accel_last = accel
|
||||
else:
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < self.CP.vEgoStopping)
|
||||
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < 0.25)
|
||||
long_active = CC.longActive
|
||||
accel = actuators.accel
|
||||
esp_starting_override = None
|
||||
@@ -424,10 +483,16 @@ class CarController(CarControllerBase):
|
||||
|
||||
acc_control = self.CCS.acc_control_value(CS.out.cruiseState.available, long_active, CC.cruiseControl.override, CS.out.accFaulted)
|
||||
accel = float(np.clip(accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if (long_active or CC.cruiseControl.override) else 0)
|
||||
self.accel_diff = (0.0019 * (accel - self.accel_last)) + (1 - 0.0019) * self.accel_diff
|
||||
self.long_jerklimit = 3.0 # AendGrad (0.01 * (np.clip(abs(accel), 0.7, 2))) + (1 - 0.01) * self.long_jerklimit
|
||||
self.long_deviation = 0.2 # RegelAbw np.interp(abs(accel - self.accel_diff), [0, 0.3, 1.0], [0.02, 0.04, 0.08])
|
||||
self.long_jerklimit = float(interp(accel, [-1.5, -0.3, 0.05], [2.0, 0.52, 0.30]))
|
||||
self.long_deviation = float(interp(accel, [-0.3, 0.1], [0.0, 0.20]))
|
||||
self.accel_last = accel
|
||||
|
||||
if blend_active and getattr(CC_IQ, "useRadarAccel", False) and CS.acc_radar_sta_adr == 1 and not self.radar_handler.failed:
|
||||
accel = float(np.clip(CS.acc_radar_sollbeschl, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX))
|
||||
self.long_jerklimit = CS.acc_radar_aendgrad
|
||||
self.long_deviation = CS.acc_radar_regelabw
|
||||
self.accel_last = accel
|
||||
|
||||
if self.CCS == mqbcan:
|
||||
can_sends.extend(self.CCS.create_acc_accel_control(
|
||||
self.packer_pt, self.CAN.pt, CS.acc_type, accel, acc_control, stopping, starting, CS.esp_hold_confirmation,
|
||||
@@ -435,10 +500,19 @@ class CarController(CarControllerBase):
|
||||
esp_starting_override=esp_starting_override, esp_stopping_override=esp_stopping_override,
|
||||
))
|
||||
else:
|
||||
can_sends.extend(self.CCS.create_acc_accel_control(
|
||||
self.packer_pt, self.CAN.pt, CS.acc_type, accel, acc_control, stopping, starting, CS.esp_hold_confirmation,
|
||||
self.long_deviation, self.long_jerklimit, eBrakeActive,
|
||||
))
|
||||
accel = apply_pq_stopping_accel(self.CP.carFingerprint, accel, stopping)
|
||||
|
||||
sng_ecd_enabled = bool(self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_SNG_ECD)
|
||||
low_speed = CS.out.vEgo <= self.CCP.SNG_HANDOFF_SPEED
|
||||
if sng_ecd_enabled and long_active and low_speed and accel <= 0.05 and not starting:
|
||||
self.sng_handoff_active = True
|
||||
else:
|
||||
self.sng_handoff_active = False
|
||||
sng_decel_req = float(np.clip(accel, self.CCP.ACCEL_MIN, self.CCP.SNG_HOLD_DECEL_MAX)) if self.sng_handoff_active else 0.0
|
||||
|
||||
can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, self.CAN.pt, CS.acc_type, accel, acc_control, stopping and not self.motor3_resuming, starting, CS.esp_hold_confirmation, self.long_deviation, self.long_jerklimit, eBrakeActive, sng_active=self.sng_handoff_active))
|
||||
if sng_ecd_enabled:
|
||||
can_sends.append(self.CCS.create_sng_handoff_control(self.packer_pt, self.CAN.aux, self.sng_handoff_active, sng_decel_req))
|
||||
|
||||
if (self.CP.flags & VolkswagenFlags.DISABLE_RADAR) and self.CP.openpilotLongitudinalControl and not CS.out.radarDisableFailed:
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
@@ -468,15 +542,16 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self.CAN.pt, CS.ldw_stock_values, CC.latActive, CS.out.steeringPressed,
|
||||
hud_alert, hud_control, sound_alert))
|
||||
else:
|
||||
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self.CAN.pt, CS.ldw_stock_values, CC.latActive, steering_pressed_hud,
|
||||
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self._pt_tx_bus, CS.ldw_stock_values, CC.latActive, steering_pressed_hud,
|
||||
hud_alert, hud_control, self.entering, self.CCS is pqcan and AngleLateralControl, self.active))
|
||||
|
||||
if hud_control.leadDistanceBars != self.lead_distance_bars_last:
|
||||
self.distance_bar_frame = self.frame
|
||||
|
||||
if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.CP.openpilotLongitudinalControl and not CS.out.radarDisableFailed:
|
||||
if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.CP.openpilotLongitudinalControl:
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
d_unresponsive = hud_control.driverUnresponsive
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
show_distance_bars = self.frame - self.distance_bar_frame < 400
|
||||
gap = max(8, CS.out.vEgo * hud_control.leadFollowTime)
|
||||
distance = max(8, hud_control.leadDistance) if hud_control.leadDistance != 0 else 0
|
||||
@@ -498,23 +573,29 @@ class CarController(CarControllerBase):
|
||||
CS.esp_hold_confirmation, distance, gap, fcw_alert, acc_hud_event, speed_limit))
|
||||
else:
|
||||
leadDistance = min(8, hud_control.leadDistance) if hud_control.leadDistance != 0 else 0
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
self.leadDistanceBars = min(3, hud_control.leadDistanceBars)
|
||||
acc_hud_status = self.CCS.acc_hud_status_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive, CC.cruiseControl.override)
|
||||
set_speed = hud_control.setSpeed * CV.MS_TO_KPH
|
||||
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, self.CAN.pt, acc_hud_status, set_speed,
|
||||
leadDistance, self.leadDistanceBars, fcw_alert, hud_control.leadVisible))
|
||||
decel = dVisual(self.CCS, CS)
|
||||
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, self.CAN.pt, acc_hud_status, set_speed, leadDistance, self.leadDistanceBars, fcw_alert, hud_control.leadVisible, self.unavailable, decel, d_unresponsive))
|
||||
|
||||
if self.CP.flags & VolkswagenFlags.PQ:
|
||||
if self.frame % 2 == 0:
|
||||
self.blinkerActive = CS.leftBlinkerUpdate or CS.rightBlinkerUpdate
|
||||
leftBlinker = CC.leftBlinker if not self.blinkerActive else False
|
||||
rightBlinker = CC.rightBlinker if not self.blinkerActive else False
|
||||
can_sends.append(self.CCS.create_blinker_control(self.packer_pt, self.CAN.pt, leftBlinker, rightBlinker))
|
||||
iq_lvbs_commander.update_turn_signals(self, CC, CS, can_sends)
|
||||
|
||||
if self.CP.openpilotLongitudinalControl and (self.CP.flags & VolkswagenFlags.PQ):
|
||||
if self.frame % 2 == 0:
|
||||
if blend_active:
|
||||
can_sends.extend(self.radar_handler.update(
|
||||
self.packer_pt, self.frame, CS,
|
||||
blend_active=True,
|
||||
engage_req=getattr(CC_IQ, "radarEngageReq", False),
|
||||
cancel_req=getattr(CC_IQ, "radarCancelReq", False),
|
||||
set_speed_kph=getattr(CC_IQ, "radarSetSpeedKph", 0.0),
|
||||
gap_bars=getattr(CC_IQ, "radarGapBars", 0),
|
||||
v_ego=CS.out.vEgo,
|
||||
))
|
||||
elif self.frame % 2 == 0:
|
||||
can_sends.append(self.CCS.filter_motor2(self.packer_pt, self.CAN.ext, CS.motor2_stock))
|
||||
can_sends.append(self.CCS.filter_motor5(self.packer_pt, self.CAN.ext, CS.motor5_stock))
|
||||
|
||||
gra_send_ready = self.CP.pcmCruise and CS.gra_stock_values["COUNTER"] != self.gra_acc_counter_last
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
@@ -526,15 +607,25 @@ class CarController(CarControllerBase):
|
||||
stock_cancel_pressed = bool(CS.gra_stock_values["GRA_Abbrechen"])
|
||||
|
||||
cancel_cmd = stock_cancel_pressed or CC.cruiseControl.cancel
|
||||
if gra_send_ready and (cancel_cmd or CC.cruiseControl.resume):
|
||||
resume_cmd = CC.cruiseControl.resume or self._should_spam_mqb_a0_resume(CS, iq_mqb_acc_resume)
|
||||
if gra_send_ready and (cancel_cmd or resume_cmd):
|
||||
bus_send = self.CAN.aux if self.CP.flags & VolkswagenFlags.PQ else self.CAN.ext
|
||||
can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, bus_send, CS.gra_stock_values,
|
||||
cancel=cancel_cmd, resume=CC.cruiseControl.resume))
|
||||
cancel=cancel_cmd, resume=resume_cmd))
|
||||
|
||||
if self.CP.openpilotLongitudinalControl and self.CCS == pqcan:
|
||||
if self.CP.openpilotLongitudinalControl and self.CCS == pqcan and not blend_active:
|
||||
if self.frame % 3:
|
||||
can_sends.append(self.CCS.create_gra_neu(self.packer_pt, self.CAN.ext, CS.gra_stock_values, CC.longActive))
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
is_stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
if CS.out.vEgo > 0.5 or not CC.longActive:
|
||||
self.motor3_resuming = False
|
||||
elif (self.motor3_was_stopping and not is_stopping and self.CP.openpilotLongitudinalControl and CC.longActive):
|
||||
self.motor3_resuming = True
|
||||
if self.motor3_resuming and CS.motor3_stock:
|
||||
can_sends.append(self.CCS.create_motor3_resume(self.packer_pt, self.CAN.aux, CS.motor1_stock, CS.motor3_stock, resume=True))
|
||||
self.motor3_was_stopping = is_stopping
|
||||
|
||||
new_actuators = actuators.as_builder()
|
||||
new_actuators.torque = self.apply_torque_last / self.CCP.STEER_MAX
|
||||
@@ -547,5 +638,6 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.lead_distance_bars_last = hud_control.leadDistanceBars
|
||||
self.gra_acc_counter_last = CS.gra_stock_values["COUNTER"]
|
||||
self.motor3_frame_last = CS.motor3_frame
|
||||
self.frame += 1
|
||||
return new_actuators, can_sends
|
||||
|
||||
@@ -12,7 +12,10 @@ from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.volkswagen.values import CAR, DBC, CanBus, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType, GearShifter, \
|
||||
CarControllerParams, VolkswagenFlags, VolkswagenFlagsIQ
|
||||
from iqdbc.car.volkswagen.speed_limit_manager import SpeedLimitManager
|
||||
from openpilot.iqpilot.konn3kt.iqlvbs import alc as iq_lvbs_alc
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
iq_lvbs_alc = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.alc")
|
||||
vehicle_state = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.vehicle_state")
|
||||
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
sys.path.insert(0, iqpilot_path)
|
||||
@@ -45,6 +48,14 @@ class CarState(CarStateBase):
|
||||
self.ea_hud_stock_values = {}
|
||||
self.ea_control_stock_values = {}
|
||||
self.acc_type = 0
|
||||
self.acc_radar_sollbeschl = 0.0
|
||||
self.acc_radar_regelabw = 0.0
|
||||
self.acc_radar_aendgrad = 0.0
|
||||
self.acc_radar_sta_adr = 0
|
||||
self.acc_radar_fehler = False
|
||||
self.acc_radar_v_wunsch = 0.0
|
||||
self.acc_radar_sta_acc = 0
|
||||
self.epb_freigabe_ver = False
|
||||
self.acc_stock_counters: dict[str, int] = {}
|
||||
self.esp_stopping = False
|
||||
self.tsk_brake_torque = 0.0
|
||||
@@ -85,7 +96,20 @@ class CarState(CarStateBase):
|
||||
self.PQ_ALC_Status_raw = 0
|
||||
self.alcOverrideAlert = False
|
||||
self.bremse8_stock = None
|
||||
self.br8_acc_anf = False
|
||||
self.tsk_verzoeg_anf = False
|
||||
self.cruise_main_switch = False
|
||||
self.motor3_stock = {}
|
||||
self.motor1_stock = {}
|
||||
self.motor3_frame = 0
|
||||
self.motor1_frame = 0
|
||||
self._odometer_store = vehicle_state.VehicleOdometerStore(CP, self._params)
|
||||
|
||||
def _update_odometer(self, ret: structs.CarState, raw_km: float) -> None:
|
||||
"""Publish the cluster value while proprietary Konn3kt code owns persistence."""
|
||||
odometer_km = self._odometer_store.record(raw_km)
|
||||
if odometer_km is not None:
|
||||
ret.odometer = odometer_km
|
||||
|
||||
def _apply_iq_private_flags(self, ret_iq: structs.IQCarState) -> None:
|
||||
ret_iq.alcOverrideAlert = bool(self.alcOverrideAlert)
|
||||
@@ -117,6 +141,9 @@ class CarState(CarStateBase):
|
||||
def _update_mqb_iq_alc_state(self, pt_cp):
|
||||
iq_lvbs_alc.update_mqb_carstate_alc_state(self, pt_cp)
|
||||
|
||||
def _update_mlb_iq_alc_state(self, pt_cp):
|
||||
iq_lvbs_alc.update_mlb_carstate_alc_state(self, pt_cp)
|
||||
|
||||
def _update_pq_iq_alc_state(self, pt_cp):
|
||||
iq_lvbs_alc.update_pq_carstate_alc_state(self, pt_cp)
|
||||
|
||||
@@ -126,7 +153,8 @@ class CarState(CarStateBase):
|
||||
ext_cp = pt_cp if self.CP.networkLocation == NetworkLocation.fwdCamera else cam_cp
|
||||
|
||||
if self.CP.flags & VolkswagenFlags.PQ:
|
||||
return self.update_pq(pt_cp, cam_cp, ext_cp)
|
||||
aux_cp = can_parsers.get(Bus.aux)
|
||||
return self.update_pq(pt_cp, cam_cp, ext_cp, aux_cp)
|
||||
elif self.CP.flags & VolkswagenFlags.MLB:
|
||||
br_cp = can_parsers[Bus.aux]
|
||||
return self.update_mlb(pt_cp, br_cp, cam_cp, ext_cp)
|
||||
@@ -218,6 +246,7 @@ class CarState(CarStateBase):
|
||||
self.grade = pt_cp.vl["Motor_16"]["TSK_Steigung"]
|
||||
acc_limiter_mode = False if cc_only else ext_cp.vl["ACC_02"]["ACC_Gesetzte_Zeitluecke"] == 0
|
||||
speed_limiter_mode = bool(pt_cp.vl["TSK_06"]["TSK_Limiter_ausgewaehlt"])
|
||||
self.tsk_verzoeg_anf = bool(pt_cp.vl["TSK_06"]["TSK_Freig_Verzoeg_Anf"])
|
||||
|
||||
self._update_mqb_iq_alc_state(pt_cp)
|
||||
|
||||
@@ -256,12 +285,15 @@ class CarState(CarStateBase):
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
|
||||
ret.lowSpeedAlert = self.update_low_speed_alert(ret.vEgo)
|
||||
ret.cruiseFaultLateralMode = False
|
||||
ret.lateralAvailable = ret.cruiseState.available
|
||||
ret.blockPcmEnable = False
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable") and self._params.get_bool("AolEnabled")
|
||||
cruise_main_switch = bool(self.gra_stock_values["GRA_Hauptschalter"])
|
||||
ret.cruiseFaultLateralMode = allow_lat_only and ret.accFaulted and cruise_main_switch
|
||||
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
|
||||
ret.blockPcmEnable = ret.cruiseFaultLateralMode
|
||||
|
||||
ret.fuelGauge = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0
|
||||
ret.fuelTankLevelL = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] # raw liters for konn3kt
|
||||
self._update_odometer(ret, pt_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
|
||||
|
||||
self.cruise_faulted = ret.accFaulted
|
||||
self._apply_iq_private_flags(ret_iq)
|
||||
@@ -340,19 +372,11 @@ class CarState(CarStateBase):
|
||||
|
||||
self.ldw_stock_values = cam_cp.vl["LDW_02"]
|
||||
|
||||
if not (self.CP.flags & VolkswagenFlags.DISABLE_RADAR):
|
||||
awv_values = ext_cp.vl.get("AWV_03", ext_cp.vl.get("ACC_10", {}))
|
||||
ret.stockFcw = bool(awv_values.get("FCW_Active", 0)) or bool(awv_values.get("AWV2_Freigabe", 0))
|
||||
else:
|
||||
ret.stockFcw = False
|
||||
awv_values = ext_cp.vl.get("AWV_03", ext_cp.vl.get("ACC_10", {}))
|
||||
ret.stockFcw = bool(awv_values.get("FCW_Active", 0)) or bool(awv_values.get("AWV2_Freigabe", 0))
|
||||
ret.stockAeb = False
|
||||
|
||||
# Camera harness (DISABLE_RADAR): ext_cp == pt_cp, so ACC_18 reads our own sent value.
|
||||
# Hardcode acc_type=2 (stop-and-go capable) to avoid self-referential read on first frame.
|
||||
if self.CP.flags & VolkswagenFlags.DISABLE_RADAR:
|
||||
self.acc_type = 2
|
||||
else:
|
||||
self.acc_type = ext_cp.vl["ACC_18"]["ACC_Typ"]
|
||||
self.acc_type = ext_cp.vl["ACC_18"]["ACC_Typ"]
|
||||
self.travel_assist_available = bool(pt_cp.vl.get("TA_01", {}).get("Travel_Assist_Available", 0))
|
||||
|
||||
ret.cruiseState.available = pt_cp.vl["Motor_51"]["TSK_Status"] in (2, 3, 4, 5)
|
||||
@@ -385,6 +409,7 @@ class CarState(CarStateBase):
|
||||
psd_06_values = main_cp.vl["PSD_06"] if self.CP.flags & VolkswagenFlags.STOCK_PSD_PRESENT else {}
|
||||
psd_06_values = pt_cp.vl["PSD_06"] if not psd_06_values and self.CP.flags & VolkswagenFlags.STOCK_PSD_06_PRESENT else psd_06_values
|
||||
diagnose_01_values = pt_cp.vl["Diagnose_01"] if self.CP.flags & VolkswagenFlags.STOCK_DIAGNOSE_01_PRESENT else {}
|
||||
self._update_odometer(ret, pt_cp.vl["Diagnose_01"]["KBI_Kilometerstand"])
|
||||
|
||||
if self.enable_speed_limit_predicative and not self.enable_predicative_speed_limit:
|
||||
self.enable_predicative_speed_limit = True
|
||||
@@ -409,10 +434,8 @@ class CarState(CarStateBase):
|
||||
ret.espDisabled = bool(pt_cp.vl["ESP_21"]["ESP_Tastung_passiv"])
|
||||
ret.espActive = bool(pt_cp.vl["ESP_21"]["ESP_Eingriff"])
|
||||
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable")
|
||||
cruise_main_switch = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Hauptschalter"])
|
||||
cruise_fault_candidate = allow_lat_only and ret.accFaulted and cruise_main_switch
|
||||
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable") and self._params.get_bool("AolEnabled")
|
||||
cruise_fault_candidate = allow_lat_only and ret.accFaulted and bool(pt_cp.vl["GRA_ACC_01"]["GRA_Hauptschalter"])
|
||||
if cruise_fault_candidate:
|
||||
self.cruise_faulted_frames += 1
|
||||
self.cruise_fault_clear_frames = 0
|
||||
@@ -426,12 +449,10 @@ class CarState(CarStateBase):
|
||||
self.cruise_fault_lateral_active = False
|
||||
else:
|
||||
self.cruise_fault_clear_frames = 0
|
||||
|
||||
if not allow_lat_only:
|
||||
self.cruise_fault_lateral_active = False
|
||||
self.cruise_faulted_frames = 0
|
||||
self.cruise_fault_clear_frames = 0
|
||||
|
||||
ret.cruiseFaultLateralMode = self.cruise_fault_lateral_active
|
||||
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
|
||||
ret.blockPcmEnable = ret.cruiseFaultLateralMode
|
||||
@@ -461,9 +482,10 @@ class CarState(CarStateBase):
|
||||
self._apply_iq_private_flags(ret_iq)
|
||||
return ret, ret_iq
|
||||
|
||||
def update_pq(self, pt_cp, cam_cp, ext_cp) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
def update_pq(self, pt_cp, cam_cp, ext_cp, aux_cp=None) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
ret = structs.CarState()
|
||||
ret_iq = structs.IQCarState()
|
||||
sng_ecd_enabled = bool(self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_SNG_ECD)
|
||||
|
||||
# vEgo obtained from Bremse_1 vehicle speed rather than Bremse_3 wheel speeds because Bremse_3 isn't present on NSF
|
||||
ret.vEgoRaw = pt_cp.vl["Bremse_1"]["BR1_Rad_kmh"] * CV.KPH_TO_MS
|
||||
@@ -476,7 +498,7 @@ class CarState(CarStateBase):
|
||||
ret.steeringTorque = pt_cp.vl["Lenkhilfe_3"]["LH3_LM"] * (1, -1)[int(pt_cp.vl["Lenkhilfe_3"]["LH3_LMSign"])]
|
||||
ret.steeringPressed = abs(ret.steeringTorque) > self.CCP.STEER_DRIVER_ALLOWANCE
|
||||
hca_status = self.CCP.hca_status_values.get(pt_cp.vl["Lenkhilfe_2"]["LH2_Sta_HCA"])
|
||||
ret.steerFaultTemporary, ret.steerFaultPermanent = self.update_hca_state(hca_status)
|
||||
ret.steerFaultTemporary, ret.steerFaultPermanent = self.update_hca_state(hca_status, ready_confirms_init=False)
|
||||
|
||||
# Update gas, brakes, and gearshift.
|
||||
ret.gasPressed = pt_cp.vl["Motor_3"]["MO3_Pedalwert"] > 0
|
||||
@@ -511,8 +533,11 @@ class CarState(CarStateBase):
|
||||
# Consume blind-spot monitoring info/warning LED states, if available.
|
||||
# Infostufe: BSM LED on, Warnung: BSM LED flashing
|
||||
if self.CP.enableBsm:
|
||||
ret.leftBlindspot = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_li"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_li"])
|
||||
ret.rightBlindspot = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_re"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_re"])
|
||||
blindspot_li = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_li"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_li"])
|
||||
blindspot_re = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_re"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_re"])
|
||||
force_rhd = self.force_rhd_for_bsm or self._params.get_bool("ForceRHDForBSM")
|
||||
ret.leftBlindspot = blindspot_re if force_rhd else blindspot_li
|
||||
ret.rightBlindspot = blindspot_li if force_rhd else blindspot_re
|
||||
|
||||
# Consume factory LDW data relevant for factory SWA (Lane Change Assist)
|
||||
# and capture it for forwarding to the blind spot radar controller
|
||||
@@ -532,16 +557,18 @@ class CarState(CarStateBase):
|
||||
# Update ACC radar status.
|
||||
self.acc_type = 0 if cc_only else ext_cp.vl["ACC_System"]["ACS_Typ_ACC"]
|
||||
cruise_main_switch = bool(pt_cp.vl["Motor_5"]["MO5_GRA_Hauptsch"])
|
||||
cruise_tsk_status = bool(pt_cp.vl["Motor_2"]["MO2_Status_TSK"])
|
||||
self.cruise_main_switch = cruise_main_switch or cruise_tsk_status
|
||||
self.cruise_main_switch = cruise_main_switch
|
||||
MO2_StaGRA = pt_cp.vl["Motor_2"]["MO2_Sta_GRA"] in (1, 2)
|
||||
ACS_StaADR = False if cc_only else ext_cp.vl["ACC_System"]["ACS_Sta_ADR"] == 1
|
||||
cruiseActive = MO2_StaGRA or ACS_StaADR
|
||||
if cruiseActive:
|
||||
self.epb_freigabe_ver = bool(aux_cp.vl["EPB_1"]["EP1_Freigabe_Ver"]) if sng_ecd_enabled and not cc_only else False
|
||||
sng_holding = sng_ecd_enabled and self.epb_freigabe_ver
|
||||
if cruiseActive or sng_holding:
|
||||
self.last_cruiseActive = True
|
||||
elif not MO2_StaGRA and not ACS_StaADR:
|
||||
elif not MO2_StaGRA and not ACS_StaADR and not sng_holding:
|
||||
self.last_cruiseActive = False
|
||||
ret.cruiseState.enabled = self.last_cruiseActive
|
||||
self.br8_acc_anf = bool(pt_cp.vl["Bremse_8"]["BR8_Sta_ACC_Anf"]) if not cc_only else False
|
||||
|
||||
if self.CP.pcmCruise:
|
||||
if cc_only:
|
||||
@@ -552,9 +579,9 @@ class CarState(CarStateBase):
|
||||
cruise_faulted = pt_cp.vl["Motor_2"]["MO2_Sta_GRA"] == 3
|
||||
|
||||
ret.accFaulted = cruise_faulted
|
||||
ret.cruiseState.available = (cruise_main_switch or cruise_tsk_status) and not cruise_faulted
|
||||
ret.cruiseState.available = cruise_main_switch and not cruise_faulted
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable") and self._params.get_bool("AolEnabled")
|
||||
cruise_main_available = cruise_main_switch or cruise_tsk_status
|
||||
cruise_main_available = cruise_main_switch
|
||||
ret.cruiseFaultLateralMode = allow_lat_only and cruise_faulted and cruise_main_available
|
||||
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
|
||||
ret.blockPcmEnable = ret.cruiseFaultLateralMode
|
||||
@@ -571,6 +598,33 @@ class CarState(CarStateBase):
|
||||
ret.cruiseState.speed = 0
|
||||
|
||||
self.motor2_stock = pt_cp.vl["Motor_2"]
|
||||
self.motor5_stock = pt_cp.vl["Motor_5"]
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
self.motor3_stock = aux_cp.vl["Motor_3"]
|
||||
self.motor1_stock = aux_cp.vl["Motor_1"]
|
||||
self.motor3_frame += 1
|
||||
self.motor1_frame += 1
|
||||
|
||||
if cc_only:
|
||||
self.acc_radar_sollbeschl = 0.0
|
||||
self.acc_radar_regelabw = 0.0
|
||||
self.acc_radar_aendgrad = 0.0
|
||||
self.acc_radar_sta_adr = 0
|
||||
self.acc_radar_fehler = False
|
||||
self.acc_radar_v_wunsch = 0.0
|
||||
self.acc_radar_sta_acc = 0
|
||||
else:
|
||||
self.acc_radar_sollbeschl = ext_cp.vl["ACC_System"]["ACS_Sollbeschl"]
|
||||
self.acc_radar_regelabw = ext_cp.vl["ACC_System"]["ACS_zul_Regelabw"]
|
||||
self.acc_radar_aendgrad = ext_cp.vl["ACC_System"]["ACS_max_AendGrad"]
|
||||
self.acc_radar_sta_adr = int(ext_cp.vl["ACC_System"]["ACS_Sta_ADR"])
|
||||
self.acc_radar_fehler = bool(ext_cp.vl["ACC_System"]["ACS_Fehler"])
|
||||
self.acc_radar_v_wunsch = ext_cp.vl["ACC_GRA_Anzeige"]["ACA_V_Wunsch"]
|
||||
self.acc_radar_sta_acc = int(ext_cp.vl["ACC_GRA_Anzeige"]["ACA_StaACC"])
|
||||
|
||||
ret_iq.accRadarStaAdr = self.acc_radar_sta_adr
|
||||
ret_iq.accRadarFehler = self.acc_radar_fehler
|
||||
|
||||
# Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough
|
||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk(300, pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_li"],
|
||||
@@ -587,6 +641,13 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.fuelGauge = pt_cp.vl["Kombi_1"]["Tankinhalt"] / 55.0
|
||||
ret.fuelTankLevelL = pt_cp.vl["Kombi_1"]["Tankinhalt"] # raw liters for konn3kt
|
||||
if aux_cp is not None:
|
||||
self._update_odometer(ret, aux_cp.vl["Kombi_3"]["Kilometerstand"])
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
ret.cruiseState.standstill = self.CP.pcmCruise and bool(pt_cp.vl["Bremse_5"]["BR5_Stillstand"]) and ret.cruiseState.enabled
|
||||
elif sng_ecd_enabled:
|
||||
ret.cruiseState.standstill = sng_holding and ret.standstill
|
||||
|
||||
self.cruise_faulted = ret.accFaulted
|
||||
self.frame += 1
|
||||
@@ -623,6 +684,7 @@ class CarState(CarStateBase):
|
||||
ret.accFaulted = pt_cp.vl["TSK_02"]["TSK_Status"] in (3,)
|
||||
|
||||
self.parse_mlb_mqb_steering_state(ret, pt_cp)
|
||||
self._update_mlb_iq_alc_state(pt_cp)
|
||||
|
||||
ret.brake = pt_cp.vl["ESP_05"]["ESP_Bremsdruck"] / 250.0
|
||||
brake_pedal_pressed = bool(pt_cp.vl["Motor_03"]["MO_Fahrer_bremst"])
|
||||
@@ -656,6 +718,7 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.fuelGauge = br_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0
|
||||
ret.fuelTankLevelL = br_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] # raw liters for konn3kt
|
||||
self._update_odometer(ret, br_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
|
||||
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
|
||||
@@ -688,10 +751,11 @@ class CarState(CarStateBase):
|
||||
ret.steerFaultTemporary, ret.steerFaultPermanent = self.update_hca_state(hca_status, drive_mode)
|
||||
return
|
||||
|
||||
def update_hca_state(self, hca_status, drive_mode=True):
|
||||
def update_hca_state(self, hca_status, drive_mode=True, ready_confirms_init=True):
|
||||
# Treat FAULT as temporary for worst likely EPS recovery time, for cars without factory Lane Assist
|
||||
# DISABLED means the EPS hasn't been configured to support Lane Assist
|
||||
self.eps_init_complete = self.eps_init_complete or (hca_status in ("DISABLED", "READY", "ACTIVE") or self.frame > 600)
|
||||
init_statuses = ("DISABLED", "READY", "ACTIVE") if ready_confirms_init else ("DISABLED", "ACTIVE")
|
||||
self.eps_init_complete = self.eps_init_complete or hca_status in init_statuses or self.frame > 1000
|
||||
perm_fault = drive_mode and hca_status == "DISABLED" or (self.eps_init_complete and hca_status == "FAULT")
|
||||
temp_fault = drive_mode and hca_status in ("REJECTED", "PREEMPTED") or not self.eps_init_complete
|
||||
return temp_fault, perm_fault
|
||||
@@ -743,8 +807,11 @@ class CarState(CarStateBase):
|
||||
]
|
||||
if CP.flags & VolkswagenFlags.MLB:
|
||||
pt_messages += [
|
||||
("Blinkmodi_01", math.nan) # From J519 BCM (is inactive when no lights active, 50Hz when active)
|
||||
("Blinkmodi_01", math.nan), # From J519 BCM (is inactive when no lights active, 50Hz when active)
|
||||
("Kombi_02", math.nan), # Auxiliary-bus cluster odometer
|
||||
]
|
||||
else:
|
||||
pt_messages += [("Kombi_02", math.nan)] # Auxiliary-bus cluster odometer
|
||||
if CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
|
||||
cam_messages += [
|
||||
("HCA_01", 1), # From R242 Driver assistance camera, 50Hz if steering/1Hz if not
|
||||
@@ -758,8 +825,12 @@ class CarState(CarStateBase):
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers_pq(CP):
|
||||
aux_messages = [("Kombi_3", math.nan)] # Bus 1 cluster odometer
|
||||
if CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
aux_messages.append(("Motor_3", 0))
|
||||
return {
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).powertrain),
|
||||
Bus.aux: CANParser(DBC[CP.carFingerprint][Bus.pt], aux_messages, CanBus(CP).aux),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).cam),
|
||||
}
|
||||
|
||||
@@ -771,14 +842,13 @@ class CarState(CarStateBase):
|
||||
# TA_01 lives on bus 0 (car ECU / OP-generated when long is active).
|
||||
# math.nan → ignore_alive=True so it never contributes to can_valid.
|
||||
("TA_01", math.nan),
|
||||
("Diagnose_01", math.nan), # Bus 0 cluster odometer
|
||||
]
|
||||
# AWV_03 (stock radar FCW/AEB) — don't subscribe when DISABLE_RADAR, the radar is silenced
|
||||
# and our carcontroller sends the replacement. Subscribing causes CAN parser timeout errors.
|
||||
if CP.networkLocation == NetworkLocation.fwdCamera and not (CP.flags & VolkswagenFlags.DISABLE_RADAR):
|
||||
if CP.networkLocation == NetworkLocation.fwdCamera:
|
||||
pt_messages.append(("AWV_03", 1))
|
||||
|
||||
cam_messages = []
|
||||
if CP.networkLocation == NetworkLocation.gateway and not (CP.flags & VolkswagenFlags.DISABLE_RADAR):
|
||||
if CP.networkLocation == NetworkLocation.gateway:
|
||||
cam_messages.append(("AWV_03", 1))
|
||||
|
||||
return {
|
||||
|
||||
@@ -681,6 +681,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x873QF907572A \xf1\x890132',
|
||||
],
|
||||
},
|
||||
CAR.VOLKSWAGEN_PASSAT_B7: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8703L906018RE\xf1\x899979',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x74f, None): [
|
||||
b'\xf1\x873AA980654D \xf1\x890300\xf1\x82\x0143',
|
||||
],
|
||||
},
|
||||
CAR.VOLKSWAGEN_POLO_MK6: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8704C906025H \xf1\x895177',
|
||||
@@ -716,6 +724,17 @@ FW_VERSIONS = {
|
||||
b'\xf1\x877N0907572C \xf1\x890211\xf1\x82\x0153',
|
||||
],
|
||||
},
|
||||
CAR.SEAT_ALHAMBRA_MK1: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8704L906016HE\xf1\x894635',
|
||||
],
|
||||
(Ecu.srs, 0x715, None): [
|
||||
b'\xf1\x877N0959655D \xf1\x890016\xf1\x82\x0801100705----10--',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x757, None): [
|
||||
b'\xf1\x877N0907572C \xf1\x890211\xf1\x82\x0153',
|
||||
],
|
||||
},
|
||||
CAR.VOLKSWAGEN_TAOS_MK1: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8704E906025CK\xf1\x892228',
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import time
|
||||
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car import get_safety_config, structs, uds
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
from iqdbc.car.isotp_parallel_query import IsoTpParallelQuery
|
||||
from iqdbc.car.volkswagen.carcontroller import CarController
|
||||
from iqdbc.car.volkswagen.carstate import CarState
|
||||
from iqdbc.car.volkswagen.values import CanBus, CAR, DashcamOnlyReason, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType, VolkswagenFlags, VolkswagenSafetyFlags, VolkswagenFlagsIQ
|
||||
from iqdbc.car.volkswagen.values import (
|
||||
CAR, CanBus, DashcamOnlyReason, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType,
|
||||
VolkswagenFlags, VolkswagenSafetyFlags, VolkswagenFlagsIQ, get_longitudinal_stopping_speed_override,
|
||||
)
|
||||
from iqdbc.car.volkswagen.radar_interface import RadarInterface
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
import sys
|
||||
import os
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
@@ -19,6 +20,11 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
except Exception:
|
||||
import_verified_module = None
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
CarState = CarState
|
||||
@@ -39,9 +45,16 @@ class CarInterface(CarInterfaceBase):
|
||||
if ret.flags & VolkswagenFlags.PQ:
|
||||
# Set global PQ35/PQ46/NMS parameters
|
||||
safety_configs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenPq)]
|
||||
if candidate == CAR.SEAT_ALHAMBRA_MK1:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB.value
|
||||
if not (ret.flags & VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB) and _params.get_bool("VwPqEpsPatched"):
|
||||
ret.minSteerSpeed = 0
|
||||
if angle_lat_enabled:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_LVBS_ALC_MODULE.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_ALC_MODULE.value
|
||||
if alpha_long:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_SNG_ECD.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_SNG_ECD.value
|
||||
ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1
|
||||
|
||||
if 0x440 in fingerprint[0] or docs: # Getriebe_1
|
||||
@@ -59,6 +72,13 @@ class CarInterface(CarInterfaceBase):
|
||||
else:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_CC_ONLY_NO_RADAR.value
|
||||
|
||||
cc_only_flags = VolkswagenFlagsIQ.IQ_CC_ONLY | VolkswagenFlagsIQ.IQ_CC_ONLY_NO_RADAR
|
||||
if ret.flags & cc_only_flags:
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_NO_CAM_BUS.value
|
||||
if (ret.flags & cc_only_flags) and not fingerprint[0]:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_LOWLINE.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_LOWLINE.value
|
||||
|
||||
if any(msg in fingerprint[1] for msg in (0x1A0, 0xC2)): # Bremse_1, Lenkwinkel_1
|
||||
ret.networkLocation = NetworkLocation.gateway
|
||||
else:
|
||||
@@ -151,7 +171,7 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.steerLimitTimer = 0.4
|
||||
if ret.flags & VolkswagenFlags.PQ:
|
||||
ret.steerActuatorDelay = 0.2
|
||||
ret.longitudinalTuning.kfDEPRECATED = 1.2
|
||||
ret.longitudinalTuning.kf = 1.2
|
||||
ret.longitudinalTuning.kpBP = [0.]
|
||||
ret.longitudinalTuning.kpV = [.45]
|
||||
ret.longitudinalTuning.kiBP = [0.]
|
||||
@@ -164,19 +184,20 @@ class CarInterface(CarInterfaceBase):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
elif ret.flags & VolkswagenFlags.MLB:
|
||||
ret.steerActuatorDelay = 0.2
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
if angle_lat_enabled:
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
ret.steerAtStandstill = bool(joystick_mode)
|
||||
else:
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
elif ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
ret.steerActuatorDelay = 0.3
|
||||
else:
|
||||
ret.steerActuatorDelay = 0.1
|
||||
ret.lateralTuning.pid.kpBP = [0.]
|
||||
ret.lateralTuning.pid.kiBP = [0.]
|
||||
ret.lateralTuning.pid.kf = 0.00006
|
||||
ret.lateralTuning.pid.kpV = [0.6]
|
||||
ret.lateralTuning.pid.kiV = [0.2]
|
||||
if angle_lat_enabled:
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
ret.steerAtStandstill = bool(joystick_mode)
|
||||
else:
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
# Global longitudinal tuning defaults, can be overridden per-vehicle
|
||||
|
||||
@@ -200,17 +221,12 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate == CAR.PORSCHE_MACAN_MK1:
|
||||
ret.steerActuatorDelay = 0.07
|
||||
|
||||
if candidate == CAR.VOLKSWAGEN_PASSAT_B7 or CAR.SEAT_ALHAMBRA_MK1:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_ACC_FTS_EPB.value
|
||||
|
||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||
if ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
ret.startingState = True
|
||||
ret.startAccel = 0.8
|
||||
ret.vEgoStarting = 0.5
|
||||
ret.vEgoStopping = 0.1
|
||||
ret.stopAccel = -0.55
|
||||
else:
|
||||
ret.stopAccel = -0.55
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.vEgoStopping = 1.5 * CV.KPH_TO_MS if ret.flags & VolkswagenFlags.PQ else 0.1
|
||||
ret.stopAccel = -0.55
|
||||
ret.autoResumeSng = ret.minEnableSpeed == -1
|
||||
CAN = CanBus(fingerprint=fingerprint)
|
||||
if CAN.pt >= 4:
|
||||
@@ -221,10 +237,18 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def pre_init(CP: structs.CarParams, CP_IQ: structs.IQCarParams, can_recv, can_send):
|
||||
# Engine-on check moved to init(): if radar can't be disabled, radarDisableFailed=True
|
||||
# gates only long control (carcontroller line ~308) while lateral still works.
|
||||
# Full dashcam mode here was too aggressive — lateral doesn't need radar disabled.
|
||||
pass
|
||||
if not (CP.flags & VolkswagenFlags.PQ) or (CP.flags & VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB) or import_verified_module is None:
|
||||
return
|
||||
try:
|
||||
params = Params()
|
||||
if params.get_bool("VwPqEpsPatched"):
|
||||
return
|
||||
flasher = import_verified_module("iqpilot_hephaestusd_private", "iqpilot_private.konn3kt.hephaestus.vw_pq_flasher")
|
||||
status = flasher.check_eps_patch_status(1, can_recv, can_send)
|
||||
except Exception:
|
||||
return
|
||||
if status == "patched":
|
||||
params.put_bool("VwPqEpsPatched", True)
|
||||
|
||||
@staticmethod
|
||||
def init(CP: structs.CarParams, CP_IQ: structs.IQCarParams, can_recv, can_send):
|
||||
@@ -321,4 +345,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def _get_params_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams, candidate, fingerprint: dict[int, dict[int, int]], car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
|
||||
ret.longitudinalStoppingSpeedOverride = get_longitudinal_stopping_speed_override(candidate, stock_cp.flags)
|
||||
return ret
|
||||
|
||||
@@ -270,5 +270,5 @@ class LatControlCurvature():
|
||||
error = desired_curvature - actual_curvature
|
||||
freeze_integrator = CC.steerLimited or CS.vEgo < 5
|
||||
output_curvature = self.pid.update(error, feedforward=desired_curvature_corr, speed=CS.vEgo,
|
||||
freeze_integrator=freeze_integrator, override=False)
|
||||
freeze_integrator=freeze_integrator, override=CS.steeringPressed)
|
||||
return output_curvature
|
||||
|
||||
@@ -45,7 +45,7 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
return [packer.make_can_msg("ACC_05", bus, values)]
|
||||
|
||||
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible):
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
|
||||
values = {}
|
||||
return packer.make_can_msg("ACC_02", bus, values)
|
||||
|
||||
|
||||
@@ -114,10 +114,10 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
"ACC_Status_ACC": acc_control,
|
||||
"ACC_StartStopp_Info": acc_enabled,
|
||||
"ACC_Sollbeschleunigung_02": accel if acc_enabled else 3.01,
|
||||
"ACC_zul_Regelabw_unten": comfortBand if acc_enabled else 0.2,
|
||||
"ACC_zul_Regelabw_oben": comfortBand if acc_enabled else 0.2,
|
||||
"ACC_neg_Sollbeschl_Grad_02": jerkLimit if acc_enabled else 0,
|
||||
"ACC_pos_Sollbeschl_Grad_02": jerkLimit if acc_enabled else 0,
|
||||
"ACC_zul_Regelabw_unten": 0.2,
|
||||
"ACC_zul_Regelabw_oben": 0.2,
|
||||
"ACC_neg_Sollbeschl_Grad_02": 3.0 if acc_enabled else 0,
|
||||
"ACC_pos_Sollbeschl_Grad_02": 3.0 if acc_enabled else 0,
|
||||
"ACC_Anfahren": starting if acc_enabled else False,
|
||||
"ACC_Anhalten": stopping if acc_enabled else False,
|
||||
}
|
||||
@@ -149,12 +149,16 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
return commands
|
||||
|
||||
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible):
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
|
||||
priodisp = 0 if fcw_alert else 1 if (acc_hud_status == 4 or decel or leadVisible) else 2 if (acc_hud_status in (3, 2)) else 0
|
||||
leadDistanceBars = distanceBars + 1 if distanceBars in (1, 2, 3) else 2
|
||||
values = {
|
||||
"ACC_Status_Anzeige": acc_hud_status,
|
||||
"ACC_Wunschgeschw_02": set_speed if set_speed < 250 else 327.36,
|
||||
"ACC_Gesetzte_Zeitluecke": distanceBars,
|
||||
"ACC_Display_Prio": 3,
|
||||
"ACC_Gesetzte_Zeitluecke": leadDistanceBars,
|
||||
"ACC_Optischer_Fahrerhinweis": 1 if fcw_alert else 0,
|
||||
"ACC_Display_Prio": priodisp,
|
||||
"ACC_Relevantes_Objekt": leadDistanceBars,
|
||||
"ACC_Abstandsindex": leadDistance if leadVisible else 0,
|
||||
"ACC_Akustik_02": fcw_alert,
|
||||
}
|
||||
|
||||
106
iqdbc_repo/iqdbc/car/volkswagen/pq_radar_handler.py
Normal file
106
iqdbc_repo/iqdbc/car/volkswagen/pq_radar_handler.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos/
|
||||
"""
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.volkswagen import pqcan
|
||||
|
||||
|
||||
class PQRadarHandler:
|
||||
GRA_STEP = 3 # GRA_Neu cadence (~33 Hz), matches stock stalk module
|
||||
SPOOF_STEP = 2 # Motor_2 / Motor_5 spoof cadence (50 Hz)
|
||||
|
||||
ENGAGE_FLOOR = 1.0 * CV.KPH_TO_MS # never SET at/below 1 kph
|
||||
REENGAGE_FLOOR = 2.0 * CV.KPH_TO_MS # hysteresis: only (re)engage above 2 kph
|
||||
|
||||
SETSPEED_TOL_KPH = 1.0 # don't chase set-speed within this band
|
||||
SHORT_STEP_KPH = 1.0 * CV.MPH_TO_KPH # GRA_*_kurz ~= 1 mph
|
||||
LONG_STEP_KPH = 5.0 * CV.MPH_TO_KPH # GRA_*_lang ~= 5 mph
|
||||
TAP_RELEASE_CYCLES = 2 # GRA cycles to release between set-speed taps
|
||||
|
||||
def __init__(self, CAN):
|
||||
self.bus = CAN.ext # radar lives on bus 2 (ext/cam)
|
||||
self.counter = 0
|
||||
self.failed = False # ACS_Fehler / irrev_Fehler -> radar dead for the drive
|
||||
self.want_engaged = False # our belief the radar cruise should be on
|
||||
self._press_phase = 0 # alternate press/release for SET/cancel discrete edges
|
||||
self._tap_cooldown = 0 # set-speed tap rate limiter
|
||||
|
||||
def reset(self):
|
||||
self.want_engaged = False
|
||||
self._press_phase = 0
|
||||
self._tap_cooldown = 0
|
||||
|
||||
@staticmethod
|
||||
def _map_gap_bars(gap_bars):
|
||||
if not gap_bars:
|
||||
return None
|
||||
return int(min(3, max(1, gap_bars)))
|
||||
|
||||
def update(self, packer, frame, CS, *, blend_active, engage_req, cancel_req,
|
||||
set_speed_kph, gap_bars, v_ego):
|
||||
can_sends = []
|
||||
|
||||
if not blend_active:
|
||||
self.reset()
|
||||
return can_sends
|
||||
|
||||
if CS.acc_radar_fehler or CS.acc_radar_sta_adr == 3:
|
||||
self.failed = True
|
||||
|
||||
radar_active = (CS.acc_radar_sta_adr == 1) and not self.failed
|
||||
|
||||
if self.failed:
|
||||
self.want_engaged = False
|
||||
elif cancel_req:
|
||||
self.want_engaged = False
|
||||
elif engage_req and v_ego > self.REENGAGE_FLOOR:
|
||||
self.want_engaged = True
|
||||
|
||||
if (frame % self.SPOOF_STEP) == 0:
|
||||
# Mirror the stock engage handshake ORDER: the radar leads (SET -> ADR active) and only THEN
|
||||
# does the engine report GRA regulating. Asserting MO2_Sta_GRA=1 before the radar's ADR is
|
||||
# active presents an impossible state ("engine regulating but ADR didn't initiate it") and the
|
||||
# radar latches an irreversible fault. So only assert cruise-active once ADR is actually active;
|
||||
# relay Motor_5 (main switch) as verbatim OEM passthrough throughout.
|
||||
hold_engaged = self.want_engaged and radar_active
|
||||
can_sends.append(pqcan.filter_motor2(packer, self.bus, CS.motor2_stock, gra_active=hold_engaged))
|
||||
can_sends.append(pqcan.filter_motor5(packer, self.bus, CS.motor5_stock, gra_active=False))
|
||||
|
||||
if (frame % self.GRA_STEP) == 0:
|
||||
set_btn = resume_btn = cancel = up_s = down_s = up_l = down_l = False
|
||||
self._press_phase ^= 1
|
||||
pressing = self._press_phase == 0
|
||||
|
||||
if self.failed:
|
||||
pass
|
||||
elif cancel_req:
|
||||
# Only actually press cancel when the radar is engaged (or overdriven) -- otherwise it's a
|
||||
# no-op against a passive/off radar and just spams GRA_Abbrechen at ~16 Hz. Fires while
|
||||
# active and stops once the radar leaves the active state.
|
||||
cancel = pressing and radar_active
|
||||
elif self.want_engaged and not radar_active and v_ego > self.ENGAGE_FLOOR:
|
||||
# Engage with RESUME (GRA_Recall), not SET. Ground-truth from an OEM ACC engage (radar leads:
|
||||
# RESUME -> ACS_Sta_ADR 2->1 in ~90ms -> engine MO2_Sta_GRA 0->1 ~80ms later) shows this radar
|
||||
# engages from passive on GRA_Recall; it ignores GRA_Neu_Setzen from that state.
|
||||
resume_btn = pressing
|
||||
elif self.want_engaged and radar_active:
|
||||
if self._tap_cooldown > 0:
|
||||
self._tap_cooldown -= 1
|
||||
elif set_speed_kph > 0:
|
||||
delta = set_speed_kph - CS.acc_radar_v_wunsch
|
||||
if abs(delta) >= self.SETSPEED_TOL_KPH:
|
||||
big = abs(delta) >= self.LONG_STEP_KPH
|
||||
if delta > 0:
|
||||
up_l, up_s = big, not big
|
||||
else:
|
||||
down_l, down_s = big, not big
|
||||
self._tap_cooldown = self.TAP_RELEASE_CYCLES
|
||||
|
||||
self.counter = (self.counter + 1) % 16
|
||||
can_sends.append(pqcan.create_radar_gra(
|
||||
packer, self.bus, CS.gra_stock_values, self.counter,
|
||||
set_btn=set_btn, resume=resume_btn, cancel=cancel, up_short=up_s, down_short=down_s,
|
||||
up_long=up_l, down_long=down_l, zeitluecke=self._map_gap_bars(gap_bars),
|
||||
))
|
||||
|
||||
return can_sends
|
||||
@@ -1,3 +1,7 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos/
|
||||
"""
|
||||
|
||||
def create_hca_steering_control(packer, bus, apply_torque, HCA_Status):
|
||||
values = {
|
||||
"LM_Offset": abs(apply_torque),
|
||||
@@ -95,20 +99,20 @@ def acc_hud_status_value(main_switch_on, acc_faulted, longActive, longOverride):
|
||||
return hud_status
|
||||
|
||||
|
||||
def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping, starting, esp_hold, comfortBand, jerkLimit, eBrakeActive):
|
||||
def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping, starting, esp_hold, comfortBand, jerkLimit, eBrakeActive, sng_active=False):
|
||||
commands = []
|
||||
acc_enabled = acc_control == 1
|
||||
acc_enabled = acc_control == 1 and not sng_active
|
||||
|
||||
values = {
|
||||
"ACS_Sta_ADR": acc_control,
|
||||
"ACS_Sta_ADR": 0 if sng_active else acc_control,
|
||||
"ACS_StSt_Info": acc_enabled,
|
||||
"ACS_Typ_ACC": acc_type,
|
||||
"ACS_Anhaltewunsch": acc_type == 1 and stopping or eBrakeActive,
|
||||
"ACS_Anhaltewunsch": (acc_type == 1 and stopping or eBrakeActive) or sng_active,
|
||||
"ACS_FreigSollB": acc_enabled,
|
||||
"ACS_Sollbeschl": accel if acc_enabled else 3.01,
|
||||
"ACS_zul_Regelabw": comfortBand if acc_enabled else 1.27,
|
||||
"ACS_max_AendGrad": jerkLimit if acc_enabled else 5.08,
|
||||
"ACS_Schubabsch": 1 if acc_enabled and (accel > 0.05) else 0,
|
||||
"ACS_Schubabsch": 0,
|
||||
"ACS_MomEingriff": 0,
|
||||
"ACS_ADR_Schub": 0,
|
||||
}
|
||||
@@ -118,6 +122,14 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
return commands
|
||||
|
||||
|
||||
def create_sng_handoff_control(packer, bus, handoff_active, decel_req):
|
||||
values = {
|
||||
"SNG_HandoffActive": handoff_active,
|
||||
"SNG_DecelReq": decel_req if handoff_active else 0.0,
|
||||
}
|
||||
return packer.make_can_msg("SNG_1", bus, values)
|
||||
|
||||
|
||||
def create_blinker_control(packer, bus, leftBlinker, rightBlinker):
|
||||
values = {
|
||||
"BM_rechts": rightBlinker,
|
||||
@@ -126,29 +138,71 @@ def create_blinker_control(packer, bus, leftBlinker, rightBlinker):
|
||||
return packer.make_can_msg("Blinkmodi_02", bus, values)
|
||||
|
||||
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible):
|
||||
if distanceBars == 1:
|
||||
leadDistanceBars = 2
|
||||
elif distanceBars == 2:
|
||||
leadDistanceBars = 3
|
||||
elif distanceBars == 3:
|
||||
leadDistanceBars = 4
|
||||
else:
|
||||
leadDistanceBars = 2
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
|
||||
priodisp = 0 if fcw_alert else 1 if (acc_hud_status == 4 or decel or leadVisible) else 2 if (acc_hud_status in (3, 2)) else 0
|
||||
leadDistanceBars = distanceBars + 1 if distanceBars in (1, 2, 3) else 2
|
||||
values = {
|
||||
"ACA_StaACC": acc_hud_status,
|
||||
"ACA_AnzDisplay": 1 if acc_hud_status in (3, 4) else 0,
|
||||
"ACA_Zeitluecke": leadDistanceBars,
|
||||
"ACA_V_Wunsch": set_speed,
|
||||
"ACA_gemZeitl": min(15, max(1, int(round(leadDistance)))) if leadVisible else 0,
|
||||
"ACA_PrioDisp": 3,
|
||||
"ACA_PrioDisp": priodisp,
|
||||
"ACA_Akustik1": d_unresponsive,
|
||||
# "ACA_Fahrerhinw": unavailable,
|
||||
"ACA_Akustik2": fcw_alert,
|
||||
"ACA_ACC_Verz": decel,
|
||||
}
|
||||
|
||||
return packer.make_can_msg("ACC_GRA_Anzeige", bus, values)
|
||||
|
||||
def filter_motor2(packer, bus, motor2_stock):
|
||||
values = motor2_stock
|
||||
values.update({
|
||||
"MO2_Sta_GRA": 0,
|
||||
})
|
||||
def filter_motor2(packer, bus, motor2_stock, gra_active=False):
|
||||
values = dict(motor2_stock)
|
||||
if gra_active:
|
||||
values.update({
|
||||
"MO2_Sta_GRA": 1,
|
||||
"MO2_Status_TSK": 1,
|
||||
})
|
||||
else:
|
||||
values.update({
|
||||
"MO2_Sta_GRA": 0,
|
||||
})
|
||||
return packer.make_can_msg("Motor_2", bus, values)
|
||||
|
||||
|
||||
def filter_motor5(packer, bus, motor5_stock, gra_active=False):
|
||||
values = dict(motor5_stock)
|
||||
if gra_active:
|
||||
values["MO5_GRA_Hauptsch"] = 1
|
||||
return packer.make_can_msg("Motor_5", bus, values)
|
||||
|
||||
|
||||
def create_motor3_resume(packer, bus, motor1_stock, motor3_stock, resume=False):
|
||||
values = dict(motor3_stock)
|
||||
values_motor1 = dict(motor1_stock)
|
||||
if resume:
|
||||
values["MO3_Pedalwert"] = values_motor1["MO1_Pedalwert"]
|
||||
return packer.make_can_msg("Motor_3", bus, values)
|
||||
|
||||
|
||||
def create_radar_gra(packer, bus, gra_stock, counter, set_btn=False, cancel=False, resume=False,
|
||||
up_short=False, down_short=False, up_long=False, down_long=False, zeitluecke=None):
|
||||
values = {s: gra_stock[s] for s in [
|
||||
"GRA_Hauptschalt", # ACC main switch passthrough
|
||||
"GRA_Typ_Hauptschalt", # momentary vs latching
|
||||
"GRA_Kodierinfo", # configuration
|
||||
"GRA_Sender", # CAN originator
|
||||
]}
|
||||
values.update({
|
||||
"COUNTER": counter % 16,
|
||||
"GRA_Neu_Setzen": 1 if set_btn else 0,
|
||||
"GRA_Abbrechen": 1 if cancel else 0,
|
||||
"GRA_Recall": 1 if resume else 0,
|
||||
"GRA_Up_kurz": 1 if up_short else 0,
|
||||
"GRA_Down_kurz": 1 if down_short else 0,
|
||||
"GRA_Up_lang": 1 if up_long else 0,
|
||||
"GRA_Down_lang": 1 if down_long else 0,
|
||||
})
|
||||
if zeitluecke is not None:
|
||||
values["GRA_Zeitluecke"] = zeitluecke
|
||||
return packer.make_can_msg("GRA_Neu", bus, values)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from iqdbc.car.volkswagen import mqbcan, pqcan
|
||||
from iqdbc.car.volkswagen.carcontroller import CarController
|
||||
from iqdbc.car.volkswagen.values import CAR, MQB_A0_CARS
|
||||
|
||||
|
||||
def test_is_mqb_a0_car_matches_expected_platforms():
|
||||
assert CAR.VOLKSWAGEN_POLO_MK6 in MQB_A0_CARS
|
||||
assert CAR.VOLKSWAGEN_TCROSS_MK1 in MQB_A0_CARS
|
||||
assert CAR.SKODA_FABIA_MK4 in MQB_A0_CARS
|
||||
assert CAR.SKODA_KAMIQ_MK1 in MQB_A0_CARS
|
||||
assert CarController._is_mqb_a0_car(CAR.VOLKSWAGEN_POLO_MK6)
|
||||
assert CarController._is_mqb_a0_car(CAR.VOLKSWAGEN_TCROSS_MK1)
|
||||
assert CarController._is_mqb_a0_car(CAR.SKODA_FABIA_MK4)
|
||||
assert CarController._is_mqb_a0_car(CAR.SKODA_KAMIQ_MK1)
|
||||
assert not CarController._is_mqb_a0_car(CAR.VOLKSWAGEN_GOLF_MK7)
|
||||
|
||||
|
||||
def test_mqb_steering_torque_scale_only_changes_when_toggle_enabled():
|
||||
controller = object.__new__(CarController)
|
||||
controller.CCS = mqbcan
|
||||
assert controller._get_mqb_steering_torque_scale(0.4, False) == 1.0
|
||||
|
||||
assert controller._get_mqb_steering_torque_scale(0.4, True) == 0.8
|
||||
assert controller._get_mqb_steering_torque_scale(4.0, True) == 1.0
|
||||
|
||||
controller.CCS = pqcan
|
||||
assert controller._get_mqb_steering_torque_scale(0.4, True) == 1.0
|
||||
|
||||
|
||||
def test_mqb_a0_resume_spam_requires_toggle_platform_and_window():
|
||||
controller = object.__new__(CarController)
|
||||
controller.CCS = mqbcan
|
||||
controller.is_mqb_a0 = True
|
||||
controller.frame = 10
|
||||
cs = SimpleNamespace(out=SimpleNamespace(standstill=True))
|
||||
|
||||
assert controller._should_spam_mqb_a0_resume(cs, True)
|
||||
|
||||
controller.frame = 20
|
||||
assert not controller._should_spam_mqb_a0_resume(cs, True)
|
||||
|
||||
controller.frame = 10
|
||||
controller.is_mqb_a0 = False
|
||||
assert not controller._should_spam_mqb_a0_resume(cs, True)
|
||||
|
||||
controller.is_mqb_a0 = True
|
||||
assert not controller._should_spam_mqb_a0_resume(cs, False)
|
||||
186
iqdbc_repo/iqdbc/car/volkswagen/tests/test_pq_can_valid.py
Normal file
186
iqdbc_repo/iqdbc/car/volkswagen/tests/test_pq_can_valid.py
Normal file
@@ -0,0 +1,186 @@
|
||||
"""
|
||||
Regression guard for the class of bug fixed in carstate.py's Diagnose_1 (cluster clock,
|
||||
removed) and EPB_1 (stop-and-go hold, now gated on PQ_SNG_ECD): reading a CAN message via
|
||||
`some_cp.vl["MsgName"]["Signal"]` without declaring it in get_can_parsers_pq() lazily adds
|
||||
it via VLDict.__getitem__ -> CANParser._add_message(key, freq=None), which is NOT the same
|
||||
as ignore-alive (that's what math.nan is for -- see
|
||||
iqdbc/can/tests/test_packer_parser.py::test_lazy_add_not_ignore_alive). An undeclared
|
||||
message defaults to "assume ~1Hz, must be seen within ~10s", so if the real car never sends
|
||||
it, CarState.canValid gets stuck False forever.
|
||||
|
||||
Rather than fuzzing every VolkswagenFlagsIQ combination (most are unreachable through
|
||||
interface.py's real detection logic), each fixture below is the CarParams captured from a
|
||||
real konn3kt route for a real car of that variant. We run CarState.update() once (no CAN
|
||||
data needs to be fed -- .vl[...] lazily adds and returns default-zero values regardless of
|
||||
whether the parser has ever seen a real frame) while recording every message name accessed,
|
||||
then assert that set is a subset of what that real car actually transmits (per its captured
|
||||
CAN fingerprint). A message accessed but not in the real fingerprint is exactly the bug
|
||||
class this guards against.
|
||||
"""
|
||||
from iqdbc.can.parser import VLDict
|
||||
from iqdbc.car import structs
|
||||
from iqdbc.car.volkswagen.carstate import CarState
|
||||
from iqdbc.car.volkswagen.values import CAR, Bus
|
||||
|
||||
|
||||
class _RecordingVLDict(VLDict):
|
||||
"""Records every message name read via .vl[...], including ones lazily added for
|
||||
messages never declared in get_can_parsers_pq's message list. Applied by reclassing
|
||||
a live CANParser.vl instance in place (rather than replacing it with a fresh object)
|
||||
so any messages already registered at CANParser construction time, and the parser
|
||||
back-reference _add_message needs, are preserved."""
|
||||
accessed: set[str]
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, str):
|
||||
self.accessed.add(key)
|
||||
return super().__getitem__(key)
|
||||
|
||||
|
||||
def _make_car_params(car_fingerprint, flags, network_location, transmission_type, enable_bsm, pcm_cruise):
|
||||
CP = structs.CarParams.new_message()
|
||||
CP.carFingerprint = car_fingerprint
|
||||
CP.flags = flags
|
||||
CP.radarUnavailable = True
|
||||
CP.networkLocation = network_location
|
||||
CP.transmissionType = transmission_type
|
||||
CP.enableBsm = enable_bsm
|
||||
CP.pcmCruise = pcm_cruise
|
||||
CP.minSteerSpeed = 0.0
|
||||
CP_IQ = structs.IQCarParams()
|
||||
return CP, CP_IQ
|
||||
|
||||
|
||||
# Real per-variant CarParams captured from konn3kt routes (not hand-derived), so each
|
||||
# fixture reflects an actual car rather than a guess at which flag combos are reachable.
|
||||
# known_bus1/known_bus2 are the exact message names present in that car's real CAN
|
||||
# fingerprint. Bus.pt and Bus.aux both listen on physical bus 1 for PQ (CanBus.powertrain
|
||||
# == CanBus.aux == 1); Bus.cam listens on physical bus 2 (CanBus.cam == 2) -- see CanBus in
|
||||
# iqdbc/car/volkswagen/values.py. UNK_* (unrecognized DBC addresses) are dropped.
|
||||
FIXTURES = [
|
||||
dict(
|
||||
name="jetta_mk6_base",
|
||||
route="a0d99b85ff06857b|0000003a--135c88414f",
|
||||
car_fingerprint=CAR.VOLKSWAGEN_JETTA_MK6,
|
||||
flags=2,
|
||||
network_location="gateway",
|
||||
transmission_type="automatic",
|
||||
enable_bsm=False,
|
||||
pcm_cruise=True,
|
||||
known_bus1={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'Airbag_2', 'BSG_Last', 'Bremse_1',
|
||||
'Bremse_10', 'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_4', 'Bremse_5', 'Bremse_8',
|
||||
'Bremse_9', 'Diagnose_1', 'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2',
|
||||
'Getriebe_1', 'Getriebe_2', 'Getriebe_4', 'Ident', 'Klima_1', 'Kombi_1', 'Kombi_2',
|
||||
'Kombi_3', 'Lenkhilfe_1', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1',
|
||||
'Motor_10', 'Motor_12', 'Motor_2', 'Motor_3', 'Motor_5', 'Motor_6', 'Motor_7', 'Motor_8',
|
||||
'Motor_Bremse', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1', 'Waehlhebel_1',
|
||||
},
|
||||
known_bus2={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'BSG_Last', 'Bremse_1', 'Bremse_10',
|
||||
'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_5', 'Bremse_8', 'Diagnose_1', 'Einheiten_1',
|
||||
'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2', 'Getriebe_1', 'Ident', 'Kombi_1', 'Kombi_2',
|
||||
'Kombi_3', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1', 'Motor_10', 'Motor_2',
|
||||
'Motor_3', 'Motor_5', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
),
|
||||
dict(
|
||||
name="passat_nms_sng_ecd",
|
||||
route="0f53129ed44f6920|00000031--0c1aea511e",
|
||||
car_fingerprint=CAR.VOLKSWAGEN_PASSAT_NMS,
|
||||
flags=524418, # PQ | IQ_LVBS_ALC_MODULE | IQ_PQ_SNG_ECD
|
||||
network_location="gateway",
|
||||
transmission_type="automatic",
|
||||
enable_bsm=False,
|
||||
pcm_cruise=False,
|
||||
known_bus1={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'Airbag_2', 'BSG_Last', 'Bremse_1',
|
||||
'Bremse_10', 'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_4', 'Bremse_5', 'Bremse_8',
|
||||
'Bremse_9', 'Diagnose_1', 'EPB_1', 'EPB_2', 'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1',
|
||||
'Gate_Komf_2', 'Getriebe_1', 'Getriebe_2', 'Ident', 'Klima_1', 'Kombi_1', 'Kombi_2',
|
||||
'Kombi_3', 'Lenkhilfe_1', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1',
|
||||
'Motor_10', 'Motor_12', 'Motor_13', 'Motor_2', 'Motor_3', 'Motor_5', 'Motor_6', 'Motor_7',
|
||||
'Motor_8', 'Motor_Bremse', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
known_bus2={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'BSG_Last', 'Bremse_1', 'Bremse_10',
|
||||
'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_5', 'Bremse_8', 'Diagnose_1', 'EPB_1',
|
||||
'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2', 'Getriebe_1', 'Ident', 'Kombi_1',
|
||||
'Kombi_2', 'Kombi_3', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1', 'Motor_10',
|
||||
'Motor_2', 'Motor_3', 'Motor_5', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
),
|
||||
dict(
|
||||
name="passat_b7_acc_fts_epb",
|
||||
route="20e3cd4f0d5f39d1|0000008e--274d762bac",
|
||||
car_fingerprint=CAR.VOLKSWAGEN_PASSAT_B7,
|
||||
flags=262146, # PQ | IQ_PQ_ACC_FTS_EPB
|
||||
network_location="gateway",
|
||||
transmission_type="automatic",
|
||||
enable_bsm=True,
|
||||
pcm_cruise=False,
|
||||
known_bus1={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'Airbag_2', 'BSG_Last', 'Bremse_1',
|
||||
'Bremse_10', 'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_4', 'Bremse_5', 'Bremse_8',
|
||||
'Bremse_9', 'Daempfer_1', 'Diagnose_1', 'EPB_1', 'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1',
|
||||
'Gate_Komf_2', 'Getriebe_1', 'Getriebe_2', 'Getriebe_4', 'HCA_1', 'Ident', 'Klima_1',
|
||||
'Kombi_1', 'Kombi_2', 'Kombi_3', 'Lenkhilfe_1', 'Lenkhilfe_2', 'Lenkhilfe_3',
|
||||
'Lenkwinkel_1', 'Motor_1', 'Motor_10', 'Motor_12', 'Motor_2', 'Motor_3', 'Motor_5',
|
||||
'Motor_6', 'Motor_7', 'Motor_8', 'Motor_Bremse', 'Motor_Flexia', 'Parkhilfe_01',
|
||||
'Soll_Verbauliste_neu', 'Systeminfo_1', 'Waehlhebel_1',
|
||||
},
|
||||
known_bus2={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'BSG_Last', 'Bremse_1', 'Bremse_10',
|
||||
'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_5', 'Bremse_8', 'Diagnose_1', 'EPB_1',
|
||||
'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2', 'Getriebe_1', 'HCA_1', 'Ident',
|
||||
'Kombi_1', 'Kombi_2', 'Kombi_3', 'LDW_Status', 'Lenkhilfe_2', 'Lenkhilfe_3',
|
||||
'Lenkwinkel_1', 'Motor_1', 'Motor_10', 'Motor_2', 'Motor_3', 'Motor_5', 'Motor_Flexia',
|
||||
'Parkhilfe_01', 'RDK_Status', 'SWA_1', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class TestVolkswagenPqCanValid:
|
||||
def test_only_reads_messages_the_real_car_sends(self, subtests):
|
||||
for fixture in FIXTURES:
|
||||
with subtests.test(car=fixture["name"]):
|
||||
CP, CP_IQ = _make_car_params(
|
||||
fixture["car_fingerprint"], fixture["flags"], fixture["network_location"],
|
||||
fixture["transmission_type"], fixture["enable_bsm"], fixture["pcm_cruise"],
|
||||
)
|
||||
|
||||
CS = CarState(CP, CP_IQ)
|
||||
can_parsers = CS.get_can_parsers(CP, CP_IQ)
|
||||
|
||||
recorders = {}
|
||||
for bus, parser in can_parsers.items():
|
||||
if parser is None:
|
||||
continue
|
||||
parser.vl.__class__ = _RecordingVLDict
|
||||
parser.vl.accessed = set()
|
||||
recorders[bus] = parser.vl
|
||||
|
||||
# no CAN data is fed: .vl[...] lazily adds and returns default-zero values
|
||||
# regardless of whether the parser has ever seen a real frame, so this alone
|
||||
# is enough to harvest every message name update_pq() touches for this variant
|
||||
CS.update(can_parsers)
|
||||
|
||||
accessed_bus1 = recorders[Bus.pt].accessed | recorders[Bus.aux].accessed
|
||||
accessed_bus2 = recorders[Bus.cam].accessed
|
||||
|
||||
extra_bus1 = accessed_bus1 - fixture["known_bus1"]
|
||||
extra_bus2 = accessed_bus2 - fixture["known_bus2"]
|
||||
|
||||
assert not extra_bus1, (
|
||||
f"{fixture['name']}: code reads {sorted(extra_bus1)} on bus 1 (pt/aux) but the "
|
||||
f"real car (route {fixture['route']}) never transmits it -- this needs to be "
|
||||
f"gated behind whatever flag makes it optional, or declared with math.nan if it's "
|
||||
f"genuinely on-demand/rare, not read unconditionally"
|
||||
)
|
||||
assert not extra_bus2, (
|
||||
f"{fixture['name']}: code reads {sorted(extra_bus2)} on bus 2 (cam) but the "
|
||||
f"real car (route {fixture['route']}) never transmits it -- this needs to be "
|
||||
f"gated behind whatever flag makes it optional, or declared with math.nan if it's "
|
||||
f"genuinely on-demand/rare, not read unconditionally"
|
||||
)
|
||||
33
iqdbc_repo/iqdbc/car/volkswagen/tests/test_stopping.py
Normal file
33
iqdbc_repo/iqdbc/car/volkswagen/tests/test_stopping.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import pytest
|
||||
|
||||
from iqdbc.car.volkswagen.interface import CarInterface
|
||||
from iqdbc.car.volkswagen.values import (
|
||||
CAR, PASSAT_B7_STOP_ACCEL, PASSAT_B7_STOPPING_SPEED, PQ_STOPPING_SPEED,
|
||||
VolkswagenFlags, apply_pq_stopping_accel, get_longitudinal_stopping_speed_override,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate, flags, expected", [
|
||||
(CAR.VOLKSWAGEN_PASSAT_B7, VolkswagenFlags.PQ, PASSAT_B7_STOPPING_SPEED),
|
||||
(CAR.VOLKSWAGEN_JETTA_MK6, VolkswagenFlags.PQ, PQ_STOPPING_SPEED),
|
||||
(CAR.VOLKSWAGEN_GOLF_MK7, 0, 0.0),
|
||||
(CAR.VOLKSWAGEN_ID4_MK1, VolkswagenFlags.MEB, 0.0),
|
||||
])
|
||||
def test_stopping_speed_override(candidate, flags, expected):
|
||||
assert get_longitudinal_stopping_speed_override(candidate, flags) == expected
|
||||
|
||||
|
||||
def test_passat_b7_stop_accel_is_exact():
|
||||
assert apply_pq_stopping_accel(CAR.VOLKSWAGEN_PASSAT_B7, -0.2, True) == PASSAT_B7_STOP_ACCEL == -0.55
|
||||
assert apply_pq_stopping_accel(CAR.VOLKSWAGEN_PASSAT_B7, -0.2, False) == -0.2
|
||||
assert apply_pq_stopping_accel(CAR.VOLKSWAGEN_JETTA_MK6, -0.2, True) == -0.2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate", [
|
||||
CAR.VOLKSWAGEN_JETTA_MK6,
|
||||
CAR.VOLKSWAGEN_PASSAT_NMS,
|
||||
])
|
||||
def test_pq_longitudinal_feedforward_uses_active_schema_field(candidate):
|
||||
fingerprint = {bus: {} for bus in range(8)}
|
||||
cp = CarInterface.get_params(candidate, fingerprint, [], alpha_long=True, is_release=False, docs=False)
|
||||
assert cp.longitudinalTuning.kf == pytest.approx(1.2)
|
||||
@@ -43,6 +43,10 @@ class TestVolkswagenPlatformConfigs:
|
||||
if len(shared_chassis_codes) == 0:
|
||||
continue
|
||||
|
||||
# A shared chassis code is unambiguous when the VIN WMI separates the candidates.
|
||||
if platform.config.wmis.isdisjoint(comp.config.wmis):
|
||||
continue
|
||||
|
||||
platform_model_years = getattr(platform.config, "model_years", set())
|
||||
comp_model_years = getattr(comp.config, "model_years", set())
|
||||
if platform_model_years and comp_model_years and platform_model_years.isdisjoint(comp_model_years):
|
||||
@@ -51,10 +55,13 @@ class TestVolkswagenPlatformConfigs:
|
||||
assert set() == shared_chassis_codes, f"Shared chassis codes: {comp}"
|
||||
|
||||
def test_custom_fuzzy_fingerprinting(self, subtests):
|
||||
all_radar_fw = list({fw for ecus in FW_VERSIONS.values() for fw in ecus[Ecu.fwdRadar, 0x757, None]})
|
||||
all_radar_fw = list({fw for ecus in FW_VERSIONS.values() for fw in ecus.get((Ecu.fwdRadar, 0x757, None), [])})
|
||||
|
||||
for platform in CAR:
|
||||
with subtests.test(platform=platform.name):
|
||||
# Fuzzy matching keys off the radar ECU (CHECK_FUZZY_ECUS), so a platform that
|
||||
# declares no radar ECU can never be VIN-matched and should never be expected to match.
|
||||
platform_has_radar = (Ecu.fwdRadar, 0x757, None) in FW_VERSIONS.get(platform, {})
|
||||
for wmi in WMI:
|
||||
for chassis_code in platform.config.chassis_codes | {"00"}:
|
||||
platform_model_years = getattr(platform.config, "model_years", set())
|
||||
@@ -70,7 +77,7 @@ class TestVolkswagenPlatformConfigs:
|
||||
for radar_fw in random.sample(all_radar_fw, 5) + [b'\xf1\x875Q0907572G \xf1\x890571', b'\xf1\x877H9907572AA\xf1\x890396']:
|
||||
model_year_match = len(platform_model_years) == 0 or model_year in platform_model_years
|
||||
should_match = ((wmi in platform.config.wmis and chassis_code in platform.config.chassis_codes and model_year_match) and
|
||||
radar_fw in all_radar_fw)
|
||||
radar_fw in all_radar_fw and platform_has_radar)
|
||||
|
||||
live_fws = {(0x757, None): [radar_fw]}
|
||||
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fws, vin, FW_VERSIONS)
|
||||
@@ -106,3 +113,17 @@ def test_button_enable_recovers_once_cruise_fault_clears():
|
||||
)]
|
||||
|
||||
assert state.update_button_enable(button_events)
|
||||
|
||||
|
||||
def test_pq_hca_ready_does_not_complete_eps_initialization():
|
||||
state = object.__new__(CarState)
|
||||
state.eps_init_complete = False
|
||||
|
||||
state.frame = 0
|
||||
assert state.update_hca_state("READY", ready_confirms_init=False) == (True, False)
|
||||
|
||||
state.frame = 317
|
||||
assert state.update_hca_state("FAULT", ready_confirms_init=False) == (True, False)
|
||||
|
||||
state.frame = 1001
|
||||
assert state.update_hca_state("FAULT", ready_confirms_init=False) == (False, True)
|
||||
|
||||
@@ -35,6 +35,10 @@ class CanBus(CanBusBase):
|
||||
# NetworkLocation.gateway: powertrain CAN
|
||||
return 1
|
||||
|
||||
@property
|
||||
def powertrain(self) -> int:
|
||||
return 1
|
||||
|
||||
@property
|
||||
def main(self) -> int:
|
||||
return 1
|
||||
@@ -49,17 +53,11 @@ class CanBus(CanBusBase):
|
||||
# ADAS / Extended CAN, side of the relay with the ACC radar
|
||||
return 2
|
||||
|
||||
@property
|
||||
def eps(self) -> int:
|
||||
return 4
|
||||
|
||||
@property
|
||||
def car(self) -> int:
|
||||
return 6
|
||||
|
||||
|
||||
# Extra Tolerances For Road Variance
|
||||
AVERAGE_ROAD_ROLL = 0.06
|
||||
PQ_STOPPING_SPEED = 1.5 * CV.KPH_TO_MS
|
||||
PASSAT_B7_STOPPING_SPEED = 0.55 * CV.KPH_TO_MS
|
||||
PASSAT_B7_STOP_ACCEL = -0.55
|
||||
|
||||
|
||||
class CarControllerParams:
|
||||
@@ -84,6 +82,8 @@ class CarControllerParams:
|
||||
AEB_CONTROL_STEP = 2 # ACC_10 frequency 50Hz
|
||||
AEB_HUD_STEP = 20 # ACC_15 frequency 5Hz
|
||||
VW_LOW_SPEED_STATE_SPEED = 0.5 # m/s; below this, always force starting or stopping in MQB legacy long
|
||||
SNG_HANDOFF_SPEED = 5.0 * CV.KPH_TO_MS
|
||||
SNG_HOLD_DECEL_MAX = -0.1
|
||||
|
||||
# Documented lateral limits: 3.00 Nm max, rate of change 5.00 Nm/sec.
|
||||
# MQB vs PQ maximums are shared, but rate-of-change limited differently
|
||||
@@ -99,7 +99,8 @@ class CarControllerParams:
|
||||
STEER_LOW_TORQUE = int(STEER_MAX * 0.20) # Steer timer mitigation performed when torque output under 20%
|
||||
STEER_TIME_LOW_TORQUE = 0.5 # Wait for this duration of STEER_LOW_TORQUE to begin mitigation
|
||||
STEER_TIME_STUCK_TORQUE = 1.9 # EPS limits same torque to 6 seconds, reset timer 3x within that period
|
||||
STEER_TIME_RESET = 1.1 # Duration of HCA disable needed for effective EPS timer reset
|
||||
STEER_TIME_RESET = 1.1 # Duration of HCA disable needed for effective EPS timer reset'
|
||||
IQ_PQ_UNAVAILABLE_HUD_FRAMES = 25
|
||||
|
||||
DEFAULT_MIN_STEER_SPEED = 0.4 # m/s, newer EPS racks fault below this speed, don't show a low speed alert
|
||||
|
||||
@@ -115,8 +116,8 @@ class CarControllerParams:
|
||||
self.LDW_STEP = 5 # LDW_1 message frequency 20Hz
|
||||
self.ACC_HUD_STEP = 4 # ACC_GRA_Anzeige frequency 25Hz
|
||||
self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
|
||||
self.STEER_DELTA_UP = 10 # Max HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
self.STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
self.STEER_DELTA_UP = 150 # Max HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
self.STEER_DELTA_DOWN = 300 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
|
||||
if CP.transmissionType == TransmissionType.automatic:
|
||||
self.shifter_values = can_define.dv["Getriebe_1"]["GE1_Wahl_Pos"]
|
||||
@@ -141,8 +142,6 @@ class CarControllerParams:
|
||||
}
|
||||
|
||||
elif CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
self.AEB_CONTROL_STEP = 100 # AWV_03 radar-replacement at 1Hz (class default 2 = 50Hz is for MQB ACC_10)
|
||||
self.AEB_HUD_STEP = 20 # MEB_AWV_01 AEB HUD at 5Hz
|
||||
self.LDW_STEP = 10
|
||||
self.ACC_HUD_STEP = 6
|
||||
self.STEER_DRIVER_ALLOWANCE = 60
|
||||
@@ -286,6 +285,10 @@ class VolkswagenSafetyFlags(IntFlag):
|
||||
ALLOW_LONG_ACCEL_WITH_GAS_PRESSED = 8
|
||||
DISABLE_RADAR = 16
|
||||
PQ_ALC_MODULE = 32
|
||||
PQ_LOWLINE = 64
|
||||
PQ_NO_CAM_BUS = 128
|
||||
PQ_ACC_FTS_EPB = 256
|
||||
PQ_SNG_ECD = 512
|
||||
|
||||
|
||||
class VolkswagenFlags(IntFlag):
|
||||
@@ -313,6 +316,10 @@ class VolkswagenFlagsIQ(IntFlag):
|
||||
IQ_CC_ONLY = 1 << 5 # CC only mode with radar (has AEB)
|
||||
IQ_CC_ONLY_NO_RADAR = 1 << 6 # CC only mode without radar
|
||||
IQ_LVBS_ALC_MODULE = 1 << 7 # IQ.Lvbs VW ALC hardware module present / intended active path
|
||||
IQ_PQ_LOWLINE = 1 << 17 # Non-ECAN lateral-only PQ: bus 0 dead, TX on bus 1 (ptCAN)
|
||||
IQ_PQ_ACC_FTS_EPB = 1 << 18 # B7 TRW450: ACC FtS + EPB hold, Motor_1 resume spoof on bus 1
|
||||
IQ_PQ_SNG_ECD = 1 << 19
|
||||
IQ_PQ_TIMEBOMB = 1 << 20
|
||||
|
||||
|
||||
RADAR_DISABLE_STATE = {"error": False}
|
||||
@@ -335,6 +342,7 @@ class VolkswagenMQBPlatformConfig(PlatformConfig):
|
||||
# on camera-integrated cars, as we lose too many ECUs to reliably identify the vehicle
|
||||
chassis_codes: set[str] = field(default_factory=set)
|
||||
wmis: set[WMI] = field(default_factory=set)
|
||||
model_years: set[str] = field(default_factory=set)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -544,24 +552,35 @@ class CAR(Platforms):
|
||||
VolkswagenCarSpecs(mass=1551, wheelbase=2.79),
|
||||
chassis_codes={"3C", "3G"},
|
||||
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
|
||||
model_years={"F", "G", "H", "J", "K", "L", "M", "N"}, # 2015-2022
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_MK7 = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat 2.0 TDI 2014")],
|
||||
VolkswagenCarSpecs(mass=1836, wheelbase=2.70, steerRatio=13.0, minSteerSpeed=31 * CV.KPH_TO_MS),
|
||||
chassis_codes={"3C"},
|
||||
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
|
||||
model_years={"E"}, # 2014
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_NMS = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat NMS 2015-17")],
|
||||
VolkswagenCarSpecs(mass=1503, wheelbase=2.80),
|
||||
chassis_codes={"A3"},
|
||||
wmis={WMI.VOLKSWAGEN_USA_CAR},
|
||||
# NMS and NMS+ share chassis code A3; disambiguate by model year
|
||||
model_years={"F", "G", "H"}, # 2015-2017
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_NMS_PLUS = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat NMS 2018-22")],
|
||||
VolkswagenCarSpecs(mass=1503, wheelbase=2.80, minEnableSpeed=20 * CV.KPH_TO_MS),
|
||||
chassis_codes={"A3"},
|
||||
wmis={WMI.VOLKSWAGEN_USA_CAR},
|
||||
model_years={"J", "K", "L", "M", "N"}, # 2018-2022
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_B7 = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat B7 2008-2011")],
|
||||
VolkswagenCarSpecs(mass=1503, wheelbase=2.712, steerRatio=16.4, minSteerSpeed=0),
|
||||
chassis_codes={"A3"},
|
||||
wmis={WMI.VOLKSWAGEN_USA_CAR},
|
||||
)
|
||||
VOLKSWAGEN_POLO_MK6 = VolkswagenMQBPlatformConfig(
|
||||
[
|
||||
@@ -575,12 +594,19 @@ class CAR(Platforms):
|
||||
VOLKSWAGEN_SHARAN_MK2 = VolkswagenPQPlatformConfig(
|
||||
[
|
||||
VWCarDocs("Volkswagen Sharan 2018-22"),
|
||||
VWCarDocs("SEAT Alhambra 2018-20"),
|
||||
],
|
||||
VolkswagenCarSpecs(mass=1639, wheelbase=2.92),
|
||||
chassis_codes={"7N"},
|
||||
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
|
||||
)
|
||||
SEAT_ALHAMBRA_MK1 = VolkswagenPQPlatformConfig(
|
||||
[
|
||||
VWCarDocs("SEAT Alhambra 2018-20"),
|
||||
],
|
||||
VolkswagenCarSpecs(mass=1639, wheelbase=2.92, minSteerSpeed=50 * CV.KPH_TO_MS),
|
||||
chassis_codes={"7N"},
|
||||
wmis={WMI.SEAT},
|
||||
)
|
||||
VOLKSWAGEN_TAOS_MK1 = VolkswagenMQBPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Taos 2022-24")],
|
||||
VolkswagenCarSpecs(mass=1498, wheelbase=2.69),
|
||||
@@ -882,4 +908,24 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
|
||||
)
|
||||
|
||||
MQB_A0_CARS = {
|
||||
CAR.VOLKSWAGEN_POLO_MK6,
|
||||
CAR.VOLKSWAGEN_TCROSS_MK1,
|
||||
CAR.SKODA_FABIA_MK4,
|
||||
CAR.SKODA_KAMIQ_MK1,
|
||||
}
|
||||
|
||||
|
||||
def get_longitudinal_stopping_speed_override(candidate: CAR, flags: int) -> float:
|
||||
if candidate == CAR.VOLKSWAGEN_PASSAT_B7:
|
||||
return PASSAT_B7_STOPPING_SPEED
|
||||
if flags & VolkswagenFlags.PQ:
|
||||
return PQ_STOPPING_SPEED
|
||||
return 0.0
|
||||
|
||||
|
||||
def apply_pq_stopping_accel(candidate: CAR, accel: float, stopping: bool) -> float:
|
||||
return PASSAT_B7_STOP_ACCEL if candidate == CAR.VOLKSWAGEN_PASSAT_B7 and stopping else accel
|
||||
|
||||
|
||||
DBC = CAR.create_dbc_map()
|
||||
|
||||
@@ -3,6 +3,13 @@ from pathlib import Path
|
||||
|
||||
env = Environment(ENV=os.environ)
|
||||
|
||||
# short colored build output, if the top-level pretty tool is present (main-repo build)
|
||||
_pretty = Dir('#site_scons/site_tools').File('pretty.py')
|
||||
if _pretty.exists():
|
||||
env.Tool('pretty', toolpath=[_pretty.dir.abspath])
|
||||
if not hasattr(env, 'PrettyAction'):
|
||||
env.AddMethod(lambda e, cmd, label, **kw: Action(cmd), 'PrettyAction')
|
||||
|
||||
generator = File("generator/generator.py")
|
||||
|
||||
source_files = [
|
||||
@@ -27,5 +34,5 @@ output_files += [
|
||||
generated = env.Command(
|
||||
target=list(set(output_files)),
|
||||
source=[generator] + source_files,
|
||||
action="python3 ${SOURCES[0]}",
|
||||
action=env.PrettyAction("python3 ${SOURCES[0]}", 'GEN'),
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ CM_ "IMPORT _gearbox_common.dbc";
|
||||
|
||||
BO_ 456 ACC_CONTROL: 8 XXX
|
||||
SG_ ACCEL_COMMAND : 7|12@0- (0.01,0) [0|0] "m/s^2" XXX
|
||||
SG_ IDLESTOP_ALLOW : 8|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ BRAKE_REQUEST : 8|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ STANDSTILL : 9|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CONTROL_ON : 10|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ BOH : 23|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
hyundai_kia_mando_front_radar.dbc
|
||||
hyundai_kia_denso_front_radar.dbc
|
||||
hyundai_kia_mando_corner_radar.dbc
|
||||
|
||||
@@ -40,18 +40,21 @@ BO_ 80 LKAS: 16 XXX
|
||||
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ LKA_AVAILABLE : 27|2@1+ (1,0) [0|255] "" XXX
|
||||
SG_ LKA_ACTIVE : 27|2@1+ (1,0) [0|255] "" XXX
|
||||
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
|
||||
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
|
||||
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
|
||||
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
|
||||
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ VALUE63 : 63|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ VALUE64 : 64|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_1 : 75|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ LKAS_ANGLE_ACTIVE : 77|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ DAMP_FACTOR : 64|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ LKAS_ANGLE_CMD : 82|14@1- (-0.1,0) [0|511] "" XXX
|
||||
SG_ LKAS_ANGLE_MAX_TORQUE : 96|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ VALUE104 : 104|8@1+ (1,0) [0|255] "" XXX
|
||||
|
||||
BO_ 81 ADRV_0x51: 32 ADRV
|
||||
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,140 @@
|
||||
VERSION ""
|
||||
|
||||
|
||||
NS_ :
|
||||
NS_DESC_
|
||||
CM_
|
||||
BA_DEF_
|
||||
BA_
|
||||
VAL_
|
||||
CAT_DEF_
|
||||
CAT_
|
||||
FILTER
|
||||
BA_DEF_DEF_
|
||||
EV_DATA_
|
||||
ENVVAR_DATA_
|
||||
ENVVAR_TYPE_
|
||||
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 RADAR
|
||||
|
||||
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;
|
||||
BA_DEF_DEF_ "GenMsgCycleTime" 0;
|
||||
|
||||
BO_ 384 CORNER_RADAR_180_OBJECTS_180: 32 RADAR
|
||||
SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 384 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 384 30;
|
||||
|
||||
BO_ 385 CORNER_RADAR_180_OBJECTS_181: 32 RADAR
|
||||
SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 385 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 385 30;
|
||||
|
||||
BO_ 386 CORNER_RADAR_180_OBJECTS_182: 32 RADAR
|
||||
SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 386 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 386 30;
|
||||
|
||||
BO_ 387 CORNER_RADAR_180_OBJECTS_183: 32 RADAR
|
||||
SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 387 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 387 30;
|
||||
|
||||
BO_ 388 CORNER_RADAR_180_OBJECTS_184: 32 RADAR
|
||||
SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 388 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 388 30;
|
||||
81
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.py
Executable file
81
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.py
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
|
||||
HEADER = """VERSION ""
|
||||
|
||||
|
||||
NS_ :
|
||||
NS_DESC_
|
||||
CM_
|
||||
BA_DEF_
|
||||
BA_
|
||||
VAL_
|
||||
CAT_DEF_
|
||||
CAT_
|
||||
FILTER
|
||||
BA_DEF_DEF_
|
||||
EV_DATA_
|
||||
ENVVAR_DATA_
|
||||
ENVVAR_TYPE_
|
||||
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 RADAR
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def write_object_msg(f, addr):
|
||||
name = f"CORNER_RADAR_180_OBJECTS_{addr:x}"
|
||||
f.write(f"""
|
||||
BO_ {addr} {name}: 32 RADAR
|
||||
SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
""")
|
||||
|
||||
f.write(f"""CM_ BO_ {addr} "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ {addr} 30;
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
|
||||
out_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), dbc_name)
|
||||
with open(out_path, "w", encoding="ascii") as f:
|
||||
f.write(HEADER)
|
||||
f.write('BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;\n')
|
||||
f.write('BA_DEF_DEF_ "GenMsgCycleTime" 0;\n')
|
||||
for addr in range(0x180, 0x185):
|
||||
write_object_msg(f, addr)
|
||||
@@ -0,0 +1,278 @@
|
||||
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_
|
||||
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 RADAR
|
||||
|
||||
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;
|
||||
BA_DEF_DEF_ "GenMsgCycleTime" 0;
|
||||
|
||||
BO_ 565 CORNER_RADAR_235_OBJECTS_235: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 565 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 565 30;
|
||||
|
||||
BO_ 566 CORNER_RADAR_235_OBJECTS_236: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 566 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 566 30;
|
||||
|
||||
BO_ 567 CORNER_RADAR_235_OBJECTS_237: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 567 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 567 30;
|
||||
|
||||
BO_ 568 CORNER_RADAR_235_OBJECTS_238: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 568 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 568 30;
|
||||
|
||||
BO_ 569 CORNER_RADAR_235_OBJECTS_239: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 569 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 569 30;
|
||||
|
||||
BO_ 570 CORNER_RADAR_235_OBJECTS_23a: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 570 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 570 30;
|
||||
|
||||
BO_ 571 CORNER_RADAR_235_OBJECTS_23b: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 571 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 571 30;
|
||||
|
||||
BO_ 572 CORNER_RADAR_235_OBJECTS_23c: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 572 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 572 30;
|
||||
|
||||
BO_ 573 CORNER_RADAR_235_OBJECTS_23d: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 573 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 573 30;
|
||||
|
||||
BO_ 574 CORNER_RADAR_235_OBJECTS_23e: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 574 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 574 30;
|
||||
|
||||
BO_ 575 CORNER_RADAR_235_OBJECTS_23f: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 575 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 575 30;
|
||||
|
||||
BO_ 576 CORNER_RADAR_235_OBJECTS_240: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 576 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 576 30;
|
||||
|
||||
BO_ 577 CORNER_RADAR_235_OBJECTS_241: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 577 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 577 30;
|
||||
|
||||
BO_ 578 CORNER_RADAR_235_OBJECTS_242: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 578 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 578 30;
|
||||
|
||||
BO_ 579 CORNER_RADAR_235_OBJECTS_243: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 579 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 579 30;
|
||||
|
||||
BO_ 580 CORNER_RADAR_235_OBJECTS_244: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 580 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 580 30;
|
||||
|
||||
BO_ 581 CORNER_RADAR_235_OBJECTS_245: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 581 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 581 30;
|
||||
|
||||
BO_ 582 CORNER_RADAR_235_OBJECTS_246: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 582 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 582 30;
|
||||
|
||||
BO_ 583 CORNER_RADAR_235_OBJECTS_247: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 583 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 583 30;
|
||||
|
||||
BO_ 584 CORNER_RADAR_235_OBJECTS_248: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
CM_ BO_ 584 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ 584 30;
|
||||
71
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.py
Executable file
71
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.py
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
|
||||
HEADER = """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_
|
||||
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 RADAR
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def write_object_msg(f, addr):
|
||||
name = f"CORNER_RADAR_235_OBJECTS_{addr:x}"
|
||||
f.write(f"""
|
||||
BO_ {addr} {name}: 32 RADAR
|
||||
SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
|
||||
SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
|
||||
SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
|
||||
SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
|
||||
SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
|
||||
SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
|
||||
SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
|
||||
""")
|
||||
|
||||
f.write(f"""CM_ BO_ {addr} "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
|
||||
BA_ "GenMsgCycleTime" BO_ {addr} 30;
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
|
||||
out_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), dbc_name)
|
||||
with open(out_path, "w", encoding="ascii") as f:
|
||||
f.write(HEADER)
|
||||
f.write('BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;\n')
|
||||
f.write('BA_DEF_DEF_ "GenMsgCycleTime" 0;\n')
|
||||
for addr in range(0x235, 0x249):
|
||||
write_object_msg(f, addr)
|
||||
@@ -0,0 +1,614 @@
|
||||
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_
|
||||
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 RADAR
|
||||
|
||||
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;
|
||||
BA_DEF_DEF_ "GenMsgCycleTime" 0;
|
||||
|
||||
BO_ 1072 CORNER_RADAR_430_OBJECTS_430: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1072 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1072 30;
|
||||
|
||||
BO_ 1073 CORNER_RADAR_430_OBJECTS_431: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1073 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1073 30;
|
||||
|
||||
BO_ 1074 CORNER_RADAR_430_OBJECTS_432: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1074 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1074 30;
|
||||
|
||||
BO_ 1075 CORNER_RADAR_430_OBJECTS_433: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1075 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1075 30;
|
||||
|
||||
BO_ 1076 CORNER_RADAR_430_OBJECTS_434: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1076 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1076 30;
|
||||
|
||||
BO_ 1077 CORNER_RADAR_430_OBJECTS_435: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1077 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1077 30;
|
||||
|
||||
BO_ 1078 CORNER_RADAR_430_OBJECTS_436: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1078 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1078 30;
|
||||
|
||||
BO_ 1079 CORNER_RADAR_430_OBJECTS_437: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1079 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1079 30;
|
||||
|
||||
BO_ 1088 CORNER_RADAR_430_OBJECTS_440: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1088 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1088 30;
|
||||
|
||||
BO_ 1089 CORNER_RADAR_430_OBJECTS_441: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1089 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1089 30;
|
||||
|
||||
BO_ 1090 CORNER_RADAR_430_OBJECTS_442: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1090 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1090 30;
|
||||
|
||||
BO_ 1091 CORNER_RADAR_430_OBJECTS_443: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1091 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1091 30;
|
||||
|
||||
BO_ 1092 CORNER_RADAR_430_OBJECTS_444: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1092 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1092 30;
|
||||
|
||||
BO_ 1093 CORNER_RADAR_430_OBJECTS_445: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1093 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1093 30;
|
||||
|
||||
BO_ 1094 CORNER_RADAR_430_OBJECTS_446: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1094 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1094 30;
|
||||
|
||||
BO_ 1095 CORNER_RADAR_430_OBJECTS_447: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||
CM_ BO_ 1095 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ 1095 30;
|
||||
76
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.py
Executable file
76
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.py
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
|
||||
HEADER = """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_
|
||||
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 RADAR
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def write_object_msg(f, addr):
|
||||
name = f"CORNER_RADAR_430_OBJECTS_{addr:x}"
|
||||
f.write(f"""
|
||||
BO_ {addr} {name}: 32 RADAR
|
||||
SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
""")
|
||||
for slot in range(7):
|
||||
bit = 32 + slot * 32
|
||||
prefix = f"SLOT{slot + 1}"
|
||||
f.write(f""" SG_ {prefix}_DISTANCE_RAW : {bit}|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ {prefix}_META_13_15 : {bit + 13}|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ {prefix}_META_BYTE_2 : {bit + 16}|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ {prefix}_META_BYTE_3 : {bit + 24}|8@1+ (1,0) [0|255] "" XXX
|
||||
""")
|
||||
f.write(f"""CM_ BO_ {addr} "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
|
||||
BA_ "GenMsgCycleTime" BO_ {addr} 30;
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
|
||||
out_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), dbc_name)
|
||||
with open(out_path, "w", encoding="ascii") as f:
|
||||
f.write(HEADER)
|
||||
f.write('BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;\n')
|
||||
f.write('BA_DEF_DEF_ "GenMsgCycleTime" 0;\n')
|
||||
for addr in range(0x430, 0x438):
|
||||
write_object_msg(f, addr)
|
||||
for addr in range(0x440, 0x448):
|
||||
write_object_msg(f, addr)
|
||||
1178
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.dbc
Normal file
1178
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.dbc
Normal file
File diff suppressed because it is too large
Load Diff
106
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.py
Executable file
106
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.py
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
|
||||
hyundai_path = os.path.dirname(os.path.realpath(__file__))
|
||||
with open(os.path.join(hyundai_path, dbc_name), "w", encoding='utf-8') as f:
|
||||
f.write("""
|
||||
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
|
||||
""")
|
||||
|
||||
for a in range(0x210, 0x210 + 16):
|
||||
f.write(f"""
|
||||
BO_ {a} RADAR_TRACK_{a:x}: 32 RADAR
|
||||
SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
|
||||
SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
|
||||
SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
|
||||
SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
|
||||
SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
|
||||
SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
|
||||
SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
|
||||
SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
|
||||
SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
|
||||
SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
|
||||
SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
|
||||
SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
|
||||
SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
|
||||
SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
|
||||
SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
|
||||
SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
|
||||
SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
|
||||
SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
|
||||
""")
|
||||
for a in range(0x3a5, 0x3a5 + 32):
|
||||
f.write(f"""
|
||||
BO_ {a} RADAR_TRACK_{a:x}: 24 RADAR
|
||||
SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
|
||||
SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
|
||||
SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
|
||||
SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
|
||||
SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
|
||||
SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
|
||||
SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
|
||||
""")
|
||||
|
||||
# Group 3 radar object list:
|
||||
# 30 one-object messages at 20 Hz, with an empty distance sentinel of 0x7ff.
|
||||
for a in range(0x400, 0x400 + 30):
|
||||
f.write(f"""
|
||||
BO_ {a} RADAR_TRACK_{a:x}: 24 RADAR
|
||||
SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
|
||||
SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
|
||||
SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
|
||||
SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
|
||||
""")
|
||||
65
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_kia_denso_front_radar.py
Executable file
65
iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_kia_denso_front_radar.py
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
|
||||
hyundai_path = os.path.dirname(os.path.realpath(__file__))
|
||||
with open(os.path.join(hyundai_path, dbc_name), "w", encoding="utf-8") as f:
|
||||
f.write("""
|
||||
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
|
||||
""")
|
||||
|
||||
# EN: The Denso DNMWR006 radar in the 2018-2019 Kia Sorento UM publishes
|
||||
# eight stable tracked objects at 20 Hz from 0x500 through 0x507.
|
||||
# Do not decode 0x508+ distance-sorted raw detections as stable tracks.
|
||||
# KO: 2018-2019 Kia Sorento UM의 Denso DNMWR006 레이더는 0x500~0x507에서
|
||||
# 안정적인 추적 객체 8개를 20Hz로 전송함. 0x508 이후의 거리순 raw
|
||||
# detection은 안정적인 트랙으로 디코딩하지 않음.
|
||||
for address in range(0x500, 0x508):
|
||||
f.write(f"""
|
||||
BO_ {address} RADAR_TRACK_{address:x}: 8 RADAR
|
||||
SG_ COUNTER : 7|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ LONG_DIST : 15|16@0+ (0.00625,0) [0|409.59375] "m" XXX
|
||||
SG_ LAT_DIST : 31|11@0- (0.0625,0) [-64|63.9375] "m" XXX
|
||||
SG_ OBJECT_FLAGS_1 : 36|5@0+ (1,0) [0|31] "" XXX
|
||||
SG_ OBJECT_FLAG_2 : 47|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ REL_SPEED : 46|12@0- (0.015625,0) [-32|31.984375] "m/s" XXX
|
||||
SG_ OBJECT_STATE : 50|3@0+ (1,0) [0|7] "" XXX
|
||||
SG_ OBJECT_DETAIL : 63|8@0+ (1,0) [0|255] "" XXX
|
||||
""")
|
||||
@@ -1,4 +1,4 @@
|
||||
CM_ "IMPORT _hyundai_canfd_common.dbc";
|
||||
CM_ "IMPORT _hyundai_common.dbc";
|
||||
|
||||
BO_ 67 DATC13: 8 XXX
|
||||
SG_ CF_Datc_AcDisp : 22|2@1+ (1,0) [0|0] "" XXX
|
||||
|
||||
@@ -1341,6 +1341,17 @@ BO_ 273 TCU11: 8 TCU
|
||||
BO_ 16 ACU13: 8 ACU
|
||||
SG_ CF_Acu_CshAct : 0|1@1+ (1.0,0.0) [0.0|1.0] "" CUBIS,IBOX,ODS
|
||||
|
||||
BO_ 1007 CRUISE_BUTTON_ALT: 8 XXX
|
||||
SG_ SET_ME_1 : 52|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseSwMain : 58|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseSwState : 60|3@1+ (1,0) [0|7] "" XXX
|
||||
|
||||
BO_ 1046 CRUISE_BUTTON_LFA: 8 XXX
|
||||
SG_ NEW_SIGNAL_2 : 49|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ NEW_SIGNAL_1 : 54|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ NEW_SIGNAL_3 : 57|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseSwLfa : 58|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 1040 CGW_USM1: 8 BCM
|
||||
SG_ CF_Gway_ATTurnRValue : 0|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
|
||||
SG_ CF_Gway_PTGMRValue : 2|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
|
||||
@@ -1384,6 +1395,8 @@ BO_ 1290 SCC13: 8 SCC
|
||||
SG_ SCC_Equip : 3|1@1+ (1,0) [0|1] "" ESC
|
||||
SG_ AebDrvSetStatus : 4|3@1+ (1,0) [0|7] "" CLU,ESC
|
||||
SG_ Lead_Veh_Dep_Alert_USM : 13|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ NEW_SIGNAL_1 : 23|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_2 : 31|8@0+ (1,0) [0|255] "" XXX
|
||||
|
||||
BO_ 1287 TCS15: 4 ESC
|
||||
SG_ ABS_W_LAMP : 0|1@1+ (1.0,0.0) [0.0|1.0] "" _4WD,CLU,CUBIS,IBOX
|
||||
@@ -1478,18 +1491,21 @@ BO_ 905 SCC14: 8 SCC
|
||||
SG_ ComfortBandLower : 6|6@1+ (0.02,0) [0|1.26] "m/s^2" ESC
|
||||
SG_ JerkUpperLimit : 12|7@1+ (0.1,0) [0|12.7] "m/s^3" ESC
|
||||
SG_ JerkLowerLimit : 19|7@1+ (0.1,0) [0|12.7] "m/s^3" ESC
|
||||
SG_ NEW_SIGNAL_1 : 26|6@1+ (1,0) [0|63] "" XXX
|
||||
SG_ ACCMode : 32|3@1+ (1,0) [0|7] "" CLU,HUD,LDWS_LKAS,ESC
|
||||
SG_ ObjGap : 56|8@1+ (1,0) [0|255] "" CLU,HUD,ESC
|
||||
SG_ ObjDistStat : 42|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ NEW_SIGNAL_2 : 55|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ ObjGap : 56|8@1+ (1,0) [0|255] "" CLU,HUD,ESC
|
||||
|
||||
BO_ 1157 LFAHDA_MFC: 4 XXX
|
||||
BO_ 1157 LFAHDA_MFC: 8 XXX
|
||||
SG_ HDA_USM : 0|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ HDA_Active : 2|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ HDA_Icon_State : 3|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ HDA_Chime : 7|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ HDA_VSetReq : 8|8@1+ (1,0) [0|255] "km/h" XXX
|
||||
SG_ LFA_SysWarning : 16|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ NEW_SIGNAL_1 : 20|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ HDA_Icon_Wheel : 20|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ HDA_LdwSysState : 21|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ LFA_Icon_State : 24|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ LFA_USM : 27|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ HDA_SysWarning : 29|2@1+ (1,0) [0|3] "" XXX
|
||||
@@ -1497,11 +1513,10 @@ BO_ 1157 LFAHDA_MFC: 4 XXX
|
||||
BO_ 913 BCM_PO_11: 8 Vector__XXX
|
||||
SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
|
||||
SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
|
||||
SG_ LDA_BTN : 4|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ LFA_Pressed : 4|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 1426 LABEL11: 8 XXX
|
||||
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ CC_ACT : 35|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 910 WHL_SPD12_FS: 5 iBAU
|
||||
SG_ CRC : 0|8@1+ (1,0) [0|0] "" Vector__XXX
|
||||
@@ -1522,7 +1537,10 @@ BO_ 865 ADAS_PRK_11: 8 ADAS_PRK
|
||||
SG_ PCA_CHECK_SUM : 48|8@1+ (1,0) [0|0] "" Vector__XXX
|
||||
|
||||
BO_ 882 ELECT_GEAR: 8 XXX
|
||||
SG_ Elect_Gear_Shifter : 16|4@1+ (1,0) [0|7] "" CLU
|
||||
SG_ Elect_Gear_Shifter : 16|4@1+ (1,0) [0|7] "" CLU
|
||||
SG_ Elect_Gear_Shifter_NEXO : 16|16@1+ (1,0) [0|65535] "" CLU
|
||||
SG_ Elect_Gear_Step : 22|3@0+ (1,0) [0|7] "" XXX
|
||||
SG_ Elect_Motor_Speed : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ SLC_ON : 31|1@0+ (1,0) [0|1] "" CLU
|
||||
SG_ SLC_SET_SPEED : 32|8@1+ (1,0) [0|255] "" CLU
|
||||
|
||||
@@ -1534,14 +1552,12 @@ BO_ 881 E_EMS11: 8 XXX
|
||||
SG_ Cruise_Limit_Target : 23|8@1+ (1,0) [0|15] "" XXX
|
||||
SG_ Accel_Pedal_Pos : 31|8@1+ (1,0) [0|254] "" XXX
|
||||
SG_ CR_Vcu_AccPedDep_Pos : 56|8@1+ (1,0) [0|254] "" XXX
|
||||
SG_ Engine_Run : 14|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ N : 18|13@1+ (1,0) [0|15] "" XXX
|
||||
|
||||
BO_ 1355 EV_PC6: 8 CGW
|
||||
SG_ CF_Vcu_SbwWarnMsg : 16|3@1+ (1,0) [0|7] "" Vector__XXX
|
||||
|
||||
BO_ 1429 E_CRUISE_CONTROL: 8 XXX
|
||||
SG_ CRUISE_LAMP_M : 50|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CRUISE_LAMP_S : 51|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 1430 EV_PC2: 8 CGW
|
||||
SG_ CR_Ldc_ActVol_LS_V : 32|8@1+ (0.1,0) [0|0] "V" Vector__XXX
|
||||
|
||||
@@ -1584,7 +1600,7 @@ BO_ 352 AHB1: 8 iBAU
|
||||
SG_ CF_Ahb_Bzzr : 26|1@1+ (1,0) [0|1] "" Vector__XXX
|
||||
SG_ CF_Ahb_ChkSum : 56|8@1+ (1,0) [0|255] "" Vector__XXX
|
||||
|
||||
BO_ 1191 MFC_4a7: 8 XXX
|
||||
BO_ 1191 MFC_4a7: 2 XXX
|
||||
SG_ PAINT1 : 0|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 1162 BCA11: 8 BCW
|
||||
@@ -1658,33 +1674,22 @@ BO_ 1348 Navi_HU: 8 XXX
|
||||
SG_ SpeedLim_Nav_General : 29|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ SpeedLim_Nav_Cam : 30|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 683 ESCC: 8 XXX
|
||||
SG_ FCA_CmdAct : 0|1@1+ (1,0) [0|1] "" ESC
|
||||
SG_ CF_VSM_Warn_FCA11 : 1|2@1+ (1,0) [0|3] "" ACU,CLU,ESC
|
||||
SG_ AEB_CmdAct : 3|1@1+ (1,0) [0|1] "" ESC
|
||||
SG_ CF_VSM_Warn_SCC12 : 4|2@1+ (1,0) [0|3] "" CLU,ESC,IAP
|
||||
SG_ CF_VSM_DecCmdAct_SCC12 : 6|1@1+ (1,0) [0|1] "" ESC
|
||||
SG_ CF_VSM_DecCmdAct_FCA11 : 7|1@1+ (1,0) [0|1] "" ESC
|
||||
SG_ CR_VSM_DecCmd_SCC12 : 8|8@1+ (0.01,0) [0|2.55] "g" ESC
|
||||
SG_ ObjValid : 16|1@1+ (1,0) [0|1] "" CLU,ESC,TCU
|
||||
SG_ ACC_ObjStatus : 17|2@1+ (1,0) [0|3] "" ABS,ESC
|
||||
SG_ ACC_ObjLatPos : 24|9@1+ (0.1,-20) [-20|31.1] "m" ABS,ESC
|
||||
SG_ ACC_ObjRelSpd : 44|12@1+ (0.1,-170) [-170|239.5] "m/s" ABS,ESC
|
||||
SG_ ACC_ObjDist : 33|11@1+ (0.1,0) [0|204.7] "m" ABS,ESC
|
||||
SG_ CR_VSM_DecCmd_FCA11 : 56|8@1+ (0.01,0) [0|2.55] "g" ESC
|
||||
|
||||
BO_ 1291 EV_Info: 8 XXX
|
||||
SG_ OPKR_EV_Charge_Level : 17|7@1+ (1,0) [0|100] "%" XXX
|
||||
CM_ "BO_ E_EMS11: All (plug-in) hybrids use this gas signal: CR_Vcu_AccPedDep_Pos, and all EVs use the Accel_Pedal_Pos signal. See hyundai/values.py for a specific car list";
|
||||
CM_ 145 "Contains signal with accelerator pedal press. Used by fuel cell hydrogen-powered (FCEV) cars such as the 2021 Hyundai Nexo.";
|
||||
CM_ 512 "Contains signal with gear shifter. Used by fuel cell hydrogen-powered (FCEV) cars such as the 2021 Hyundai Nexo.";
|
||||
CM_ SG_ 871 CF_Lvr_IsgState "Idle Stop and Go";
|
||||
CM_ SG_ 1056 SCCInfoDisplay "Goes to 1 for a second while transitioning from Cruise Control to No Message";
|
||||
CM_ SG_ 1348 SpeedLim_Nav_Clu "Speed limit displayed on Nav, Cluster and HUD";
|
||||
CM_ SG_ 1348 SpeedLim_Nav_Cam "Speed limit if speed cam exist";
|
||||
VAL_ 882 Elect_Gear_Shifter_NEXO 1546 "D" 2314 "N" 2566 "R" 2569 "P";
|
||||
|
||||
VAL_ 274 CUR_GR 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 7 "D" 8 "D" 14 "R" 0 "P";
|
||||
VAL_ 512 HYDROGEN_GEAR_SHIFTER 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
|
||||
VAL_ 871 CF_Lvr_IsgState 0 "enabled" 1 "activated" 2 "unknown" 3 "disabled";
|
||||
VAL_ 871 CF_Lvr_Gear 12 "T" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
|
||||
VAL_ 882 Elect_Gear_Shifter 4 "S" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
|
||||
VAL_ 882 Elect_Gear_Shifter 4 "S" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P" 12 "T";
|
||||
VAL_ 905 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
|
||||
VAL_ 905 ObjDistStat 0 "no_object" 1 "receding" 2 "approaching";
|
||||
VAL_ 909 CF_VSM_Warn 2 "FCW" 3 "AEB";
|
||||
|
||||
@@ -204,7 +204,7 @@ BO_ 605 DAS_road: 6 XXX
|
||||
BO_ 1160 DAS_steeringControl: 4 PARTY
|
||||
SG_ DAS_steeringControlChecksum : 24|8@1+ (1,0) [0|255] "" aps
|
||||
SG_ DAS_steeringControlCounter : 16|4@1+ (1,0) [0|15] "" aps
|
||||
SG_ DAS_steeringControlType : 23|2@0+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_steeringControlType : 23|3@0+ (1,0) [0|7] "" aps
|
||||
SG_ DAS_steeringAngleRequest : 6|15@0+ (0.1,-1638.35) [-1638.35|1638.35] "deg" aps
|
||||
SG_ DAS_steeringHapticRequest : 7|1@0+ (1,0) [0|1] "" aps
|
||||
|
||||
@@ -426,7 +426,7 @@ VAL_ 599 DI_uiSpeedUnits 0 "DI_SPEED_MPH" 1 "DI_SPEED_KPH" ;
|
||||
VAL_ 599 DI_uiSpeed 255 "DI_UI_SPEED_SNA" ;
|
||||
VAL_ 599 DI_vehicleSpeed 4095 "SNA" ;
|
||||
VAL_ 637 APS_eacAllow 0 "INHIBIT" 1 "ALLOW" 2 "RESERVED" 3 "SNA";
|
||||
VAL_ 1160 DAS_steeringControlType 2 "LANE_KEEP_ASSIST" 0 "NONE" 1 "ANGLE_CONTROL" 3 "EMERGENCY_LANE_KEEP" ;
|
||||
VAL_ 1160 DAS_steeringControlType 2 "LANE_KEEP_ASSIST" 0 "NONE" 1 "ANGLE_CONTROL" 3 "EMERGENCY_LANE_KEEP" 4 "FSD" ;
|
||||
VAL_ 1160 DAS_steeringAngleRequest 16384 "ZERO_ANGLE" ;
|
||||
VAL_ 297 SCCM_steeringAngleValidity 3 "SNA" 2 "INIT" 0 "INVALID" 1 "VALID" ;
|
||||
VAL_ 297 SCCM_steeringAngleSensorStatus 0 "OK" 1 "INIT" 2 "ERROR" 3 "ERROR_INIT" ;
|
||||
|
||||
@@ -197,15 +197,24 @@ BO_ 1001 DAS_bodyControls: 8 VEH
|
||||
SG_ DAS_headlightRequest : 0|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_hazardLightRequest : 2|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_wiperSpeed : 4|4@1+ (1,0) [0|15] "" aps
|
||||
SG_ DAS_turnIndicatorRequest : 8|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_highLowBeamDecision : 10|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_heaterRequest : 12|2@1+ (1,0) [0|2] "" aps
|
||||
SG_ DAS_turnIndicatorRequestReason : 17|4@1+ (1,0) [0|8] "" aps
|
||||
SG_ DAS_autopilotActive : 24|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ DAS_accActive : 29|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ DAS_turnIndicatorRequest : 8|3@1+ (1,0) [0|4] "" aps
|
||||
SG_ DAS_highLowBeamDecision : 11|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_heaterRequest : 13|2@1+ (1,0) [0|2] "" aps
|
||||
SG_ DAS_highLowBeamOffReason : 15|3@1+ (1,0) [0|5] "" aps
|
||||
SG_ DAS_turnIndicatorRequestReason : 18|4@1+ (1,0) [0|12] "" aps
|
||||
SG_ DAS_dynamicBrakeLightRequest : 22|1@1+ (1,0) [0|1] "" aps
|
||||
SG_ DAS_radarHeaterRequest : 23|1@1+ (1,0) [0|1] "" aps
|
||||
SG_ DAS_ahlbOverride : 24|1@1+ (1,0) [0|1] "" aps
|
||||
SG_ DAS_mirrorFoldRequest : 25|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_bodyControlsCounter : 52|4@1+ (1,0) [0|15] "" aps
|
||||
SG_ DAS_bodyControlsChecksum : 56|8@1+ (1,0) [0|255] "" aps
|
||||
|
||||
BO_ 994 VCLEFT_lightStatus: 7 VEH
|
||||
SG_ VCLEFT_turnSignalStatus : 4|2@1+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 995 VCRIGHT_lightStatus: 2 VEH
|
||||
SG_ VCRIGHT_turnSignalStatus : 4|2@1+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 1013 ID3F5VCFRONT_lighting: 8 VEH
|
||||
SG_ VCFRONT_lowBeamsCalibrated : 62|1@1+ (1,0) [0|1] "" Receiver
|
||||
SG_ VCFRONT_lowBeamsOnForDRL : 61|1@1+ (1,0) [0|1] "" Receiver
|
||||
@@ -388,5 +397,10 @@ BO_ 826 ID33AUI_rangeSOC: 8 VehicleBus
|
||||
BO_ 306 ID132HVBattAmpVolt: 8 VehicleBus
|
||||
SG_ BattVoltage132 : 0|16@1+ (0.01,0) [0|655.35] "V" Receiver
|
||||
|
||||
BO_ 950 ID3B6UI_odometer: 8 VehicleBus
|
||||
SG_ UI_odometer : 0|32@1+ (0.001,0) [0|4294967.295] "km" Receiver
|
||||
SG_ UI_odometerCounter : 52|4@1+ (1,0) [0|15] "" Receiver
|
||||
SG_ UI_odometerChecksum : 56|8@1+ (1,0) [0|255] "" Receiver
|
||||
|
||||
BO_ 658 ID292BMS_SOC: 8 VehicleBus
|
||||
SG_ SOCUI292 : 10|10@1+ (0.1,0) [0|102.3] "%" Receiver
|
||||
|
||||
@@ -541,21 +541,21 @@ BO_ 1437 mRemotestart_FFB: 8 Vector__XXX
|
||||
SG_ RSF_Tastencode_2 : 8|8@1+ (1,0) [1|255] "" Vector__XXX
|
||||
SG_ RSF_Tastencode_Maske : 16|8@1+ (1,0) [1|255] "" Vector__XXX
|
||||
|
||||
BO_ 640 Motor_1: 8 XXX
|
||||
SG_ Fahrerwunschmoment : 56|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ mechanisches_Motor_Verlustmomen : 48|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ Fahrpedalwert_oder_Drosselklapp : 40|8@1+ (0.4,0) [0|101.6] "%" XXX
|
||||
SG_ inneres_Motor_Moment_ohne_exter : 32|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ Motordrehzahl : 16|16@1+ (0.25,0) [0|16256] "U/min" XXX
|
||||
SG_ inneres_Motor_Moment : 8|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ Momentenangaben_ungenau : 7|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Fehlerstatus_Getriebe_Momentene : 6|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Fehlerstatus_Brems_Momenteneing : 5|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Time_Out_Bremsen_Botschaft : 4|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Kupplungsschalter : 3|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Kickdownschalter : 2|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Fahrpedalwert_ungenau__Motor_1_ M : 1|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Leergasinformation : 0|1@1+ (1,0) [0|0] "" XXX
|
||||
BO_ 640 Motor_1: 8 Motor
|
||||
SG_ MO1_Wunschmo : 56|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Verlustmo : 48|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Pedalwert : 40|8@1+ (0.4,0) [0|101.6] "%" XXX
|
||||
SG_ MO1_Mo_o_ex : 32|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Drehzahl : 16|16@1+ (0.25,0) [0|16256] "1/min" XXX
|
||||
SG_ MO1_Mo_m_ex : 8|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Sta_MotMo : 7|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Sta_Getr : 6|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Sta_Bremse : 5|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_TiOut_Br : 4|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Kup_schalt : 3|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Kickdown : 2|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Sta_Pedal : 1|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Leergas : 0|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 262 Master_3: 8 XXX
|
||||
SG_ Frei_Master_3_1 : 56|8@1+ (1,0) [0|0] "" XXX
|
||||
@@ -1353,6 +1353,12 @@ BO_ 982 APD_1: 8 XXX
|
||||
SG_ APD_AngleOffSet : 42|11@1+ (0.01,-10) [-10|10.47] "deg" XXX
|
||||
SG_ APD_GripFactor : 53|11@1+ (0.001,0) [0|2.047] "" XXX
|
||||
|
||||
BO_ 983 SNG_1: 8 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ SNG_HandoffActive : 12|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ SNG_DecelReq : 16|8@1+ (0.048,-7.968) [-7.968|4.224] "Unit_MeterPerSeconSquar" XXX
|
||||
|
||||
BO_ 210 HCA_1: 5 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|15] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import re
|
||||
import json
|
||||
import os
|
||||
import unicodedata
|
||||
|
||||
from iqdbc.car.common.basedir import BASEDIR
|
||||
from iqdbc.car.docs import get_all_footnotes, get_params_for_docs
|
||||
from iqdbc.car.values import PLATFORMS
|
||||
|
||||
CAR_LIST_JSON_OUT = os.path.join(BASEDIR, "../", "iqpilot", "car", "car_list.json")
|
||||
|
||||
|
||||
def build_car_catalog() -> dict[str, dict[str, list[str] | str]]:
|
||||
collected_footnote = get_all_footnotes()
|
||||
@@ -62,8 +57,6 @@ def collect_car_docs(platforms, footnotes) -> dict[str, dict[str, list[str] | st
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
catalog = build_car_catalog()
|
||||
|
||||
with open(CAR_LIST_JSON_OUT, "w") as json_file:
|
||||
json.dump(catalog, json_file, indent=2, ensure_ascii=False)
|
||||
print(f"Generated and written to {CAR_LIST_JSON_OUT}")
|
||||
# build_car_catalog() is the raw platform source; the shipped catalog is generated
|
||||
# (and encoded to its on-disk envelope) by the main-repo entry point:
|
||||
print("run: python -m openpilot.iqpilot.selfdrive.car.vehicle_catalog")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
Always-on-Lateral adapter for Chrysler. CarState reads the LKAS toggle button
|
||||
(and the forwarded LKAS heartbeat); CarController tracks the AOL state and, when
|
||||
AOL is available, drives the LKAS_DISABLED bit the dash reads from the heartbeat.
|
||||
"""
|
||||
from enum import StrEnum
|
||||
from collections import namedtuple
|
||||
|
||||
from iqdbc.car import Bus, structs
|
||||
from iqdbc.car.chrysler.values import RAM_CARS
|
||||
|
||||
from iqdbc.lvbs.aol_base import AolCarStateBase
|
||||
from iqdbc.can.parser import CANParser
|
||||
|
||||
AolDataIQ = namedtuple("AolDataIQ",
|
||||
["enable_aol", "paused", "lkas_disabled"])
|
||||
|
||||
AolDataIQ = namedtuple("AolDataIQ", ["enable_aol", "paused", "lkas_disabled"])
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
_HEARTBIT_FIELDS = ("LKAS_DISABLED", "AUTO_HIGH_BEAM", "FORWARD_1", "FORWARD_2", "FORWARD_3")
|
||||
|
||||
|
||||
class AolCarController:
|
||||
def __init__(self):
|
||||
@@ -23,28 +25,18 @@ class AolCarController:
|
||||
|
||||
@staticmethod
|
||||
def create_lkas_heartbit(packer, lkas_heartbit, aol):
|
||||
# LKAS_HEARTBIT (0x2D9) LKAS heartbeat
|
||||
values = {s: lkas_heartbit[s] for s in [
|
||||
"LKAS_DISABLED",
|
||||
"AUTO_HIGH_BEAM",
|
||||
"FORWARD_1",
|
||||
"FORWARD_2",
|
||||
"FORWARD_3",
|
||||
]}
|
||||
|
||||
values = {name: lkas_heartbit[name] for name in _HEARTBIT_FIELDS}
|
||||
if aol.enable_aol:
|
||||
values["LKAS_DISABLED"] = 1 if aol.lkas_disabled else 0
|
||||
|
||||
return packer.make_can_msg("LKAS_HEARTBIT", 0, values)
|
||||
|
||||
@staticmethod
|
||||
def aol_status_update(CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS) -> AolDataIQ:
|
||||
enable_aol = CC_IQ.aol.available
|
||||
paused = CC_IQ.aol.enabled and not CC.latActive
|
||||
|
||||
# A tap of the LKAS button flips the driver's "LKAS disabled" preference.
|
||||
if any(be.type == ButtonType.lkas and be.pressed for be in CS.out.buttonEvents):
|
||||
CS.lkas_disabled = not CS.lkas_disabled
|
||||
|
||||
return AolDataIQ(enable_aol, paused, CS.lkas_disabled)
|
||||
|
||||
def update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS) -> None:
|
||||
@@ -55,35 +47,27 @@ class AolCarState(AolCarStateBase):
|
||||
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
|
||||
super().__init__(CP, CP_IQ)
|
||||
self.lkas_heartbit = 0
|
||||
|
||||
self.init_lkas_disabled = False
|
||||
self.lkas_disabled = False
|
||||
|
||||
@staticmethod
|
||||
def get_parser(CP, pt_messages, cam_messages) -> None:
|
||||
if CP.carFingerprint in RAM_CARS:
|
||||
pt_messages += [
|
||||
("Center_Stack_2", 1),
|
||||
]
|
||||
pt_messages.append(("Center_Stack_2", 1))
|
||||
else:
|
||||
pt_messages.append(("TRACTION_BUTTON", 1))
|
||||
cam_messages.append(("LKAS_HEARTBIT", 1))
|
||||
|
||||
def get_lkas_button(self, cp, cp_cam):
|
||||
def _read_lkas_button(self, cp, cp_cam) -> int:
|
||||
if self.CP.carFingerprint in RAM_CARS:
|
||||
lkas_button = cp.vl["Center_Stack_2"]["LKAS_Button"]
|
||||
else:
|
||||
lkas_button = cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"]
|
||||
self.lkas_heartbit = cp_cam.vl["LKAS_HEARTBIT"]
|
||||
if not self.init_lkas_disabled:
|
||||
self.lkas_disabled = cp_cam.vl["LKAS_HEARTBIT"]["LKAS_DISABLED"]
|
||||
self.init_lkas_disabled = True
|
||||
return cp.vl["Center_Stack_2"]["LKAS_Button"]
|
||||
|
||||
return lkas_button
|
||||
self.lkas_heartbit = cp_cam.vl["LKAS_HEARTBIT"]
|
||||
if not self.init_lkas_disabled:
|
||||
self.lkas_disabled = cp_cam.vl["LKAS_HEARTBIT"]["LKAS_DISABLED"]
|
||||
self.init_lkas_disabled = True
|
||||
return cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"]
|
||||
|
||||
def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
|
||||
cp = can_parsers[Bus.pt]
|
||||
cp_cam = can_parsers[Bus.cam]
|
||||
|
||||
self.prev_lkas_button = self.lkas_button
|
||||
self.lkas_button = self.get_lkas_button(cp, cp_cam)
|
||||
self.lkas_button = self._read_lkas_button(can_parsers[Bus.pt], can_parsers[Bus.cam])
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
from iqdbc.car import Bus, structs
|
||||
from iqdbc.can.parser import CANParser
|
||||
from iqdbc.car.chrysler.values import RAM_HD
|
||||
from iqdbc.lvbs.car.chrysler.values_ext import BUTTONS
|
||||
|
||||
|
||||
class CarStateExt:
|
||||
def __init__(self, CP, CP_IQ):
|
||||
self.CP = CP
|
||||
self.CP_IQ = CP_IQ
|
||||
|
||||
self.button_events = []
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]):
|
||||
cp = can_parsers[Bus.pt]
|
||||
|
||||
button_events = []
|
||||
for button in BUTTONS:
|
||||
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
|
||||
if self.button_states[button.event_type] != state:
|
||||
event = structs.CarState.ButtonEvent.new_message()
|
||||
event.type = button.event_type
|
||||
event.pressed = state
|
||||
button_events.append(event)
|
||||
self.button_states[button.event_type] = state
|
||||
self.button_events = button_events
|
||||
|
||||
if self.CP.carFingerprint in RAM_HD:
|
||||
ret.steeringAngleDeg = cp.vl["STEERING"]["STEERING_ANGLE"]
|
||||
@@ -1,23 +1,27 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
|
||||
Chrysler low-speed steering gate: overrides the stock LKAS control bit when the
|
||||
no-min-steering-speed option is set, and holds the RAM DT engagement window.
|
||||
"""
|
||||
from iqdbc.car import structs
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.chrysler.values import RAM_DT
|
||||
from iqdbc.lvbs.car.chrysler.values_ext import ChryslerFlagsIQ
|
||||
from iqdbc.lvbs.car.chrysler.iq_values import ChryslerFlagsIQ
|
||||
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
|
||||
|
||||
class CarControllerExt:
|
||||
class IQCarController:
|
||||
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
|
||||
self.CP = CP
|
||||
self.CP_IQ = CP_IQ
|
||||
|
||||
def get_lkas_control_bit(self, CS: CarStateBase, CC: structs.CarControl, lkas_control_bit: bool) -> bool:
|
||||
if self.CP_IQ.flags & ChryslerFlagsIQ.NO_MIN_STEERING_SPEED:
|
||||
lkas_control_bit = CC.latActive
|
||||
elif self.CP.carFingerprint in RAM_DT:
|
||||
return CC.latActive
|
||||
|
||||
if self.CP.carFingerprint in RAM_DT:
|
||||
if self.CP.minEnableSpeed <= CS.out.vEgo <= self.CP.minEnableSpeed + 0.5:
|
||||
lkas_control_bit = True
|
||||
if self.CP.minEnableSpeed >= 14.5 and CS.out.gearShifter != GearShifter.drive:
|
||||
32
iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carstate.py
Normal file
32
iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carstate.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
|
||||
Chrysler cruise-button reader: emits edge ButtonEvents for the ACC steering-wheel
|
||||
buttons so IQ.Pilot can react to accel/decel/cancel/resume.
|
||||
"""
|
||||
from enum import StrEnum
|
||||
|
||||
from iqdbc.car import Bus, structs
|
||||
from iqdbc.can.parser import CANParser
|
||||
from iqdbc.lvbs.car.chrysler.iq_values import BUTTONS
|
||||
|
||||
|
||||
class IQCarState:
|
||||
def __init__(self, CP, CP_IQ):
|
||||
self.CP = CP
|
||||
self.CP_IQ = CP_IQ
|
||||
self.button_events: list = []
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
|
||||
cp = can_parsers[Bus.pt]
|
||||
events = []
|
||||
for button in BUTTONS:
|
||||
pressed = cp.vl[button.can_addr][button.can_msg] in button.values
|
||||
if pressed != self.button_states[button.event_type]:
|
||||
event = structs.CarState.ButtonEvent.new_message()
|
||||
event.type = button.event_type
|
||||
event.pressed = pressed
|
||||
events.append(event)
|
||||
self.button_states[button.event_type] = pressed
|
||||
self.button_events = events
|
||||
@@ -1,7 +1,9 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
IQ.Pilot Chrysler extension flags + the cruise-button table read by the AOL
|
||||
cruise-button reader.
|
||||
"""
|
||||
from collections import namedtuple
|
||||
from enum import IntFlag
|
||||
|
||||
@@ -20,5 +22,3 @@ BUTTONS = [
|
||||
|
||||
class ChryslerFlagsIQ(IntFlag):
|
||||
NO_MIN_STEERING_SPEED = 1
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user