IQ.Pilot Prebuilt Release @ 27f668a
This commit is contained in:
1
artifacts/package_runtime/iqdbc/lvbs/tools/__init__.py
Normal file
1
artifacts/package_runtime/iqdbc/lvbs/tools/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
45
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/clear_dtc.py
Normal file
45
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/clear_dtc.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import argparse
|
||||
from subprocess import check_output, CalledProcessError
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.uds import UdsClient, MessageTimeoutError, SESSION_TYPE, DTC_GROUP_TYPE
|
||||
from iqdbc.car.structs import CarParams
|
||||
from panda import Panda
|
||||
|
||||
parser = argparse.ArgumentParser(description="clear DTC status")
|
||||
parser.add_argument("addr", type=lambda x: int(x,0), nargs="?", default=0x7DF) # default is functional (broadcast) address
|
||||
parser.add_argument("--bus", type=int, default=0)
|
||||
parser.add_argument('--debug', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
try:
|
||||
check_output(["pidof", "pandad"])
|
||||
print("pandad is running, please kill openpilot before running this script! (aborted)")
|
||||
sys.exit(1)
|
||||
except CalledProcessError as e:
|
||||
if e.returncode != 1: # 1 == no process found (pandad not running)
|
||||
raise e
|
||||
|
||||
panda = Panda()
|
||||
panda.set_safety_mode(CarParams.SafetyModel.elm327)
|
||||
uds_client = UdsClient(panda, args.addr, bus=args.bus)
|
||||
print("extended diagnostic session ...")
|
||||
try:
|
||||
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
|
||||
except MessageTimeoutError:
|
||||
# functional address isn't properly handled so a timeout occurs
|
||||
if args.addr != 0x7DF:
|
||||
raise
|
||||
print("clear diagnostic info ...")
|
||||
try:
|
||||
uds_client.clear_diagnostic_information(DTC_GROUP_TYPE.ALL)
|
||||
except MessageTimeoutError:
|
||||
# functional address isn't properly handled so a timeout occurs
|
||||
if args.addr != 0x7DF:
|
||||
pass
|
||||
print("")
|
||||
print("you may need to power cycle your vehicle now")
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import iqpilot.cereal.messaging as messaging
|
||||
from iqdbc.car.disable_ecu import disable_ecu
|
||||
from iqpilot.selfdrive.car.card import can_comm_callbacks
|
||||
|
||||
if __name__ == "__main__":
|
||||
sendcan = messaging.pub_sock('sendcan')
|
||||
logcan = messaging.sub_sock('can')
|
||||
can_callbacks = can_comm_callbacks(logcan, sendcan)
|
||||
time.sleep(1)
|
||||
|
||||
# honda bosch radar disable
|
||||
disabled = disable_ecu(*can_callbacks, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03', timeout=0.5)
|
||||
print(f"disabled: {disabled}")
|
||||
44
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/ecu_addrs.py
Normal file
44
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/ecu_addrs.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import time
|
||||
import iqpilot.cereal.messaging as messaging
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.ecu_addrs import get_all_ecu_addrs
|
||||
from iqpilot.common.params import Params
|
||||
from iqpilot.selfdrive.car.card import can_comm_callbacks, obd_callback
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Get addresses of all ECUs')
|
||||
parser.add_argument('--debug', action='store_true')
|
||||
parser.add_argument('--bus', type=int, default=1)
|
||||
parser.add_argument('--no-obd', action='store_true')
|
||||
parser.add_argument('--timeout', type=float, default=1.0)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
logcan = messaging.sub_sock('can')
|
||||
sendcan = messaging.pub_sock('sendcan')
|
||||
can_callbacks = can_comm_callbacks(logcan, sendcan)
|
||||
|
||||
# Set up params for pandad
|
||||
params = Params()
|
||||
params.remove("FirmwareQueryDone")
|
||||
params.put_bool("IsOnroad", False)
|
||||
time.sleep(0.2) # thread is 10 Hz
|
||||
params.put_bool("IsOnroad", True)
|
||||
|
||||
obd_callback(params)(not args.no_obd)
|
||||
|
||||
print("Getting ECU addresses ...")
|
||||
ecu_addrs = get_all_ecu_addrs(*can_callbacks, args.bus, args.timeout)
|
||||
|
||||
print()
|
||||
print("Found ECUs on rx addresses:")
|
||||
for addr, subaddr, _ in ecu_addrs:
|
||||
msg = f" {hex(addr)}"
|
||||
if subaddr is not None:
|
||||
msg += f" (sub-address: {hex(subaddr)})"
|
||||
print(msg)
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Some Hyundai radars can be reconfigured to output (debug) radar points on bus 1.
|
||||
Reconfiguration is done over UDS by reading/writing to 0x0142 using the Read/Write Data By Identifier
|
||||
endpoints (0x22 & 0x2E). This script checks your radar firmware version against a list of known
|
||||
firmware versions. If you want to try on a new radar make sure to note the default config value
|
||||
in case it's different from the other radars and you need to revert the changes.
|
||||
|
||||
After changing the config the car should not show any faults when openpilot is not running.
|
||||
These config changes are persistent across car reboots. You need to run this script again
|
||||
to go back to the default values.
|
||||
|
||||
USE AT YOUR OWN RISK! Safety features, like AEB and FCW, might be affected by these changes."""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
from typing import NamedTuple
|
||||
from subprocess import check_output, CalledProcessError
|
||||
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.uds import UdsClient, SESSION_TYPE, DATA_IDENTIFIER_TYPE
|
||||
from iqdbc.car.structs import CarParams
|
||||
from panda.python import Panda
|
||||
|
||||
class ConfigValues(NamedTuple):
|
||||
default_config: bytes
|
||||
tracks_enabled: bytes
|
||||
|
||||
# If your radar supports changing data identifier 0x0142 as well make a PR to
|
||||
# this file to add your firmware version. Make sure to post a drive as proof!
|
||||
# NOTE: these firmware versions do not match what openpilot uses
|
||||
# because this script uses a different diagnostic session type
|
||||
SUPPORTED_FW_VERSIONS = {
|
||||
# 2020 SONATA
|
||||
b"DN8_ SCC FHCUP 1.00 1.00 99110-L0000\x19\x08)\x15T ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
b"DN8_ SCC F-CUP 1.00 1.00 99110-L0000\x19\x08)\x15T ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2021 SONATA HYBRID
|
||||
b"DNhe SCC FHCUP 1.00 1.00 99110-L5000\x19\x04&\x13' ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
b"DNhe SCC FHCUP 1.00 1.02 99110-L5000 \x01#\x15# ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2020 PALISADE
|
||||
b"LX2_ SCC FHCUP 1.00 1.04 99110-S8100\x19\x05\x02\x16V ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2022 PALISADE
|
||||
b"LX2_ SCC FHCUP 1.00 1.00 99110-S8110!\x04\x05\x17\x01 ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2020 SANTA FE
|
||||
b"TM__ SCC F-CUP 1.00 1.03 99110-S2000\x19\x050\x13' ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2020 GENESIS G70
|
||||
b'IK__ SCC F-CUP 1.00 1.02 96400-G9100\x18\x07\x06\x17\x12 ': ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2019 SANTA FE
|
||||
b"TM__ SCC F-CUP 1.00 1.00 99110-S1210\x19\x01%\x168 ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
b"TM__ SCC F-CUP 1.00 1.02 99110-S2000\x18\x07\x08\x18W ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2021 K5 HEV
|
||||
b"DLhe SCC FHCUP 1.00 1.02 99110-L7000 \x01 \x102 ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
# 2022 Niro EV
|
||||
b"DEev SCC F-CUP 1.00 1.00 99110-Q4600\x01\x42 ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
b"DEev SCC F-CUP 1.00 1.00 99110-Q4600 \x07\x03\t% ": ConfigValues(
|
||||
default_config=b"\x00\x00\x00\x01\x00\x00",
|
||||
tracks_enabled=b"\x00\x00\x00\x01\x00\x01"),
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='configure radar to output points (or reset to default)')
|
||||
parser.add_argument('--default', action="store_true", default=False, help='reset to default configuration (default: false)')
|
||||
parser.add_argument('--debug', action="store_true", default=False, help='enable debug output (default: false)')
|
||||
parser.add_argument('--bus', type=int, default=0, help='can bus to use (default: 0)')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
try:
|
||||
check_output(["pidof", "pandad"])
|
||||
print("pandad is running, please kill openpilot before running this script! (aborted)")
|
||||
sys.exit(1)
|
||||
except CalledProcessError as e:
|
||||
if e.returncode != 1: # 1 == no process found (pandad not running)
|
||||
raise e
|
||||
|
||||
confirm = input("power on the vehicle keeping the engine off (press start button twice) then type OK to continue: ").upper().strip()
|
||||
if confirm != "OK":
|
||||
print("\nyou didn't type 'OK! (aborted)")
|
||||
sys.exit(0)
|
||||
|
||||
panda = Panda()
|
||||
panda.set_safety_mode(CarParams.SafetyModel.elm327)
|
||||
uds_client = UdsClient(panda, 0x7D0, bus=args.bus)
|
||||
|
||||
print("\n[START DIAGNOSTIC SESSION]")
|
||||
session_type: SESSION_TYPE = 0x07
|
||||
uds_client.diagnostic_session_control(session_type)
|
||||
|
||||
print("[HARDWARE/SOFTWARE VERSION]")
|
||||
fw_version_data_id: DATA_IDENTIFIER_TYPE = 0xf100
|
||||
fw_version = uds_client.read_data_by_identifier(fw_version_data_id)
|
||||
print(fw_version)
|
||||
if fw_version not in SUPPORTED_FW_VERSIONS.keys():
|
||||
print("radar not supported! (aborted)")
|
||||
sys.exit(1)
|
||||
|
||||
print("[GET CONFIGURATION]")
|
||||
config_data_id: DATA_IDENTIFIER_TYPE = 0x0142
|
||||
current_config = uds_client.read_data_by_identifier(config_data_id)
|
||||
config_values = SUPPORTED_FW_VERSIONS[fw_version]
|
||||
new_config = config_values.default_config if args.default else config_values.tracks_enabled
|
||||
print(f"current config: 0x{current_config.hex()}")
|
||||
if current_config != new_config:
|
||||
print("[CHANGE CONFIGURATION]")
|
||||
print(f"new config: 0x{new_config.hex()}")
|
||||
uds_client.write_data_by_identifier(config_data_id, new_config)
|
||||
if not args.default and current_config != SUPPORTED_FW_VERSIONS[fw_version].default_config:
|
||||
print("\ncurrent config does not match expected default! (aborted)")
|
||||
sys.exit(1)
|
||||
|
||||
print("[DONE]")
|
||||
print("\nrestart your vehicle and ensure there are no faults")
|
||||
if not args.default:
|
||||
print("you can run this script again with --default to go back to the original (factory) settings")
|
||||
else:
|
||||
print("[DONE]")
|
||||
print("\ncurrent config is already the desired configuration")
|
||||
sys.exit(0)
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import argparse
|
||||
from subprocess import check_output, CalledProcessError
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.uds import UdsClient, SESSION_TYPE, DTC_REPORT_TYPE, DTC_STATUS_MASK_TYPE, get_dtc_num_as_str, get_dtc_status_names
|
||||
from iqdbc.car.structs import CarParams
|
||||
from panda import Panda
|
||||
|
||||
parser = argparse.ArgumentParser(description="read DTC status")
|
||||
parser.add_argument("addr", type=lambda x: int(x,0))
|
||||
parser.add_argument("--bus", type=int, default=0)
|
||||
parser.add_argument('--debug', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
try:
|
||||
check_output(["pidof", "pandad"])
|
||||
print("pandad is running, please kill openpilot before running this script! (aborted)")
|
||||
sys.exit(1)
|
||||
except CalledProcessError as e:
|
||||
if e.returncode != 1: # 1 == no process found (pandad not running)
|
||||
raise e
|
||||
|
||||
panda = Panda()
|
||||
panda.set_safety_mode(CarParams.SafetyModel.elm327)
|
||||
uds_client = UdsClient(panda, args.addr, bus=args.bus)
|
||||
print("extended diagnostic session ...")
|
||||
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
|
||||
print("read diagnostic codes ...")
|
||||
data = uds_client.read_dtc_information(DTC_REPORT_TYPE.DTC_BY_STATUS_MASK, DTC_STATUS_MASK_TYPE.ALL)
|
||||
print("status availability:", " ".join(get_dtc_status_names(data[0])))
|
||||
print("DTC status:")
|
||||
for i in range(1, len(data), 4):
|
||||
dtc_num = get_dtc_num_as_str(data[i:i+3])
|
||||
dtc_status = " ".join(get_dtc_status_names(data[i+3]))
|
||||
print(dtc_num, dtc_status)
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from sklearn import linear_model
|
||||
from iqdbc.car.toyota.values import STEER_THRESHOLD
|
||||
|
||||
from iqpilot.tools.lib.logreader import LogReader
|
||||
|
||||
MIN_SAMPLES = 30 * 100
|
||||
|
||||
|
||||
def to_signed(n, bits):
|
||||
if n >= (1 << max((bits - 1), 0)):
|
||||
n = n - (1 << max(bits, 0))
|
||||
return n
|
||||
|
||||
|
||||
def get_eps_factor(lr, plot=False):
|
||||
engaged = False
|
||||
steering_pressed = False
|
||||
torque_cmd, eps_torque = None, None
|
||||
cmds, eps = [], []
|
||||
|
||||
for msg in lr:
|
||||
if msg.which() != 'can':
|
||||
continue
|
||||
|
||||
for m in msg.can:
|
||||
if m.address == 0x2e4 and m.src == 128:
|
||||
engaged = bool(m.dat[0] & 1)
|
||||
torque_cmd = to_signed((m.dat[1] << 8) | m.dat[2], 16)
|
||||
elif m.address == 0x260 and m.src == 0:
|
||||
eps_torque = to_signed((m.dat[5] << 8) | m.dat[6], 16)
|
||||
steering_pressed = abs(to_signed((m.dat[1] << 8) | m.dat[2], 16)) > STEER_THRESHOLD
|
||||
|
||||
if engaged and torque_cmd is not None and eps_torque is not None and not steering_pressed:
|
||||
cmds.append(torque_cmd)
|
||||
eps.append(eps_torque)
|
||||
else:
|
||||
if len(cmds) > MIN_SAMPLES:
|
||||
break
|
||||
cmds, eps = [], []
|
||||
|
||||
if len(cmds) < MIN_SAMPLES:
|
||||
raise Exception("too few samples found in route")
|
||||
|
||||
lm = linear_model.LinearRegression(fit_intercept=False)
|
||||
lm.fit(np.array(cmds).reshape(-1, 1), eps)
|
||||
scale_factor = 1. / lm.coef_[0]
|
||||
|
||||
if plot:
|
||||
plt.plot(np.array(eps) * scale_factor)
|
||||
plt.plot(cmds)
|
||||
plt.show()
|
||||
return scale_factor
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
lr = LogReader(sys.argv[1])
|
||||
n = get_eps_factor(lr, plot="--plot" in sys.argv)
|
||||
print("EPS torque factor: ", n)
|
||||
26
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/vin.py
Normal file
26
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/vin.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import time
|
||||
import iqpilot.cereal.messaging as messaging
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.vin import get_vin
|
||||
from iqpilot.selfdrive.car.card import can_comm_callbacks
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Get VIN of the car')
|
||||
parser.add_argument('--debug', action='store_true')
|
||||
parser.add_argument('--bus', type=int, default=1)
|
||||
parser.add_argument('--timeout', type=float, default=0.1)
|
||||
parser.add_argument('--retry', type=int, default=5)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
sendcan = messaging.pub_sock('sendcan')
|
||||
logcan = messaging.sub_sock('can')
|
||||
can_callbacks = can_comm_callbacks(logcan, sendcan)
|
||||
time.sleep(1)
|
||||
|
||||
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (args.bus,), args.timeout, args.retry)
|
||||
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
|
||||
164
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/vw_mqb_config.py
Normal file
164
artifacts/package_runtime/iqdbc/lvbs/tools/ecu/vw_mqb_config.py
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import struct
|
||||
from enum import IntEnum
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.uds import UdsClient, MessageTimeoutError, NegativeResponseError, SESSION_TYPE,\
|
||||
DATA_IDENTIFIER_TYPE, ACCESS_TYPE
|
||||
from iqdbc.car.structs import CarParams
|
||||
from panda import Panda
|
||||
from datetime import date
|
||||
|
||||
# TODO: extend UDS library to allow custom/vendor-defined data identifiers without ignoring type checks
|
||||
class VOLKSWAGEN_DATA_IDENTIFIER_TYPE(IntEnum):
|
||||
CODING = 0x0600
|
||||
|
||||
# TODO: extend UDS library security_access() to take an access level offset per ISO 14229-1:2020 10.4 and remove this
|
||||
class ACCESS_TYPE_LEVEL_1(IntEnum):
|
||||
REQUEST_SEED = ACCESS_TYPE.REQUEST_SEED + 2
|
||||
SEND_KEY = ACCESS_TYPE.SEND_KEY + 2
|
||||
|
||||
MQB_EPS_CAN_ADDR = 0x712
|
||||
RX_OFFSET = 0x6a
|
||||
|
||||
if __name__ == "__main__":
|
||||
desc_text = "Shows Volkswagen EPS software and coding info, and enables or disables Heading Control Assist " + \
|
||||
"(Lane Assist). Useful for enabling HCA on cars without factory Lane Assist that want to use " + \
|
||||
"openpilot integrated at the CAN gateway (J533)."
|
||||
epilog_text = "This tool is meant to run directly on a vehicle-installed comma three, with the " + \
|
||||
"openpilot/tmux processes stopped. It should also work on a separate PC with a USB-attached comma " + \
|
||||
"panda. Vehicle ignition must be on. Recommend engine not be running when making changes. Must " + \
|
||||
"turn ignition off and on again for any changes to take effect."
|
||||
parser = argparse.ArgumentParser(description=desc_text, epilog=epilog_text)
|
||||
parser.add_argument("--debug", action="store_true", help="enable ISO-TP/UDS stack debugging output")
|
||||
parser.add_argument("action", choices={"show", "enable", "disable"}, help="show or modify current EPS HCA config")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
panda = Panda()
|
||||
panda.set_safety_mode(CarParams.SafetyModel.elm327)
|
||||
uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, 1, timeout=0.2)
|
||||
|
||||
try:
|
||||
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
|
||||
except MessageTimeoutError:
|
||||
print("Timeout opening session with EPS")
|
||||
quit()
|
||||
|
||||
odx_file, current_coding = None, None
|
||||
try:
|
||||
hw_pn = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER).decode("utf-8")
|
||||
sw_pn = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_SPARE_PART_NUMBER).decode("utf-8")
|
||||
sw_ver = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_ECU_SOFTWARE_VERSION_NUMBER).decode("utf-8")
|
||||
component = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.SYSTEM_NAME_OR_ENGINE_TYPE).decode("utf-8")
|
||||
odx_file = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.ODX_FILE).decode("utf-8").rstrip('\x00')
|
||||
current_coding = uds_client.read_data_by_identifier(VOLKSWAGEN_DATA_IDENTIFIER_TYPE.CODING)
|
||||
coding_text = current_coding.hex()
|
||||
|
||||
print("\nEPS diagnostic data\n")
|
||||
print(f" Part No HW: {hw_pn}")
|
||||
print(f" Part No SW: {sw_pn}")
|
||||
print(f" SW Version: {sw_ver}")
|
||||
print(f" Component: {component}")
|
||||
print(f" Coding: {coding_text}")
|
||||
print(f" ASAM Dataset: {odx_file}")
|
||||
except NegativeResponseError:
|
||||
print("Error fetching data from EPS")
|
||||
quit()
|
||||
except MessageTimeoutError:
|
||||
print("Timeout fetching data from EPS")
|
||||
quit()
|
||||
|
||||
coding_variant, current_coding_array, coding_byte, coding_bit = None, None, 0, 0
|
||||
coding_length = len(current_coding)
|
||||
|
||||
# EPS_MQB_ZFLS
|
||||
if odx_file in ("EV_SteerAssisMQB", "EV_SteerAssisMNB"):
|
||||
coding_variant = "ZFLS"
|
||||
coding_byte = 0
|
||||
coding_bit = 4
|
||||
|
||||
# MQB_PP_APA, MQB_VWBS_GEN2
|
||||
elif odx_file in ("EV_SteerAssisVWBSMQBA", "EV_SteerAssisVWBSMQBGen2"):
|
||||
coding_variant = "APA"
|
||||
coding_byte = 3
|
||||
coding_bit = 0
|
||||
|
||||
else:
|
||||
print("Configuration changes not yet supported on this EPS!")
|
||||
quit()
|
||||
|
||||
current_coding_array = struct.unpack(f"!{coding_length}B", current_coding)
|
||||
hca_enabled = (current_coding_array[coding_byte] & (1 << coding_bit) != 0)
|
||||
hca_text = ("DISABLED", "ENABLED")[hca_enabled]
|
||||
print(f" Lane Assist: {hca_text}")
|
||||
|
||||
try:
|
||||
params = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION).decode("utf-8")
|
||||
param_version_system_params = params[1:3]
|
||||
param_vehicle_type = params[3:5]
|
||||
param_index_char_curve = params[5:7]
|
||||
param_version_char_values = params[7:9]
|
||||
param_version_memory_map = params[9:11]
|
||||
print("\nEPS parameterization (per-vehicle calibration) data\n")
|
||||
print(f" Version of system parameters: {param_version_system_params}")
|
||||
print(f" Vehicle type: {param_vehicle_type}")
|
||||
print(f" Index of characteristic curve: {param_index_char_curve}")
|
||||
print(f" Version of characteristic values: {param_version_char_values}")
|
||||
print(f" Version of memory map: {param_version_memory_map}")
|
||||
except (NegativeResponseError, MessageTimeoutError):
|
||||
print("Error fetching parameterization data from EPS!")
|
||||
quit()
|
||||
|
||||
if args.action in ["enable", "disable"]:
|
||||
print("\nAttempting configuration update")
|
||||
|
||||
assert (coding_variant in ("ZFLS", "APA"))
|
||||
# ZFLS EPS config coding length can be anywhere from 1 to 4 bytes, but the
|
||||
# bit we care about is always in the same place in the first byte
|
||||
if args.action == "enable":
|
||||
new_byte = current_coding_array[coding_byte] | (1 << coding_bit)
|
||||
else:
|
||||
new_byte = current_coding_array[coding_byte] & ~(1 << coding_bit)
|
||||
new_coding = current_coding[0:coding_byte] + new_byte.to_bytes(1, "little") + current_coding[coding_byte+1:]
|
||||
|
||||
try:
|
||||
seed = uds_client.security_access(ACCESS_TYPE_LEVEL_1.REQUEST_SEED)
|
||||
key = struct.unpack("!I", seed)[0] + 28183 # yeah, it's like that
|
||||
uds_client.security_access(ACCESS_TYPE_LEVEL_1.SEND_KEY, struct.pack("!I", key))
|
||||
except (NegativeResponseError, MessageTimeoutError):
|
||||
print("Security access failed!")
|
||||
print("Open the hood and retry (disables the \"diagnostic firewall\" on newer vehicles)")
|
||||
quit()
|
||||
|
||||
try:
|
||||
# Programming date and tester number must be written before making
|
||||
# a change, or write to CODING will fail with request sequence error
|
||||
# Encoding on tester is unclear, it contains the workshop code in the
|
||||
# last two bytes, but not the VZ/importer or tester serial number
|
||||
# Can't seem to read it back, but we can read the calibration tester,
|
||||
# so fib a little and say that same tester did the programming
|
||||
current_date = date.today()
|
||||
formatted_date = current_date.strftime('%y-%m-%d')
|
||||
year, month, day = (int(part) for part in formatted_date.split('-'))
|
||||
prog_date = bytes([year, month, day])
|
||||
uds_client.write_data_by_identifier(DATA_IDENTIFIER_TYPE.PROGRAMMING_DATE, prog_date)
|
||||
tester_num = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER)
|
||||
uds_client.write_data_by_identifier(DATA_IDENTIFIER_TYPE.REPAIR_SHOP_CODE_OR_TESTER_SERIAL_NUMBER, tester_num)
|
||||
uds_client.write_data_by_identifier(VOLKSWAGEN_DATA_IDENTIFIER_TYPE.CODING, new_coding)
|
||||
except (NegativeResponseError, MessageTimeoutError):
|
||||
print("Writing new configuration failed!")
|
||||
print("Make sure the comma processes are stopped: tmux kill-session -t comma")
|
||||
quit()
|
||||
|
||||
try:
|
||||
# Read back result just to make 100% sure everything worked
|
||||
current_coding_text = uds_client.read_data_by_identifier(VOLKSWAGEN_DATA_IDENTIFIER_TYPE.CODING).hex()
|
||||
print(f" New coding: {current_coding_text}")
|
||||
except (NegativeResponseError, MessageTimeoutError):
|
||||
print("Reading back updated coding failed!")
|
||||
quit()
|
||||
print("EPS configuration successfully updated")
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
|
||||
from iqdbc.car import uds
|
||||
from iqpilot.tools.lib.logreader import LogReader, ReadMode, live_logreader
|
||||
|
||||
|
||||
def main(route: str | None, addrs: list[int], rxoffset: int | None):
|
||||
"""
|
||||
TODO:
|
||||
- highlight TX vs RX clearly
|
||||
- disambiguate sendcan and can (useful to know if something sent on sendcan made it to the bus on can->128)
|
||||
- print as fixed width table, easier to read
|
||||
"""
|
||||
|
||||
if route is None:
|
||||
lr = live_logreader()
|
||||
else:
|
||||
lr = LogReader(route, default_mode=ReadMode.RLOG, sort_by_time=True)
|
||||
|
||||
start_mono_time = None
|
||||
prev_mono_time = 0
|
||||
|
||||
# include rx addresses
|
||||
addrs = addrs + [uds.get_rx_addr_for_tx_addr(addr, rxoffset) for addr in addrs]
|
||||
|
||||
for msg in lr:
|
||||
if msg.which() == 'can':
|
||||
if start_mono_time is None:
|
||||
start_mono_time = msg.logMonoTime
|
||||
|
||||
if msg.which() in ("can", 'sendcan'):
|
||||
for can in getattr(msg, msg.which()):
|
||||
if can.address in addrs or not len(addrs):
|
||||
if msg.logMonoTime != prev_mono_time:
|
||||
print()
|
||||
prev_mono_time = msg.logMonoTime
|
||||
print(f"{msg.which():>7}: rxaddr={can.address}, bus={str(can.src) + ',':<4} {round((msg.logMonoTime - start_mono_time) * 1e-6)} ms, " +
|
||||
f"0x{can.dat.hex()}, {can.dat}, {len(can.dat)=}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='View back and forth ISO-TP communication between various ECUs given an address')
|
||||
parser.add_argument('route', nargs='?', help='Route name, live if not specified')
|
||||
parser.add_argument('--addrs', nargs='*', default=[], help='List of tx address to view (0x7e0 for engine)')
|
||||
parser.add_argument('--rxoffset', default='')
|
||||
args = parser.parse_args()
|
||||
|
||||
addrs = [int(addr, base=16) if addr.startswith('0x') else int(addr) for addr in args.addrs]
|
||||
rxoffset = int(args.rxoffset, base=16) if args.rxoffset else None
|
||||
main(args.route, addrs, rxoffset)
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from iqpilot.tools.lib.logreader import LogReader, ReadMode
|
||||
|
||||
|
||||
def get_fingerprint(lr):
|
||||
# TODO: make this a nice tool for car ports. should also work with qlogs for FW
|
||||
|
||||
fw = None
|
||||
vin = None
|
||||
msgs = {}
|
||||
for msg in lr:
|
||||
if msg.which() == 'carParams':
|
||||
fw = msg.carParams.carFw
|
||||
vin = msg.carParams.carVin
|
||||
elif msg.which() == 'can':
|
||||
for c in msg.can:
|
||||
# read also msgs sent by EON on CAN bus 0x80 and filter out the
|
||||
# addr with more than 11 bits
|
||||
if c.src % 0x80 == 0 and c.address < 0x800 and c.address not in (0x7df, 0x7e0, 0x7e8):
|
||||
msgs[c.address] = len(c.dat)
|
||||
|
||||
# show CAN fingerprint
|
||||
fingerprint = ', '.join(f"{v[0]}: {v[1]}" for v in sorted(msgs.items()))
|
||||
print(f"\nfound {len(msgs)} messages. CAN fingerprint:\n")
|
||||
print(fingerprint)
|
||||
|
||||
# TODO: also print the fw fingerprint merged with the existing ones
|
||||
# show FW fingerprint
|
||||
if fw:
|
||||
print("\nFW fingerprint:\n")
|
||||
for f in fw:
|
||||
print(f" (Ecu.{f.ecu}, {hex(f.address)}, {None if f.subAddress == 0 else f.subAddress}): [")
|
||||
print(f" {f.fwVersion},")
|
||||
print(" ],")
|
||||
print()
|
||||
print(f"VIN: {vin}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: ./fingerprint_from_route.py <route>")
|
||||
sys.exit(1)
|
||||
|
||||
lr = LogReader(sys.argv[1], ReadMode.QLOG)
|
||||
get_fingerprint(lr)
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
import random
|
||||
from collections import defaultdict
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
from iqdbc.car.fw_versions import match_fw_to_car_fuzzy
|
||||
from iqdbc.car.toyota.values import FW_VERSIONS as TOYOTA_FW_VERSIONS
|
||||
from iqdbc.car.honda.values import FW_VERSIONS as HONDA_FW_VERSIONS
|
||||
from iqdbc.car.hyundai.values import FW_VERSIONS as HYUNDAI_FW_VERSIONS
|
||||
from iqdbc.car.volkswagen.values import FW_VERSIONS as VW_FW_VERSIONS
|
||||
|
||||
|
||||
FWS = {}
|
||||
FWS.update(TOYOTA_FW_VERSIONS)
|
||||
FWS.update(HONDA_FW_VERSIONS)
|
||||
FWS.update(HYUNDAI_FW_VERSIONS)
|
||||
FWS.update(VW_FW_VERSIONS)
|
||||
|
||||
if __name__ == "__main__":
|
||||
total = 0
|
||||
match = 0
|
||||
wrong_match = 0
|
||||
confusions = defaultdict(set)
|
||||
|
||||
for _ in tqdm(range(1000)):
|
||||
for candidate, fws in FWS.items():
|
||||
fw_dict = {}
|
||||
for (_, addr, subaddr), fw_list in fws.items():
|
||||
fw_dict[(addr, subaddr)] = [random.choice(fw_list)]
|
||||
|
||||
matches = match_fw_to_car_fuzzy(fw_dict, log=False, exclude=candidate)
|
||||
|
||||
total += 1
|
||||
if len(matches) == 1:
|
||||
if list(matches)[0] == candidate:
|
||||
match += 1
|
||||
else:
|
||||
confusions[candidate] |= matches
|
||||
wrong_match += 1
|
||||
|
||||
print()
|
||||
for candidate, wrong_matches in sorted(confusions.items()):
|
||||
print(candidate, wrong_matches)
|
||||
|
||||
print()
|
||||
print(f"Total fuzz cases: {total}")
|
||||
print(f"Correct matches: {match}")
|
||||
print(f"Wrong matches: {wrong_match}")
|
||||
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from collections import defaultdict
|
||||
import argparse
|
||||
import os
|
||||
import traceback
|
||||
from tqdm import tqdm
|
||||
from iqdbc.car.car_helpers import interface_names
|
||||
from iqdbc.car.fingerprints import MIGRATION
|
||||
from iqdbc.car.fw_versions import VERSIONS, match_fw_to_car
|
||||
from iqpilot.tools.lib.logreader import LogReader, ReadMode
|
||||
from iqpilot.tools.lib.route import SegmentRange
|
||||
|
||||
|
||||
NO_API = "NO_API" in os.environ
|
||||
SUPPORTED_BRANDS = VERSIONS.keys()
|
||||
SUPPORTED_CARS = [brand for brand in SUPPORTED_BRANDS for brand in interface_names[brand]]
|
||||
UNKNOWN_BRAND = "unknown"
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Run FW fingerprint on Qlog of route or list of routes')
|
||||
parser.add_argument('route', help='Route or file with list of routes')
|
||||
parser.add_argument('--car', help='Force comparison fingerprint to known car')
|
||||
args = parser.parse_args()
|
||||
|
||||
if os.path.exists(args.route):
|
||||
routes = list(open(args.route))
|
||||
else:
|
||||
routes = [args.route]
|
||||
|
||||
mismatches = defaultdict(list)
|
||||
|
||||
not_fingerprinted = 0
|
||||
solved_by_fuzzy = 0
|
||||
|
||||
good_exact = 0
|
||||
wrong_fuzzy = 0
|
||||
good_fuzzy = 0
|
||||
|
||||
dongles = []
|
||||
for route in tqdm(routes):
|
||||
sr = SegmentRange(route)
|
||||
dongle_id = sr.dongle_id
|
||||
|
||||
if dongle_id in dongles:
|
||||
continue
|
||||
|
||||
if sr.slice == '' and sr.selector is None:
|
||||
route += '/0'
|
||||
|
||||
lr = LogReader(route, default_mode=ReadMode.QLOG)
|
||||
|
||||
try:
|
||||
dongles.append(dongle_id)
|
||||
|
||||
CP = None
|
||||
for msg in lr:
|
||||
if msg.which() == "pandaStates":
|
||||
if msg.pandaStates[0].pandaType in ('unknown', 'whitePanda', 'greyPanda', 'pedal'):
|
||||
print("wrong panda type")
|
||||
break
|
||||
|
||||
elif msg.which() == "carParams":
|
||||
CP = msg.carParams
|
||||
car_fw = [fw for fw in CP.carFw if not fw.logging]
|
||||
if len(car_fw) == 0:
|
||||
print("WARNING: no fw")
|
||||
|
||||
live_fingerprint = CP.carFingerprint
|
||||
live_fingerprint = MIGRATION.get(live_fingerprint, live_fingerprint)
|
||||
|
||||
if args.car is not None:
|
||||
live_fingerprint = args.car
|
||||
|
||||
if live_fingerprint not in SUPPORTED_CARS:
|
||||
print("not in supported cars")
|
||||
break
|
||||
|
||||
_, exact_matches = match_fw_to_car(car_fw, CP.carVin, allow_exact=True, allow_fuzzy=False)
|
||||
_, fuzzy_matches = match_fw_to_car(car_fw, CP.carVin, allow_exact=False, allow_fuzzy=True)
|
||||
|
||||
if (len(exact_matches) == 1) and (list(exact_matches)[0] == live_fingerprint):
|
||||
good_exact += 1
|
||||
print(f"Correct! Live: {live_fingerprint} - Fuzzy: {fuzzy_matches}")
|
||||
|
||||
# Check if fuzzy match was correct
|
||||
if len(fuzzy_matches) == 1:
|
||||
if list(fuzzy_matches)[0] != live_fingerprint:
|
||||
wrong_fuzzy += 1
|
||||
print("Fuzzy match wrong! Fuzzy:", fuzzy_matches, "Live:", live_fingerprint)
|
||||
else:
|
||||
good_fuzzy += 1
|
||||
break
|
||||
|
||||
print("Old style:", live_fingerprint, "Vin", CP.carVin)
|
||||
print("New style (exact):", exact_matches)
|
||||
print("New style (fuzzy):", fuzzy_matches)
|
||||
|
||||
padding = max([len(fw.brand or UNKNOWN_BRAND) for fw in car_fw] + [0])
|
||||
for version in sorted(car_fw, key=lambda fw: fw.brand):
|
||||
subaddr = None if version.subAddress == 0 else hex(version.subAddress)
|
||||
print(f" Brand: {version.brand or UNKNOWN_BRAND:{padding}}, bus: {version.bus} - " +
|
||||
f"(Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion}],")
|
||||
|
||||
print("Mismatches")
|
||||
found = False
|
||||
for brand in SUPPORTED_BRANDS:
|
||||
car_fws = VERSIONS[brand]
|
||||
if live_fingerprint in car_fws:
|
||||
found = True
|
||||
expected = car_fws[live_fingerprint]
|
||||
for (_, expected_addr, expected_sub_addr), v in expected.items():
|
||||
for version in car_fw:
|
||||
if version.brand != brand and len(version.brand):
|
||||
continue
|
||||
sub_addr = None if version.subAddress == 0 else version.subAddress
|
||||
addr = version.address
|
||||
|
||||
if (addr, sub_addr) == (expected_addr, expected_sub_addr):
|
||||
if version.fwVersion not in v:
|
||||
print(f"({hex(addr)}, {'None' if sub_addr is None else hex(sub_addr)}) - {version.fwVersion}")
|
||||
|
||||
# Add to global list of mismatches
|
||||
mismatch = (addr, sub_addr, version.fwVersion)
|
||||
if mismatch not in mismatches[live_fingerprint]:
|
||||
mismatches[live_fingerprint].append(mismatch)
|
||||
|
||||
# No FW versions for this car yet, add them all to mismatch list
|
||||
if not found:
|
||||
for version in car_fw:
|
||||
sub_addr = None if version.subAddress == 0 else version.subAddress
|
||||
addr = version.address
|
||||
mismatch = (addr, sub_addr, version.fwVersion)
|
||||
if mismatch not in mismatches[live_fingerprint]:
|
||||
mismatches[live_fingerprint].append(mismatch)
|
||||
|
||||
print()
|
||||
not_fingerprinted += 1
|
||||
|
||||
if len(fuzzy_matches) == 1:
|
||||
if list(fuzzy_matches)[0] == live_fingerprint:
|
||||
solved_by_fuzzy += 1
|
||||
else:
|
||||
wrong_fuzzy += 1
|
||||
print("Fuzzy match wrong! Fuzzy:", fuzzy_matches, "Live:", live_fingerprint)
|
||||
|
||||
break
|
||||
|
||||
if CP is None:
|
||||
print("no CarParams in logs")
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
print()
|
||||
# Print FW versions that need to be added separated out by car and address
|
||||
for car, m in sorted(mismatches.items()):
|
||||
print(car)
|
||||
addrs = defaultdict(list)
|
||||
for (addr, sub_addr, version) in m:
|
||||
addrs[(addr, sub_addr)].append(version)
|
||||
|
||||
for (addr, sub_addr), versions in addrs.items():
|
||||
print(f" ({hex(addr)}, {'None' if sub_addr is None else hex(sub_addr)}): [")
|
||||
for v in versions:
|
||||
print(f" {v},")
|
||||
print(" ]")
|
||||
print()
|
||||
|
||||
print()
|
||||
print(f"Number of dongle ids checked: {len(dongles)}")
|
||||
print(f"Fingerprinted: {good_exact}")
|
||||
print(f"Not fingerprinted: {not_fingerprinted}")
|
||||
print(f" of which had a fuzzy match: {solved_by_fuzzy}")
|
||||
|
||||
print()
|
||||
print(f"Correct fuzzy matches: {good_fuzzy}")
|
||||
print(f"Wrong fuzzy matches: {wrong_fuzzy}")
|
||||
print()
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import argparse
|
||||
import iqpilot.cereal.messaging as messaging
|
||||
from iqpilot.cereal import car
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.fw_versions import get_fw_versions, match_fw_to_car
|
||||
from iqdbc.car.vin import get_vin
|
||||
from iqpilot.common.params import Params
|
||||
from iqpilot.selfdrive.car.card import can_comm_callbacks, obd_callback
|
||||
from typing import Any
|
||||
|
||||
Ecu = car.CarParams.Ecu
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Get firmware version of ECUs')
|
||||
parser.add_argument('--scan', action='store_true')
|
||||
parser.add_argument('--debug', action='store_true')
|
||||
parser.add_argument('--brand', help='Only query addresses/with requests for this brand')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
carlog.setLevel('DEBUG')
|
||||
|
||||
logcan = messaging.sub_sock('can')
|
||||
pandaStates_sock = messaging.sub_sock('pandaStates')
|
||||
sendcan = messaging.pub_sock('sendcan')
|
||||
can_callbacks = can_comm_callbacks(logcan, sendcan)
|
||||
|
||||
# Set up params for pandad
|
||||
params = Params()
|
||||
params.remove("FirmwareQueryDone")
|
||||
params.put_bool("IsOnroad", False)
|
||||
time.sleep(0.2) # thread is 10 Hz
|
||||
params.put_bool("IsOnroad", True)
|
||||
set_obd_multiplexing = obd_callback(params)
|
||||
|
||||
extra: Any = None
|
||||
if args.scan:
|
||||
extra = {}
|
||||
# Honda
|
||||
for i in range(256):
|
||||
extra[(Ecu.unknown, 0x18da00f1 + (i << 8), None)] = []
|
||||
extra[(Ecu.unknown, 0x700 + i, None)] = []
|
||||
extra[(Ecu.unknown, 0x750, i)] = []
|
||||
extra = {"any": {"debug": extra}}
|
||||
|
||||
num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates)
|
||||
|
||||
t = time.monotonic()
|
||||
print("Getting vin...")
|
||||
set_obd_multiplexing(True)
|
||||
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1))
|
||||
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
|
||||
print(f"Getting VIN took {time.monotonic() - t:.3f} s")
|
||||
print()
|
||||
|
||||
t = time.monotonic()
|
||||
fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, progress=True)
|
||||
_, candidates = match_fw_to_car(fw_vers, vin)
|
||||
|
||||
print()
|
||||
print("Found FW versions")
|
||||
print("{")
|
||||
padding = max([len(fw.brand) for fw in fw_vers] or [0])
|
||||
for version in fw_vers:
|
||||
subaddr = None if version.subAddress == 0 else hex(version.subAddress)
|
||||
print(f" Brand: {version.brand:{padding}}, bus: {version.bus}, OBD: {version.obdMultiplexing} - " +
|
||||
f"(Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion!r}]")
|
||||
print("}")
|
||||
|
||||
print()
|
||||
print("Possible matches:", candidates)
|
||||
print(f"Getting fw took {time.monotonic() - t:.3f} s")
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# simple script to get a vehicle fingerprint.
|
||||
|
||||
# Instructions:
|
||||
# - connect to a Panda
|
||||
# - run selfdrive/pandad/pandad
|
||||
# - launching this script
|
||||
# Note: it's very important that the car is in stock mode, in order to collect a complete fingerprint
|
||||
# - since some messages are published at low frequency, keep this script running for at least 30s,
|
||||
# until all messages are received at least once
|
||||
|
||||
import iqpilot.cereal.messaging as messaging
|
||||
|
||||
logcan = messaging.sub_sock('can')
|
||||
msgs = {}
|
||||
while True:
|
||||
lc = messaging.recv_sock(logcan, True)
|
||||
if lc is None:
|
||||
continue
|
||||
|
||||
for c in lc.can:
|
||||
# read also msgs sent by EON on CAN bus 0x80 and filter out the
|
||||
# addr with more than 11 bits
|
||||
if c.src % 0x80 == 0 and c.address < 0x800 and c.address not in (0x7df, 0x7e0, 0x7e8):
|
||||
msgs[c.address] = len(c.dat)
|
||||
|
||||
fingerprint = ', '.join(f"{v[0]}: {v[1]}" for v in sorted(msgs.items()))
|
||||
|
||||
print(f"number of messages {len(msgs)}:")
|
||||
print(f"fingerprint {fingerprint}")
|
||||
Reference in New Issue
Block a user