diff --git a/RELEASES.md b/RELEASES.md
index 1b5ef8f7a7..ddb4a036b0 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -8,6 +8,7 @@ Version 0.9.1 (2022-12-XX)
* Hyundai Tucson 2022-23 support
* Kia Sorento 2022-23 support thanks to sunnyhaibin!
* Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin!
+* Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607!
Version 0.9.0 (2022-11-21)
========================
diff --git a/docs/CARS.md b/docs/CARS.md
index 390d2bf349..ea06176178 100644
--- a/docs/CARS.md
+++ b/docs/CARS.md
@@ -4,7 +4,7 @@
A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system.
-# 224 Supported Cars
+# 231 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -30,7 +30,8 @@ A supported vehicle is one that just works when you install a comma three. All s
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None||
|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[](##)|[](##)|Hyundai F||
|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Hyundai F||
-|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[](##)|[](##)|Hyundai H||
+|Genesis|G80 2017|All|Stock|19 mph|37 mph|[](##)|[](##)|Hyundai J||
+|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[](##)|[](##)|Hyundai H||
|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Hyundai C||
|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Hyundai A||
|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Hyundai K||
@@ -135,6 +136,8 @@ A supported vehicle is one that just works when you install a comma three. All s
|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[](##)|[](##)|Toyota||
|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|Toyota||
|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|Toyota||
+|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533|
|
+|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533|
|
|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[](##)|[](##)|Mazda||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[](##)|[](##)|Mazda|
|
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|Nissan B||
@@ -181,6 +184,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[](##)|[](##)|Toyota||
|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|Toyota|
|
|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|Toyota||
+|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[](##)|[](##)|Toyota||
|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[](##)|[](##)|Toyota|
|
|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|Toyota||
|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[](##)|[](##)|Toyota||
@@ -209,6 +213,8 @@ A supported vehicle is one that just works when you install a comma three. All s
|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533|
|
+|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533|
|
+|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533|
|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
@@ -217,6 +223,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
+|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[](##)|[](##)|J533|
|
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[](##)|[](##)|J533||
diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc
index 4bba070eee..647a0d9c78 100644
--- a/selfdrive/boardd/panda.cc
+++ b/selfdrive/boardd/panda.cc
@@ -236,6 +236,9 @@ void Panda::can_send(capnp::List::Reader can_data_list) {
}
bool Panda::can_receive(std::vector& out_vec) {
+ // Check if enough space left in buffer to store RECV_SIZE data
+ assert(receive_buffer_size + RECV_SIZE <= sizeof(receive_buffer));
+
int recv = handle->bulk_read(0x81, &receive_buffer[receive_buffer_size], RECV_SIZE);
if (!comms_healthy()) {
return false;
@@ -278,6 +281,7 @@ bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector> 5) # curvature
+ checksum += dat[6] + ((dat[7] & 0xE0) >> 5) # curvature rate
+ checksum += (dat[3] & 0x1F) + ((dat[4] & 0xFC) >> 2) # path angle
+ checksum += (dat[4] & 0x3) + dat[5] # path offset
+ return 0xFF - (checksum & 0xFF)
+
+
def create_lka_msg(packer):
"""
Creates an empty CAN message for the Ford LKA Command.
@@ -16,7 +25,8 @@ def create_lka_msg(packer):
return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {})
-def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float, curvature_rate: float):
+def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float,
+ curvature_rate: float):
"""
Creates a CAN message for the Ford TJA/LCA Command.
@@ -55,6 +65,38 @@ def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle:
return packer.make_can_msg("LateralMotionControl", CANBUS.main, values)
+def create_lat_ctl2_msg(packer, mode: int, path_offset: float, path_angle: float, curvature: float,
+ curvature_rate: float, counter: int):
+ """
+ Create a CAN message for the new Ford Lane Centering command.
+
+ This message is used on the CAN FD platform and replaces the old LateralMotionControl message. It is similar but has
+ additional signals for a counter and checksum.
+
+ Frequency is 20Hz.
+ """
+
+ values = {
+ "LatCtl_D2_Rq": mode, # Mode: 0=None, 1=PathFollowingLimitedMode, 2=PathFollowingExtendedMode,
+ # 3=SafeRampOut, 4-7=NotUsed [0|7]
+ "LatCtlRampType_D_Rq": 0, # 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3]
+ "LatCtlPrecision_D_Rq": 1, # 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3]
+ "LatCtlPathOffst_L_Actl": path_offset, # [-5.12|5.11] meter
+ "LatCtlPath_An_Actl": path_angle, # [-0.5|0.5235] radians
+ "LatCtlCurv_No_Actl": curvature, # [-0.02|0.02094] 1/meter
+ "LatCtlCrv_NoRate2_Actl": curvature_rate, # [-0.001024|0.001023] 1/meter^2
+ "HandsOffCnfm_B_Rq": 0, # 0=Inactive, 1=Active [0|1]
+ "LatCtlPath_No_Cnt": counter, # [0|15]
+ "LatCtlPath_No_Cs": 0, # [0|255]
+ }
+
+ # calculate checksum
+ dat = packer.make_can_msg("LateralMotionControl2", CANBUS.main, values)[2]
+ values["LatCtlPath_No_Cs"] = calculate_lat_ctl2_checksum(mode, counter, dat)
+
+ return packer.make_can_msg("LateralMotionControl2", CANBUS.main, values)
+
+
def create_acc_command(packer, long_active: bool, gas: float, accel: float, precharge_brake: bool, decel: bool):
"""
Creates a CAN message for the Ford ACC Command.
diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py
index 7b075f1547..4cabdb11e1 100644
--- a/selfdrive/car/ford/values.py
+++ b/selfdrive/car/ford/values.py
@@ -1,7 +1,7 @@
from collections import defaultdict
from dataclasses import dataclass
from enum import Enum
-from typing import Dict, List, Union
+from typing import Dict, List, Set, Union
from cereal import car
from selfdrive.car import AngleRateLimit, dbc_dict
@@ -52,6 +52,9 @@ class CAR:
MAVERICK_MK1 = "FORD MAVERICK 1ST GEN"
+CANFD_CARS: Set[str] = set()
+
+
class RADAR:
DELPHI_ESR = 'ford_fusion_2018_adas'
DELPHI_MRR = 'FORD_CADS'
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py
index 4e3dd484c8..1d531c2b87 100644
--- a/selfdrive/car/hyundai/values.py
+++ b/selfdrive/car/hyundai/values.py
@@ -147,7 +147,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
],
CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
- CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages
+ CAR.HYUNDAI_GENESIS: [
+ HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages
+ HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j),
+ ],
CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c),
CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness
CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness=Harness.hyundai_c),
@@ -232,7 +235,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f),
CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f),
CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l),
- CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2017-19", "All", harness=Harness.hyundai_h),
+ CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", harness=Harness.hyundai_h),
CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness=Harness.hyundai_c),
}
@@ -364,6 +367,13 @@ FW_QUERY_CONFIG = FwQueryConfig(
)
FW_VERSIONS = {
+ CAR.HYUNDAI_GENESIS: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DH LKAS 1.1 -150210',
+ b'\xf1\x00DH LKAS 1.4 -140110',
+ b'\xf1\x00DH LKAS 1.5 -140425',
+ ],
+ },
CAR.IONIQ: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ',
@@ -1028,6 +1038,25 @@ FW_VERSIONS = {
b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
+ CAR.GENESIS_G80: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DH__ SCC F-CUP 1.00 1.01 96400-B1120 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DH LKAS AT USA LHD 1.01 1.03 95895-B1500 180713',
+ b'\xf1\x00DH LKAS AT USA LHD 1.01 1.02 95895-B1500 170810',
+ b'\xf1\x00DH LKAS AT USA LHD 1.01 1.01 95895-B1500 161014',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SDH0T33NH4\xd7O\x9e\xc9',
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00TDH0G38NH3:-\xa9n',
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0G38NH2j\x9dA\x1c',
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0T33NH3\x97\xe6\xbc\xb8',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
CAR.GENESIS_G90: {
(Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDGMD15866192DD3x\x88x\x89wuFvvfUf\x88vWwgwwwvfVgx\x87o\xff\xbc^\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7'],
(Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00HI__ SCC F-CUP 1.00 1.01 96400-D2100 '],
diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py
index d1b73afcf6..bcdb00fd60 100644
--- a/selfdrive/car/tests/routes.py
+++ b/selfdrive/car/tests/routes.py
@@ -26,6 +26,7 @@ non_tested_cars = [
HYUNDAI.GENESIS_G90,
HYUNDAI.KIA_OPTIMA_H,
HONDA.ODYSSEY_CHN,
+ VOLKSWAGEN.CRAFTER_MK2, # need a route from an ACC-equipped Crafter
]
CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,))
diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml
index aeb2e6f280..56057dfae0 100644
--- a/selfdrive/car/torque_data/substitute.yaml
+++ b/selfdrive/car/torque_data/substitute.yaml
@@ -59,6 +59,7 @@ SKODA SCALA 1ST GEN: SKODA SUPERB 3RD GEN
SKODA KODIAQ 1ST GEN: SKODA SUPERB 3RD GEN
SKODA KAROQ 1ST GEN: SKODA SUPERB 3RD GEN
SKODA KAMIQ 1ST GEN: SKODA SUPERB 3RD GEN
+VOLKSWAGEN CRAFTER 2ND GEN: VOLKSWAGEN TIGUAN 2ND GEN
VOLKSWAGEN T-ROC 1ST GEN: VOLKSWAGEN TIGUAN 2ND GEN
VOLKSWAGEN T-CROSS 1ST GEN: VOLKSWAGEN TIGUAN 2ND GEN
VOLKSWAGEN TOURAN 2ND GEN: VOLKSWAGEN TIGUAN 2ND GEN
diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py
index 6dbdd4b5d9..222cf70613 100644
--- a/selfdrive/car/toyota/carcontroller.py
+++ b/selfdrive/car/toyota/carcontroller.py
@@ -143,7 +143,7 @@ class CarController:
# forcing the pcm to disengage causes a bad fault sound so play a good sound instead
send_ui = True
- if self.frame % 100 == 0 or send_ui:
+ if self.frame % 20 == 0 or send_ui:
can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible,
hud_control.rightLaneVisible, hud_control.leftLaneDepart,
hud_control.rightLaneDepart, CC.enabled, CS.lkas_hud))
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index c413028a25..6c2b865982 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -125,6 +125,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
],
CAR.COROLLAH_TSS2: [
ToyotaCarInfo("Toyota Corolla Hybrid 2020-22"),
+ ToyotaCarInfo("Toyota Corolla Hybrid (Non-US only) 2020-23", min_enable_speed=7.5),
ToyotaCarInfo("Toyota Corolla Cross Hybrid (Non-US only) 2020-22", min_enable_speed=7.5),
ToyotaCarInfo("Lexus UX Hybrid 2019-22"),
],
@@ -841,6 +842,7 @@ FW_VERSIONS = {
b'\x02896630A07000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630A21000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZJ5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
+ b'\x02896630ZK8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZN8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZQ3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZR2000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py
index da0ce25afa..b979a96d70 100644
--- a/selfdrive/car/volkswagen/interface.py
+++ b/selfdrive/car/volkswagen/interface.py
@@ -107,6 +107,11 @@ class CarInterface(CarInterfaceBase):
ret.mass = 2011 + STD_CARGO_KG
ret.wheelbase = 2.98
+ elif candidate == CAR.CRAFTER_MK2:
+ ret.mass = 2100 + STD_CARGO_KG
+ ret.wheelbase = 3.64 # SWB, LWB is 4.49, TBD how to detect difference
+ ret.minSteerSpeed = 50 * CV.KPH_TO_MS
+
elif candidate == CAR.GOLF_MK7:
ret.mass = 1397 + STD_CARGO_KG
ret.wheelbase = 2.62
diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py
index bdb43c542a..9f6dee2689 100755
--- a/selfdrive/car/volkswagen/values.py
+++ b/selfdrive/car/volkswagen/values.py
@@ -111,6 +111,7 @@ class CANBUS:
class CAR:
ARTEON_MK1 = "VOLKSWAGEN ARTEON 1ST GEN" # Chassis AN, Mk1 VW Arteon and variants
ATLAS_MK1 = "VOLKSWAGEN ATLAS 1ST GEN" # Chassis CA, Mk1 VW Atlas and Atlas Cross Sport
+ CRAFTER_MK2 = "VOLKSWAGEN CRAFTER 2ND GEN" # Chassis SY/SZ, Mk2 VW Crafter, VW Grand California, MAN TGE
GOLF_MK7 = "VOLKSWAGEN GOLF 7TH GEN" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants
JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 VW Jetta
PASSAT_MK8 = "VOLKSWAGEN PASSAT 8TH GEN" # Chassis 3G, Mk8 VW Passat and variants
@@ -122,7 +123,7 @@ class CAR:
TIGUAN_MK2 = "VOLKSWAGEN TIGUAN 2ND GEN" # Chassis AD/BW, Mk2 VW Tiguan and variants
TOURAN_MK2 = "VOLKSWAGEN TOURAN 2ND GEN" # Chassis 1T, Mk2 VW Touran and variants
TRANSPORTER_T61 = "VOLKSWAGEN TRANSPORTER T6.1" # Chassis 7H/7L, T6-facelift Transporter/Multivan/Caravelle/California
- TROC_MK1 = "VOLKSWAGEN T-ROC 1ST GEN" # Chassis A1, Mk1 VW VW T-Roc and variants
+ TROC_MK1 = "VOLKSWAGEN T-ROC 1ST GEN" # Chassis A1, Mk1 VW T-Roc and variants
AUDI_A3_MK3 = "AUDI A3 3RD GEN" # Chassis 8V/FF, Mk3 Audi A3 and variants
AUDI_Q2_MK1 = "AUDI Q2 1ST GEN" # Chassis GA, Mk1 Audi Q2 (RoW) and Q2L (China only)
AUDI_Q3_MK2 = "AUDI Q3 2ND GEN" # Chassis 8U/F3/FS, Mk2 Audi Q3 and variants
@@ -184,6 +185,13 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
VWCarInfo("Volkswagen Teramont Cross Sport 2021-22"),
VWCarInfo("Volkswagen Teramont X 2021-22"),
],
+ CAR.CRAFTER_MK2: [
+ VWCarInfo("Volkswagen Crafter 2017-23", video_link="https://youtu.be/4100gLeabmo"),
+ VWCarInfo("Volkswagen e-Crafter 2018-23", video_link="https://youtu.be/4100gLeabmo"),
+ VWCarInfo("Volkswagen Grand California 2019-23", video_link="https://youtu.be/4100gLeabmo"),
+ VWCarInfo("MAN TGE 2017-23", video_link="https://youtu.be/4100gLeabmo"),
+ VWCarInfo("MAN eTGE 2020-23", video_link="https://youtu.be/4100gLeabmo"),
+ ],
CAR.GOLF_MK7: [
VWCarInfo("Volkswagen e-Golf 2014-20"),
VWCarInfo("Volkswagen Golf 2015-20"),
@@ -352,6 +360,23 @@ FW_VERSIONS = {
b'\xf1\x875Q0907572P \xf1\x890682',
],
},
+ CAR.CRAFTER_MK2: {
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x8704L906056EK\xf1\x896391',
+ ],
+ # Only current upstreamed vehicle has a manual transmission
+ #(Ecu.transmission, 0x7e1, None): [
+ #],
+ (Ecu.srs, 0x715, None): [
+ b'\xf1\x873Q0959655BG\xf1\x890703\xf1\x82\x0e16120016130012051G1313052900',
+ ],
+ (Ecu.eps, 0x712, None): [
+ b'\xf1\x872N0909143E \xf1\x897021\xf1\x82\x05163AZ306A2',
+ ],
+ (Ecu.fwdRadar, 0x757, None): [
+ b'\xf1\x872Q0907572M \xf1\x890233',
+ ],
+ },
CAR.GOLF_MK7: {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8704E906016A \xf1\x897697',
@@ -942,16 +967,19 @@ FW_VERSIONS = {
b'\xf1\x8704L906021EL\xf1\x897542',
b'\xf1\x8704L906026BP\xf1\x891198',
b'\xf1\x8704L906026BP\xf1\x897608',
+ b'\xf1\x8704L906056CR\xf1\x892797',
b'\xf1\x8705E906018AS\xf1\x899596',
b'\xf1\x878V0906264H \xf1\x890005',
],
(Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x870CW300041D \xf1\x891004',
b'\xf1\x870CW300041G \xf1\x891003',
b'\xf1\x870CW300050J \xf1\x891908',
b'\xf1\x870D9300042M \xf1\x895016',
],
(Ecu.srs, 0x715, None): [
b'\xf1\x873Q0959655AC\xf1\x890189\xf1\x82\r11110011110011021511110200',
+ b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r11110011110011021511110200',
b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r12110012120012021612110200',
b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\x0e1312001313001305171311052900',
b'\xf1\x873Q0959655CM\xf1\x890720\xf1\x82\0161312001313001305171311052900',
@@ -965,6 +993,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x757, None): [
b'\xf1\x875Q0907572B \xf1\x890200\xf1\x82\00101',
b'\xf1\x875Q0907572H \xf1\x890620',
+ b'\xf1\x875Q0907572K \xf1\x890402\xf1\x82\x0101',
b'\xf1\x875Q0907572P \xf1\x890682',
],
},
diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit
index 51de0f0013..b598524fd7 100644
--- a/selfdrive/test/process_replay/ref_commit
+++ b/selfdrive/test/process_replay/ref_commit
@@ -1 +1 @@
-844c84eae269e74b246b039d2b33fd44e98a5b68
\ No newline at end of file
+d795362593d935767c694c652ecb05ab80dd1914
\ No newline at end of file
diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc
index 2edc89d857..47fc5dc03b 100644
--- a/tools/cabana/chartswidget.cc
+++ b/tools/cabana/chartswidget.cc
@@ -13,8 +13,6 @@
#include
#include
-#include "selfdrive/ui/qt/util.h"
-
// ChartsWidget
ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
@@ -24,7 +22,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
QToolBar *toolbar = new QToolBar(tr("Charts"), this);
toolbar->setIconSize({16, 16});
- QAction *new_plot_btn = toolbar->addAction(bootstrapPixmap("file-plus"), "");
+ QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), "");
new_plot_btn->setToolTip(tr("New Plot"));
toolbar->addWidget(title_label = new QLabel());
title_label->setContentsMargins(0, 0, 12, 0);
@@ -46,9 +44,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
range_slider->setPageStep(60); // 1 min
toolbar->addWidget(range_slider);
- reset_zoom_btn = toolbar->addAction(bootstrapPixmap("zoom-out"), "");
+ reset_zoom_btn = toolbar->addAction(utils::icon("zoom-out"), "");
reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)"));
- remove_all_btn = toolbar->addAction(bootstrapPixmap("x"), "");
+ remove_all_btn = toolbar->addAction(utils::icon("x"), "");
remove_all_btn->setToolTip(tr("Remove all charts"));
dock_btn = toolbar->addAction("");
main_layout->addWidget(toolbar);
@@ -170,7 +168,7 @@ void ChartsWidget::setMaxChartRange(int value) {
void ChartsWidget::updateToolBar() {
range_lb->setText(QString(" %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0')));
title_label->setText(tr("Charts: %1").arg(charts.size()));
- dock_btn->setIcon(bootstrapPixmap(docking ? "arrow-up-right" : "arrow-down-left"));
+ dock_btn->setIcon(utils::icon(docking ? "arrow-up-right" : "arrow-down-left"));
dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts"));
remove_all_btn->setEnabled(!charts.isEmpty());
reset_zoom_btn->setEnabled(is_zoomed);
@@ -311,7 +309,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
chart->setMargins({20, 11, 11, 11});
QToolButton *remove_btn = new QToolButton();
- remove_btn->setIcon(bootstrapPixmap("x"));
+ remove_btn->setIcon(utils::icon("x"));
remove_btn->setAutoRaise(true);
remove_btn->setToolTip(tr("Remove Chart"));
close_btn_proxy = new QGraphicsProxyWidget(chart);
@@ -319,7 +317,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
close_btn_proxy->setZValue(chart->zValue() + 11);
QToolButton *manage_btn = new QToolButton();
- manage_btn->setIcon(bootstrapPixmap("gear"));
+ manage_btn->setIcon(utils::icon("gear"));
manage_btn->setAutoRaise(true);
manage_btn->setToolTip(tr("Manage series"));
manage_btn_proxy = new QGraphicsProxyWidget(chart);
@@ -358,11 +356,6 @@ void ChartView::setPlotAreaLeftPosition(int pos) {
void ChartView::addSeries(const QString &msg_id, const Signal *sig) {
QLineSeries *series = new QLineSeries(this);
- // TODO: Due to a bug in CameraWidget the camera frames
- // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed
-#ifndef __APPLE__
- series->setUseOpenGL(true);
-#endif
chart()->addSeries(series);
series->attachAxis(axis_x);
series->attachAxis(axis_y);
@@ -476,17 +469,32 @@ void ChartView::updatePlot(double cur, double min, double max) {
if (min != axis_x->min() || max != axis_x->max()) {
axis_x->setRange(min, max);
updateAxisY();
- }
- // Show points when zoomed in enough
- for (auto &s : sigs) {
- auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; });
- auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; });
+ // Show points when zoomed in enough
+ for (auto &s : sigs) {
+ auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; });
+ auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; });
- int num_points = std::max(end - begin, 1);
- int pixels_per_point = width() / num_points;
+ int num_points = std::max(end - begin, 1);
+ int pixels_per_point = width() / num_points;
- s.series->setPointsVisible(pixels_per_point > 20);
+ s.series->setPointsVisible(pixels_per_point > 20);
+
+ // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs.
+#ifndef __APPLE
+ // OpenGL mode lacks certain features (such as showing points), only use when drawing many points
+ bool use_opengl = pixels_per_point < 1;
+ s.series->setUseOpenGL(use_opengl);
+
+ // Qt doesn't properly apply device pixel ratio in OpenGL mode
+ QApplication* application = static_cast(QApplication::instance());
+ float scale = use_opengl ? application->devicePixelRatio() : 1.0;
+
+ QPen pen = s.series->pen();
+ pen.setWidth(2.0 * scale);
+ s.series->setPen(pen);
+#endif
+ }
}
scene()->invalidate({}, QGraphicsScene::ForegroundLayer);
diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc
index 5e127966c1..3af0fa9fc3 100644
--- a/tools/cabana/detailwidget.cc
+++ b/tools/cabana/detailwidget.cc
@@ -6,7 +6,6 @@
#include
#include
-#include "selfdrive/ui/qt/util.h"
#include "tools/cabana/commands.h"
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
@@ -38,8 +37,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
name_label->setAlignment(Qt::AlignCenter);
name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolbar->addWidget(name_label);
- toolbar->addAction(bootstrapPixmap("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message"));
- remove_msg_act = toolbar->addAction(bootstrapPixmap("x-lg"), "", this, &DetailWidget::removeMsg);
+ toolbar->addAction(utils::icon("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message"));
+ remove_msg_act = toolbar->addAction(utils::icon("x-lg"), "", this, &DetailWidget::removeMsg);
remove_msg_act->setToolTip(tr("Remove Message"));
main_layout->addWidget(toolbar);
@@ -63,8 +62,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
tab_widget = new QTabWidget(this);
tab_widget->setTabPosition(QTabWidget::South);
- tab_widget->addTab(splitter, bootstrapPixmap("file-earmark-ruled"), "&Msg");
- tab_widget->addTab(history_log = new LogsWidget(this), bootstrapPixmap("stopwatch"), "&Logs");
+ tab_widget->addTab(splitter, utils::icon("file-earmark-ruled"), "&Msg");
+ tab_widget->addTab(history_log = new LogsWidget(this), utils::icon("stopwatch"), "&Logs");
main_layout->addWidget(tab_widget);
stacked_layout = new QStackedLayout(this);
@@ -148,7 +147,7 @@ void DetailWidget::refresh() {
if (!warnings.isEmpty()) {
warning_label->setText(warnings.join('\n'));
- warning_icon->setPixmap(bootstrapPixmap(msg ? "exclamation-triangle" : "info-circle"));
+ warning_icon->setPixmap(utils::icon(msg ? "exclamation-triangle" : "info-circle"));
}
warning_widget->setVisible(!warnings.isEmpty());
}
diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc
index ceb7b7ba3f..7f31293c41 100644
--- a/tools/cabana/signaledit.cc
+++ b/tools/cabana/signaledit.cc
@@ -10,8 +10,6 @@
#include "tools/cabana/commands.h"
-#include "selfdrive/ui/qt/util.h"
-
// SignalModel
SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(parent) {
@@ -132,7 +130,7 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const {
if (item->type == Item::Endian) return item->sig->is_little_endian ? Qt::Checked : Qt::Unchecked;
if (item->type == Item::Signed) return item->sig->is_signed ? Qt::Checked : Qt::Unchecked;
} else if (role == Qt::DecorationRole && index.column() == 0 && item->type == Item::ExtraInfo) {
- return bootstrapPixmap(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up");
+ return utils::icon(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up");
}
}
return {};
@@ -331,7 +329,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts),
hl->addWidget(filter_edit);
hl->addStretch(1);
auto collapse_btn = new QToolButton();
- collapse_btn->setIcon(bootstrapPixmap("dash-square"));
+ collapse_btn->setIcon(utils::icon("dash-square"));
collapse_btn->setIconSize({12, 12});
collapse_btn->setAutoRaise(true);
collapse_btn->setToolTip(tr("Collapse All"));
@@ -375,7 +373,7 @@ void SignalView::setMessage(const QString &id) {
void SignalView::rowsChanged() {
auto create_btn = [](const QString &id, const QString &tooltip) {
auto btn = new QToolButton();
- btn->setIcon(bootstrapPixmap(id));
+ btn->setIcon(utils::icon(id));
btn->setToolTip(tooltip);
btn->setAutoRaise(true);
return btn;
diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc
index 023e893e11..699aa7dc01 100644
--- a/tools/cabana/util.cc
+++ b/tools/cabana/util.cc
@@ -1,8 +1,11 @@
#include "tools/cabana/util.h"
+#include
#include
#include
+#include "selfdrive/ui/qt/util.h"
+
static QColor blend(QColor a, QColor b) {
return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2);
}
@@ -100,3 +103,17 @@ QValidator::State NameValidator::validate(QString &input, int &pos) const {
input.replace(' ', '_');
return QRegExpValidator::validate(input, pos);
}
+
+namespace utils {
+QPixmap icon(const QString &id) {
+ static bool dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() >
+ QApplication::style()->standardPalette().color(QPalette::Background).value();
+ QPixmap pm = bootstrapPixmap(id);
+ if (dark_theme) {
+ QPainter p(&pm);
+ p.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ p.fillRect(pm.rect(), Qt::lightGray);
+ }
+ return pm;
+}
+} // namespace utils
diff --git a/tools/cabana/util.h b/tools/cabana/util.h
index 20c85af39e..a598726bb6 100644
--- a/tools/cabana/util.h
+++ b/tools/cabana/util.h
@@ -45,3 +45,7 @@ public:
NameValidator(QObject *parent=nullptr);
QValidator::State validate(QString &input, int &pos) const override;
};
+
+namespace utils {
+QPixmap icon(const QString &id);
+}
diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc
index 445a21c755..d8d89a708c 100644
--- a/tools/cabana/videowidget.cc
+++ b/tools/cabana/videowidget.cc
@@ -13,8 +13,6 @@
#include
#include
-#include "selfdrive/ui/qt/util.h"
-
inline QString formatTime(int seconds) {
return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss");
}
@@ -130,7 +128,7 @@ void VideoWidget::updateState() {
}
void VideoWidget::updatePlayBtnState() {
- play_btn->setIcon(bootstrapPixmap(can->isPaused() ? "play" : "pause"));
+ play_btn->setIcon(utils::icon(can->isPaused() ? "play" : "pause"));
play_btn->setToolTip(can->isPaused() ? tr("Play") : tr("Pause"));
}