From d4dec3ba5e7c68c57c137e15c0a51c903737b8b7 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 18 May 2023 15:25:24 -0700 Subject: [PATCH 001/283] Ford: longitudinal behind alpha toggle (#28196) * bump panda * set safety config/configure experimental longitudinal * send inactive signals * bump * just calculate in function * already in the variable * clean that up * add comment, on ford stock long, prchg seems to be set from the possible future accel * comment * this signal didn't have an impact on engaging * add comment and fix * worst case while AEB * and kill ACCDATAs * this could be dangerous * need to test this too * Revert "need to test this too" This reverts commit 09bba75950fa55d90a82f0109e3138ffe5a1d08c. * Revert "this could be dangerous" This reverts commit 323143e84727f1a780bbb600be5f7ceb763516b1. * Revert "and kill ACCDATAs" This reverts commit 15f6804bf64d01145daf57a592c2f3fd44ceba27. * Revert "worst case while AEB" This reverts commit 85e1aaa8e1af90373c688d1973dbfbb07b1fb8b2. * bump panda * Update selfdrive/car/ford/fordcan.py * move around * was already here * rm * use variable * update docs * Update ref_commit --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 12 ++++++------ selfdrive/car/ford/interface.py | 6 ++++++ selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 46f8bd2787..9068c6ba30 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -31,11 +31,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| -|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Escape 2020-22|Co-Pilot360 Assist+|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Explorer 2020-22|Co-Pilot360 Assist+|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Maverick 2022-23|Co-Pilot360 Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| @@ -152,7 +152,7 @@ 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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lincoln|Aviator 2021|Co-Pilot360 Plus|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| |MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| |MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 937980899f..626853dd8f 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from cereal import car +from panda import Panda from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.ford.values import CAR, Ecu @@ -25,6 +26,11 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.2 ret.steerLimitTimer = 1.0 + ret.experimentalLongitudinalAvailable = True + if experimental_long: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_FORD_LONG_CONTROL + ret.openpilotLongitudinalControl = True + if candidate == CAR.BRONCO_SPORT_MK1: ret.wheelbase = 2.67 ret.steerRatio = 17.7 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4dee64009f..310d6300d2 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -658e4dd36d92ae7a973a090aaf3fab62fdf701b6 +c67a0959201829ef07a7d68d5fb59603b3983587 From d528481d8dc5669fa6dbeca88b8d63f112205635 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Thu, 18 May 2023 15:30:58 -0700 Subject: [PATCH 002/283] Offset topdown map by 128 meters (#28216) We drive forward :) --- selfdrive/navd/map_renderer.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 203470bb42..5c7e17cd51 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -15,7 +15,9 @@ const int HEIGHT = 256, WIDTH = 256; const int NUM_VIPC_BUFFERS = 4; const int EARTH_CIRCUMFERENCE_METERS = 40075000; +const int EARTH_RADIUS_METERS = 6378137; const int PIXELS_PER_TILE = 256; +const int MAP_OFFSET = 128; const bool TEST_MODE = getenv("MAP_RENDER_TEST_MODE"); const int LLK_DECIMATION = TEST_MODE ? 1 : 10; @@ -26,6 +28,14 @@ float get_zoom_level_for_scale(float lat, float meters_per_pixel) { return log2(num_tiles) - 1; } +QMapbox::Coordinate get_point_along_line(float lat, float lon, float bearing, float dist) { + float ang_dist = dist / EARTH_RADIUS_METERS; + float lat1 = DEG2RAD(lat), lon1 = DEG2RAD(lon), bearing1 = DEG2RAD(bearing); + float lat2 = asin(sin(lat1)*cos(ang_dist) + cos(lat1)*sin(ang_dist)*cos(bearing1)); + float lon2 = lon1 + atan2(sin(bearing1)*sin(ang_dist)*cos(lat1), cos(ang_dist)-sin(lat1)*sin(lat2)); + return QMapbox::Coordinate(RAD2DEG(lat2), RAD2DEG(lon2)); +} + MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_settings(settings) { QSurfaceFormat fmt; @@ -70,7 +80,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set if (online) { vipc_server.reset(new VisionIpcServer("navd")); - vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH/2, HEIGHT/2); + vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH, HEIGHT); vipc_server->start_listener(); pm.reset(new PubMaster({"navThumbnail", "mapRenderState"})); @@ -93,7 +103,8 @@ void MapRenderer::msgUpdate() { bool localizer_valid = (location.getStatus() == cereal::LiveLocationKalman::Status::VALID) && pos.getValid(); if (localizer_valid && (sm->rcv_frame("liveLocationKalman") % LLK_DECIMATION) == 0) { - updatePosition(QMapbox::Coordinate(pos.getValue()[0], pos.getValue()[1]), RAD2DEG(orientation.getValue()[2])); + float bearing = RAD2DEG(orientation.getValue()[2]); + updatePosition(get_point_along_line(pos.getValue()[0], pos.getValue()[1], bearing, MAP_OFFSET), bearing); // TODO: use the static rendering mode if (!loaded() && frame_id > 0) { From a30a0c4b698fa73017ba59b48ecd59fb2a9ef2af Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 18 May 2023 16:23:14 -0700 Subject: [PATCH 003/283] bump to 0.9.3 --- RELEASES.md | 3 +++ common/version.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index a4b2a76875..b2e7be396a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,6 @@ +Version 0.9.3 (2023-06-XX) +======================== + Version 0.9.2 (2023-05-22) ======================== * New driving model diff --git a/common/version.h b/common/version.h index 5637029cf4..57d60e7f68 100644 --- a/common/version.h +++ b/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.9.2" +#define COMMA_VERSION "0.9.3" From e6c9e764c0f9198bc4fadd1e01679a5d1e2d55b6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 19 May 2023 18:01:38 +0800 Subject: [PATCH 004/283] cabana: fix segfault on screen changed (#28233) fix segfault on scrrenChanged --- tools/cabana/chart/chart.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 7840ffd673..a7f700f3c2 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -44,9 +44,9 @@ ChartView::ChartView(const std::pair &x_range, ChartsWidget *par setTheme(settings.theme == DARK_THEME ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); signal_value_font.setPointSize(9); - QObject::connect(axis_y, &QValueAxis::rangeChanged, [this]() { resetChartCache(); }); - QObject::connect(axis_y, &QAbstractAxis::titleTextChanged, [this]() { resetChartCache(); }); - QObject::connect(window()->windowHandle(), &QWindow::screenChanged, [this]() { resetChartCache(); }); + QObject::connect(axis_y, &QValueAxis::rangeChanged, this, &ChartView::resetChartCache); + QObject::connect(axis_y, &QAbstractAxis::titleTextChanged, this, &ChartView::resetChartCache); + QObject::connect(window()->windowHandle(), &QWindow::screenChanged, this, &ChartView::resetChartCache); QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); From ac2c87246af2d73f6c0481934d8cc4969aba4b4d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 20 May 2023 03:36:11 +0800 Subject: [PATCH 005/283] cabana: use the same double precision as the dbc file (#28234) --- tools/cabana/dbc/dbc.h | 3 +++ tools/cabana/dbc/dbcfile.cc | 5 ++--- tools/cabana/signalview.cc | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index 7daa258ecd..c88834876b 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -85,3 +86,5 @@ int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size); std::pair getSignalRange(const cabana::Signal *s); inline std::vector allDBCNames() { return get_dbc_names(); } +inline QString doubleToString(double value) { return QString::number(value, 'g', std::numeric_limits::digits10); } + diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index fd20c0af19..49579bc7fa 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -257,8 +256,8 @@ QString DBCFile::generateDBC() { .arg(sig->size) .arg(sig->is_little_endian ? '1' : '0') .arg(sig->is_signed ? '-' : '+') - .arg(sig->factor, 0, 'g', std::numeric_limits::digits10) - .arg(sig->offset, 0, 'g', std::numeric_limits::digits10) + .arg(doubleToString(sig->factor)) + .arg(doubleToString(sig->offset)) .arg(sig->min) .arg(sig->max) .arg(sig->unit); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 124f9f6b9a..cf72b34ccf 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -124,8 +124,8 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { case Item::Sig: return item->sig_val; case Item::Name: return item->sig->name; case Item::Size: return item->sig->size; - case Item::Offset: return QString::number(item->sig->offset, 'f', 6); - case Item::Factor: return QString::number(item->sig->factor, 'f', 6); + case Item::Offset: return doubleToString(item->sig->offset); + case Item::Factor: return doubleToString(item->sig->factor); case Item::Unit: return item->sig->unit; case Item::Comment: return item->sig->comment; case Item::Min: return item->sig->min; From 309126a5277a8735f76a2344cfb2aaa3ae13a05a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 19 May 2023 13:29:33 -0700 Subject: [PATCH 006/283] logging: change event_name arg (#28232) This doesn't change anything in practice, but makes it harder to write a bug where a kwarg with the name `event` would overwrite the event name. --- common/logging_extra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/logging_extra.py b/common/logging_extra.py index 5baaac1f90..899ad7a391 100644 --- a/common/logging_extra.py +++ b/common/logging_extra.py @@ -153,9 +153,9 @@ class SwagLogger(logging.Logger): def bind_global(self, **kwargs): self.global_ctx.update(kwargs) - def event(self, event_name, *args, **kwargs): + def event(self, event, *args, **kwargs): evt = NiceOrderedDict() - evt['event'] = event_name + evt['event'] = event if args: evt['args'] = args evt.update(kwargs) From bda0d6ac77b4f1179eea76e8146da6eee5cae983 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Fri, 19 May 2023 15:20:43 -0700 Subject: [PATCH 007/283] update dm model README (#28238) add calib dm input in readme --- selfdrive/modeld/models/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/modeld/models/README.md b/selfdrive/modeld/models/README.md index 80d6dc0e02..04964f3eab 100644 --- a/selfdrive/modeld/models/README.md +++ b/selfdrive/modeld/models/README.md @@ -35,6 +35,7 @@ Read [here](https://github.com/commaai/openpilot/blob/90af436a121164a51da9fa48d0 * single image W = 1440 H = 960 represented in planar YUV420 format: * full input size is 1440 * 960 = 1382400 * normalized ranging from 0.0 to 1.0 in float32 (onnx runner) or ranging from 0 to 255 in uint8 (snpe runner) +* camera calibration angles (roll, pitch, yaw) from liveCalibration: 3 x float32 inputs ### output format * 84 x float32 outputs = 2 + 41 * 2 ([parsing example](https://github.com/commaai/openpilot/blob/22ce4e17ba0d3bfcf37f8255a4dd1dc683fe0c38/selfdrive/modeld/models/dmonitoring.cc#L33)) From 2014b10ec33f9117cfae18bc3a6660ae7a2c50f1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 19 May 2023 17:36:30 -0700 Subject: [PATCH 008/283] boardd: longer loopback test (#28239) Co-authored-by: Comma Device --- .../boardd/tests/test_boardd_loopback.py | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index 4be5b3f7e8..f3642e1668 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 import os +import copy import random import time import unittest from collections import defaultdict +from pprint import pprint import cereal.messaging as messaging from cereal import car, log @@ -63,12 +65,13 @@ class TestBoardd(unittest.TestCase): n = 200 for i in range(n): + print(f"boardd loopback {i}/{n}") self.spinner.update(f"boardd loopback {i}/{n}") sent_msgs = defaultdict(set) - for _ in range(random.randrange(10)): + for _ in range(random.randrange(20, 100)): to_send = [] - for __ in range(random.randrange(100)): + for __ in range(random.randrange(50)): bus = random.choice([b for b in range(3*num_pandas) if b % 4 != 3]) addr = random.randrange(1, 1<<29) dat = bytes(random.getrandbits(8) for _ in range(random.randrange(1, 9))) @@ -76,22 +79,25 @@ class TestBoardd(unittest.TestCase): to_send.append(make_can_msg(addr, dat, bus)) sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan')) - for _ in range(100 * 2): + sent_loopback = copy.deepcopy(sent_msgs) + sent_loopback.update({k+128: copy.deepcopy(v) for k, v in sent_msgs.items()}) + sent_total = {k: len(v) for k, v in sent_loopback.items()} + for _ in range(100 * 5): recvd = messaging.drain_sock(can, wait_for_one=True) for msg in recvd: for m in msg.can: - if m.src >= 128: - key = (m.address, m.dat) - assert key in sent_msgs[m.src-128], f"got unexpected msg: {m.src=} {m.address=} {m.dat=}" - sent_msgs[m.src-128].discard(key) + key = (m.address, m.dat) + assert key in sent_loopback[m.src], f"got unexpected msg: {m.src=} {m.address=} {m.dat=}" + sent_loopback[m.src].discard(key) - if all(len(v) == 0 for v in sent_msgs.values()): + if all(len(v) == 0 for v in sent_loopback.values()): break # if a set isn't empty, messages got dropped - for bus in sent_msgs.keys(): - assert not len(sent_msgs[bus]), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages" - + pprint(sent_msgs) + pprint(sent_loopback) + for bus in sent_loopback.keys(): + assert not len(sent_loopback[bus]), f"loop {i}: bus {bus} missing {len(sent_loopback[bus])} out of {sent_total[bus]} messages" if __name__ == "__main__": unittest.main() From 184e224a6ad7e8edd08315b3420b88cd66aca737 Mon Sep 17 00:00:00 2001 From: johangithub Date: Fri, 19 May 2023 18:30:43 -0700 Subject: [PATCH 009/283] HKG: add 2017 Genesis G90 Fingerprint (#28230) --- selfdrive/car/hyundai/values.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 8be3a5fe50..b5d35cc9ea 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1142,7 +1142,10 @@ FW_VERSIONS = { ], }, 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.transmission, 0x7e1, None): [ + b'\xf1\x87VDGMD15352242DD3w\x87gxwvgv\x87wvw\x88wXwffVfffUfw\x88o\xff\x06J\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7', + 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 '], (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00HI LKAS AT USA LHD 1.00 1.00 95895-D2020 160302'], (Ecu.engine, 0x7e0, None): [b'\xf1\x810000000000\x00'], From 7a684da47f7c587063ec3c333d748cc37b5417a6 Mon Sep 17 00:00:00 2001 From: Kyle Greenlaw Date: Sat, 20 May 2023 02:49:46 -0300 Subject: [PATCH 010/283] Subaru: Add fw for 2020 Subaru Outback (#28240) Route: a4e8e925930fce2c|2023-05-19--20-47-32 --- selfdrive/car/subaru/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index f90f015bfb..1977b43f95 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -510,6 +510,7 @@ FW_VERSIONS = { b'\xf1\x82\xe2,\xa0@\x07', b'\xbc"`q\x07', b'\xe3,\xa0@\x07', + b'\xbc,\xa0u\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xa5\xfe\xf7@\x00', @@ -519,6 +520,7 @@ FW_VERSIONS = { b'\xf1\x82\xa7\xf6D@\x00', b'\xa7\xf6D@\x00', b'\xa7\xfe\xf4@\x00', + b'\xa5\xfe\xf8@\x00', ], }, } From e4a37620ee9cb6416e51a3e8346e5008aeeab027 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 19 May 2023 23:24:52 -0700 Subject: [PATCH 011/283] boardd: handle nack on tx buffer full (#28241) * boardd: handle nack on tx buffer full * print pandaStates * rx buffer too small * connect timeout --------- Co-authored-by: Comma Device --- panda | 2 +- selfdrive/boardd/panda_comms.h | 4 +-- selfdrive/boardd/spi.cc | 34 ++++++++----------- .../boardd/tests/test_boardd_loopback.py | 8 ++++- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/panda b/panda index 2a53833753..52f96bac68 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2a538337537e6830f02565c2c36af4f886c963e4 +Subproject commit 52f96bac685b129c5b90e274fe39386e76da512e diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index f93d292170..723a4ab79c 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -75,8 +75,8 @@ private: inline static std::recursive_mutex hw_lock; int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack); - int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len); + int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len, unsigned int timeout); int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); - int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); + int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); }; #endif diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 82a95f7759..54638b1b8d 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -29,8 +29,7 @@ struct __attribute__((packed)) spi_header { uint16_t max_rx_len; }; -const int SPI_MAX_RETRIES = 5; -const int SPI_ACK_TIMEOUT = 50; // milliseconds +const int SPI_ACK_TIMEOUT = 500; // milliseconds const std::string SPI_DEVICE = "/dev/spidev0.0"; class LockEx { @@ -89,7 +88,7 @@ PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { } // get hw UID/serial - ret = control_read(0xc3, 0, 0, uid, uid_len); + ret = control_read(0xc3, 0, 0, uid, uid_len, 1000); if (ret == uid_len) { std::stringstream stream; for (int i = 0; i < uid_len; i++) { @@ -127,37 +126,33 @@ void PandaSpiHandle::cleanup() { int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout) { - LockEx lock(spi_fd, hw_lock); ControlPacket_t packet = { .request = request, .param1 = param1, .param2 = param2, .length = 0 }; - return spi_transfer_retry(0, (uint8_t *) &packet, sizeof(packet), NULL, 0); + return spi_transfer_retry(0, (uint8_t *) &packet, sizeof(packet), NULL, 0, timeout); } int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout) { - LockEx lock(spi_fd, hw_lock); ControlPacket_t packet = { .request = request, .param1 = param1, .param2 = param2, .length = length }; - return spi_transfer_retry(0, (uint8_t *) &packet, sizeof(packet), data, length); + return spi_transfer_retry(0, (uint8_t *) &packet, sizeof(packet), data, length, timeout); } int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { - LockEx lock(spi_fd, hw_lock); - return bulk_transfer(endpoint, data, length, NULL, 0); + return bulk_transfer(endpoint, data, length, NULL, 0, timeout); } int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { - LockEx lock(spi_fd, hw_lock); - return bulk_transfer(endpoint, NULL, 0, data, length); + return bulk_transfer(endpoint, NULL, 0, data, length, timeout); } -int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len) { +int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len, unsigned int timeout) { const int xfer_size = 0x40 * 15; int ret = 0; @@ -166,10 +161,10 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t int d; if (tx_data != NULL) { int len = std::min(xfer_size, tx_len - (xfer_size * i)); - d = spi_transfer_retry(endpoint, tx_data + (xfer_size * i), len, NULL, 0); + d = spi_transfer_retry(endpoint, tx_data + (xfer_size * i), len, NULL, 0, timeout); } else { uint16_t to_read = std::min(xfer_size, rx_len - ret); - d = spi_transfer_retry(endpoint, NULL, 0, rx_data + (xfer_size * i), to_read); + d = spi_transfer_retry(endpoint, NULL, 0, rx_data + (xfer_size * i), to_read, timeout); } if (d < 0) { @@ -213,15 +208,13 @@ bool check_checksum(uint8_t *data, int data_len) { } -int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { +int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout) { int ret; - - int count = SPI_MAX_RETRIES; + double start_time = millis_since_boot(); do { // TODO: handle error ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); - count--; - } while (ret < 0 && connected && count > 0); + } while (ret < 0 && connected && ((timeout == 0) || (millis_since_boot() - start_time) < timeout)); return ret; } @@ -238,7 +231,7 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { if (rx_buf[0] == ack) { break; } else if (rx_buf[0] == SPI_NACK) { - LOGW("SPI: got NACK"); + LOGD("SPI: got NACK"); return -1; } @@ -255,6 +248,7 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { int ret; uint16_t rx_data_len; + LockEx lock(spi_fd, hw_lock); // needs to be less, since we need to have space for the checksum assert(tx_len < SPI_BUF_SIZE); diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index f3642e1668..d0504d6bf2 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -61,6 +61,7 @@ class TestBoardd(unittest.TestCase): sendcan = messaging.pub_sock('sendcan') can = messaging.sub_sock('can', conflate=False, timeout=100) + sm = messaging.SubMaster(['pandaStates']) time.sleep(0.5) n = 200 @@ -71,7 +72,7 @@ class TestBoardd(unittest.TestCase): sent_msgs = defaultdict(set) for _ in range(random.randrange(20, 100)): to_send = [] - for __ in range(random.randrange(50)): + for __ in range(random.randrange(20)): bus = random.choice([b for b in range(3*num_pandas) if b % 4 != 3]) addr = random.randrange(1, 1<<29) dat = bytes(random.getrandbits(8) for _ in range(random.randrange(1, 9))) @@ -83,6 +84,7 @@ class TestBoardd(unittest.TestCase): sent_loopback.update({k+128: copy.deepcopy(v) for k, v in sent_msgs.items()}) sent_total = {k: len(v) for k, v in sent_loopback.items()} for _ in range(100 * 5): + sm.update(0) recvd = messaging.drain_sock(can, wait_for_one=True) for msg in recvd: for m in msg.can: @@ -96,8 +98,12 @@ class TestBoardd(unittest.TestCase): # if a set isn't empty, messages got dropped pprint(sent_msgs) pprint(sent_loopback) + print({k: len(x) for k, x in sent_loopback.items()}) + print(sum([len(x) for x in sent_loopback.values()])) + pprint(sm['pandaStates']) # may drop messages due to RX buffer overflow for bus in sent_loopback.keys(): assert not len(sent_loopback[bus]), f"loop {i}: bus {bus} missing {len(sent_loopback[bus])} out of {sent_total[bus]} messages" + if __name__ == "__main__": unittest.main() From 39c5d492bfb4ca1630fed1a4ab6990c171c5e797 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 20 May 2023 17:59:41 -0700 Subject: [PATCH 012/283] time to onroad test (#28242) * time to onroad test * run few times * test on stripped builds * manager * cleanup * split those out * run first --------- Co-authored-by: Comma Device --- Jenkinsfile | 1 + release/files_common | 1 + selfdrive/test/helpers.py | 8 ++++- selfdrive/test/test_onroad.py | 6 ---- selfdrive/test/test_time_to_onroad.py | 46 +++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 7 deletions(-) create mode 100755 selfdrive/test/test_time_to_onroad.py diff --git a/Jenkinsfile b/Jenkinsfile index 8a2f83be2f..9b1ea421ac 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -153,6 +153,7 @@ pipeline { ["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR EXTRA_FILES='tools/' ./build_devel.sh"], ["build openpilot", "cd selfdrive/manager && ./build.py"], ["check dirty", "release/check-dirty.sh"], + ["time to onroad", "cd selfdrive/test/ && pytest test_time_to_onroad.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], ]) diff --git a/release/files_common b/release/files_common index 2fcbf90c91..6f671e1781 100644 --- a/release/files_common +++ b/release/files_common @@ -293,6 +293,7 @@ selfdrive/test/__init__.py selfdrive/test/helpers.py selfdrive/test/setup_device_ci.sh selfdrive/test/test_onroad.py +selfdrive/test/test_time_to_onroad.py selfdrive/ui/.gitignore selfdrive/ui/SConscript diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py index 281c902933..9fc80d8d72 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -3,13 +3,19 @@ import time from functools import wraps import cereal.messaging as messaging +from common.params import Params from selfdrive.manager.process_config import managed_processes from system.hardware import PC from system.version import training_version, terms_version def set_params_enabled(): - from common.params import Params + os.environ['PASSIVE'] = "0" + os.environ['REPLAY'] = "1" + os.environ['SKIP_FW_QUERY'] = "1" + os.environ['FINGERPRINT'] = "TOYOTA COROLLA TSS2 2019" + os.environ['LOGPRINT'] = "debug" + params = Params() params.put("HasAcceptedTerms", terms_version) params.put("CompletedTrainingVersion", training_version) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 22ddb6e9cc..327d8d0ff6 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -95,12 +95,6 @@ class TestOnroad(unittest.TestCase): return # setup env - os.environ['PASSIVE'] = "0" - os.environ['REPLAY'] = "1" - os.environ['SKIP_FW_QUERY'] = "1" - os.environ['FINGERPRINT'] = "TOYOTA COROLLA TSS2 2019" - os.environ['LOGPRINT'] = "debug" - params = Params() params.clear_all() set_params_enabled() diff --git a/selfdrive/test/test_time_to_onroad.py b/selfdrive/test/test_time_to_onroad.py new file mode 100755 index 0000000000..65683ed890 --- /dev/null +++ b/selfdrive/test/test_time_to_onroad.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +import os +import time +import subprocess +import pytest + +import cereal.messaging as messaging +from common.basedir import BASEDIR +from common.timeout import Timeout +from selfdrive.test.helpers import set_params_enabled + + +def test_time_to_onroad(): + # launch + set_params_enabled() + manager_path = os.path.join(BASEDIR, "selfdrive/manager/manager.py") + proc = subprocess.Popen(["python", manager_path]) + + start_time = time.monotonic() + sm = messaging.SubMaster(['controlsState', 'deviceState']) + try: + # wait for onroad + with Timeout(20, "timed out waiting to go onroad"): + while True: + sm.update(1000) + if sm['deviceState'].started: + break + time.sleep(1) + + # wait for engageability + with Timeout(10, "timed out waiting for engageable"): + while True: + sm.update(1000) + if sm['controlsState'].engageable: + break + time.sleep(1) + print(f"engageable after {time.monotonic() - start_time:.2f}s") + + # once we're enageable, must be for the next few seconds + for _ in range(500): + sm.update(100) + assert sm['controlsState'].engageable + finally: + proc.terminate() + if proc.wait(60) is None: + proc.kill() From 3d94423108cbe313d47301c7d6e3f24227157c07 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 20 May 2023 18:09:57 -0700 Subject: [PATCH 013/283] GM: explicitly copy signals to forward (#28243) * gm * same order as DBC --- selfdrive/car/gm/gmcan.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 63189bcd89..0de2066678 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -20,10 +20,20 @@ def create_buttons(packer, bus, idx, button): def create_pscm_status(packer, bus, pscm_status): - checksum_mod = int(1 - pscm_status["HandsOffSWlDetectionStatus"]) << 5 - pscm_status["HandsOffSWlDetectionStatus"] = 1 - pscm_status["PSCMStatusChecksum"] += checksum_mod - return packer.make_can_msg("PSCMStatus", bus, pscm_status) + values = {s: pscm_status[s] for s in [ + "HandsOffSWDetectionMode", + "HandsOffSWlDetectionStatus", + "LKATorqueDeliveredStatus", + "LKADriverAppldTrq", + "LKATorqueDelivered", + "LKATotalTorqueDelivered", + "RollingCounter", + "PSCMStatusChecksum", + ]} + checksum_mod = int(1 - values["HandsOffSWlDetectionStatus"]) << 5 + values["HandsOffSWlDetectionStatus"] = 1 + values["PSCMStatusChecksum"] += checksum_mod + return packer.make_can_msg("PSCMStatus", bus, values) def create_steering_control(packer, bus, apply_steer, idx, lkas_active): From 9160faf8e554efae57d79517af1cbdf73abcc8fd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 20 May 2023 18:09:12 -0700 Subject: [PATCH 014/283] remove unused import --- selfdrive/test/test_time_to_onroad.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/test/test_time_to_onroad.py b/selfdrive/test/test_time_to_onroad.py index 65683ed890..5991250945 100755 --- a/selfdrive/test/test_time_to_onroad.py +++ b/selfdrive/test/test_time_to_onroad.py @@ -2,7 +2,6 @@ import os import time import subprocess -import pytest import cereal.messaging as messaging from common.basedir import BASEDIR From f951390ddaeaece3ffe2c79432adb85e7d974229 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sat, 20 May 2023 20:20:57 -0500 Subject: [PATCH 015/283] VW: Explicit signal pass-through (#28179) * VW: Explicit signal copy * normalize whitespace --- selfdrive/car/volkswagen/carcontroller.py | 3 +-- selfdrive/car/volkswagen/mqbcan.py | 28 ++++++++++++++++++---- selfdrive/car/volkswagen/pqcan.py | 29 +++++++++++++++++++---- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index c17b632450..3b897c0c16 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -101,8 +101,7 @@ class CarController: gra_send_ready = self.CP.pcmCruise and CS.gra_stock_values["COUNTER"] != self.gra_acc_counter_last if gra_send_ready and (CC.cruiseControl.cancel or CC.cruiseControl.resume): - counter = (CS.gra_stock_values["COUNTER"] + 1) % 16 - can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, ext_bus, CS.gra_stock_values, counter, + can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, ext_bus, CS.gra_stock_values, cancel=CC.cruiseControl.cancel, resume=CC.cruiseControl.resume)) new_actuators = actuators.copy() diff --git a/selfdrive/car/volkswagen/mqbcan.py b/selfdrive/car/volkswagen/mqbcan.py index b461fd02ae..3b07044d37 100644 --- a/selfdrive/car/volkswagen/mqbcan.py +++ b/selfdrive/car/volkswagen/mqbcan.py @@ -11,7 +11,15 @@ def create_steering_control(packer, bus, apply_steer, lkas_enabled): def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control): - values = ldw_stock_values.copy() + values = {} + if len(ldw_stock_values): + values = {s: ldw_stock_values[s] for s in [ + "LDW_SW_Warnung_links", # Blind spot in warning mode on left side due to lane departure + "LDW_SW_Warnung_rechts", # Blind spot in warning mode on right side due to lane departure + "LDW_Seite_DLCTLC", # Direction of most likely lane departure (left or right) + "LDW_DLC", # Lane departure, distance to line crossing + "LDW_TLC", # Lane departure, time to line crossing + ]} values.update({ "LDW_Status_LED_gelb": 1 if enabled and steering_pressed else 0, @@ -23,11 +31,23 @@ def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pres return packer.make_can_msg("LDW_02", bus, values) -def create_acc_buttons_control(packer, bus, gra_stock_values, counter, cancel=False, resume=False): - values = gra_stock_values.copy() +def create_acc_buttons_control(packer, bus, gra_stock_values, cancel=False, resume=False): + values = {s: gra_stock_values[s] for s in [ + "GRA_Hauptschalter", # ACC button, on/off + "GRA_Abbrechen", # ACC button, cancel + "GRA_Tip_Setzen", # ACC button, set + "GRA_Tip_Hoch", # ACC button, increase or accel + "GRA_Tip_Runter", # ACC button, decrease or decel + "GRA_Tip_Wiederaufnahme", # ACC button, resume + "GRA_Verstellung_Zeitluecke", # ACC button, time gap adj + "GRA_Typ_Hauptschalter", # ACC main button type + "GRA_Codierung", # ACC button configuration/coding + "GRA_Tip_Stufe_2", # unknown related to stalk type + "GRA_ButtonTypeInfo", # unknown related to stalk type + ]} values.update({ - "COUNTER": counter, + "COUNTER": (gra_stock_values["COUNTER"] + 1) % 16, "GRA_Abbrechen": cancel, "GRA_Tip_Wiederaufnahme": resume, }) diff --git a/selfdrive/car/volkswagen/pqcan.py b/selfdrive/car/volkswagen/pqcan.py index bac3ca121d..9df43c8cf4 100644 --- a/selfdrive/car/volkswagen/pqcan.py +++ b/selfdrive/car/volkswagen/pqcan.py @@ -10,7 +10,15 @@ def create_steering_control(packer, bus, apply_steer, lkas_enabled): def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control): - values = ldw_stock_values.copy() + values = {} + if len(ldw_stock_values): + values = {s: ldw_stock_values[s] for s in [ + "LDW_SW_Warnung_links", # Blind spot in warning mode on left side due to lane departure + "LDW_SW_Warnung_rechts", # Blind spot in warning mode on right side due to lane departure + "LDW_Seite_DLCTLC", # Direction of most likely lane departure (left or right) + "LDW_DLC", # Lane departure, distance to line crossing + "LDW_TLC", # Lane departure, time to line crossing + ]} values.update({ "LDW_Lampe_gelb": 1 if enabled and steering_pressed else 0, @@ -23,11 +31,24 @@ def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pres return packer.make_can_msg("LDW_Status", bus, values) -def create_acc_buttons_control(packer, bus, gra_stock_values, counter, cancel=False, resume=False): - values = gra_stock_values.copy() +def create_acc_buttons_control(packer, bus, gra_stock_values, cancel=False, resume=False): + values = {s: gra_stock_values[s] for s in [ + "GRA_Hauptschalt", # ACC button, on/off + "GRA_Typ_Hauptschalt", # ACC button, momentary vs latching + "GRA_Kodierinfo", # ACC button, configuration + "GRA_Abbrechen", # ACC button, cancel + "GRA_Neu_Setzen", # ACC button, set + "GRA_Up_lang", # ACC button, increase or accel, long press + "GRA_Down_lang", # ACC button, decrease or decel, long press + "GRA_Up_kurz", # ACC button, increase or accel, short press + "GRA_Down_kurz", # ACC button, decrease or decel, short press + "GRA_Recall", # ACC button, resume + "GRA_Zeitluecke", # ACC button, time gap adj + "GRA_Sender", # ACC button, CAN message originator + ]} values.update({ - "COUNTER": counter, + "COUNTER": (gra_stock_values["COUNTER"] + 1) % 16, "GRA_Abbrechen": cancel, "GRA_Recall": resume, }) From 37eb9f900c18b68ced90e5c417c7aa7a421509bf Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 20 May 2023 18:25:19 -0700 Subject: [PATCH 016/283] Mazda: explicitly copy signals to forward (#28244) mazda --- selfdrive/car/mazda/mazdacan.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/mazda/mazdacan.py b/selfdrive/car/mazda/mazdacan.py index e2ee93e022..3b29a25621 100644 --- a/selfdrive/car/mazda/mazdacan.py +++ b/selfdrive/car/mazda/mazdacan.py @@ -1,5 +1,3 @@ -import copy - from selfdrive.car.mazda.values import GEN1, Buttons @@ -64,7 +62,17 @@ def create_steering_control(packer, car_fingerprint, frame, apply_steer, lkas): def create_alert_command(packer, cam_msg: dict, ldw: bool, steer_required: bool): - values = copy.copy(cam_msg) + values = {s: cam_msg[s] for s in [ + "LINE_VISIBLE", + "LINE_NOT_VISIBLE", + "LANE_LINES", + "BIT1", + "BIT2", + "BIT3", + "NO_ERR_BIT", + "S1", + "S1_HBEAM", + ]} values.update({ # TODO: what's the difference between all these? do we need to send all? "HANDS_WARN_3_BITS": 0b111 if steer_required else 0, From 24579949c1b6781b667872a687a5ecbba2fe872a Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 21 May 2023 00:31:12 -0500 Subject: [PATCH 017/283] VW: A little less signal pass-through (#28246) --- selfdrive/car/volkswagen/mqbcan.py | 6 ------ selfdrive/car/volkswagen/pqcan.py | 8 -------- 2 files changed, 14 deletions(-) diff --git a/selfdrive/car/volkswagen/mqbcan.py b/selfdrive/car/volkswagen/mqbcan.py index 3b07044d37..849d99592f 100644 --- a/selfdrive/car/volkswagen/mqbcan.py +++ b/selfdrive/car/volkswagen/mqbcan.py @@ -34,12 +34,6 @@ def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pres def create_acc_buttons_control(packer, bus, gra_stock_values, cancel=False, resume=False): values = {s: gra_stock_values[s] for s in [ "GRA_Hauptschalter", # ACC button, on/off - "GRA_Abbrechen", # ACC button, cancel - "GRA_Tip_Setzen", # ACC button, set - "GRA_Tip_Hoch", # ACC button, increase or accel - "GRA_Tip_Runter", # ACC button, decrease or decel - "GRA_Tip_Wiederaufnahme", # ACC button, resume - "GRA_Verstellung_Zeitluecke", # ACC button, time gap adj "GRA_Typ_Hauptschalter", # ACC main button type "GRA_Codierung", # ACC button configuration/coding "GRA_Tip_Stufe_2", # unknown related to stalk type diff --git a/selfdrive/car/volkswagen/pqcan.py b/selfdrive/car/volkswagen/pqcan.py index 9df43c8cf4..f42c3cf781 100644 --- a/selfdrive/car/volkswagen/pqcan.py +++ b/selfdrive/car/volkswagen/pqcan.py @@ -36,14 +36,6 @@ def create_acc_buttons_control(packer, bus, gra_stock_values, cancel=False, resu "GRA_Hauptschalt", # ACC button, on/off "GRA_Typ_Hauptschalt", # ACC button, momentary vs latching "GRA_Kodierinfo", # ACC button, configuration - "GRA_Abbrechen", # ACC button, cancel - "GRA_Neu_Setzen", # ACC button, set - "GRA_Up_lang", # ACC button, increase or accel, long press - "GRA_Down_lang", # ACC button, decrease or decel, long press - "GRA_Up_kurz", # ACC button, increase or accel, short press - "GRA_Down_kurz", # ACC button, decrease or decel, short press - "GRA_Recall", # ACC button, resume - "GRA_Zeitluecke", # ACC button, time gap adj "GRA_Sender", # ACC button, CAN message originator ]} From 038d2264aab863a5c262456782e8c84443c70c56 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 20 May 2023 23:35:14 -0700 Subject: [PATCH 018/283] spi: handle timeout more like usb (#28249) --- panda | 2 +- selfdrive/boardd/panda_comms.h | 4 +-- selfdrive/boardd/spi.cc | 57 ++++++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/panda b/panda index 52f96bac68..c898ec7ce8 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 52f96bac685b129c5b90e274fe39386e76da512e +Subproject commit c898ec7ce8b7d9a5656b18de810f7b80e8ca15d4 diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index 723a4ab79c..b07aec509e 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -74,9 +74,9 @@ private: uint8_t rx_buf[SPI_BUF_SIZE]; inline static std::recursive_mutex hw_lock; - int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack); + int wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout); int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len, unsigned int timeout); - int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); + int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); }; #endif diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 54638b1b8d..92ec1c4cdc 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -22,6 +22,12 @@ #define SPI_NACK 0x1FU #define SPI_CHECKSUM_START 0xABU + +enum SpiError { + NACK = -2, + ACK_TIMEOUT = -3, +}; + struct __attribute__((packed)) spi_header { uint8_t sync; uint8_t endpoint; @@ -40,8 +46,8 @@ public: }; ~LockEx() { - m.unlock(); flock(fd, LOCK_UN); + m.unlock(); } private: @@ -170,7 +176,7 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t if (d < 0) { LOGE("SPI: bulk transfer failed with %d", d); comms_healthy = false; - return -1; + return d; } ret += d; @@ -210,17 +216,40 @@ bool check_checksum(uint8_t *data, int data_len) { int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout) { int ret; + int count = 0; + bool timed_out = false; double start_time = millis_since_boot(); do { - // TODO: handle error - ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); - } while (ret < 0 && connected && ((timeout == 0) || (millis_since_boot() - start_time) < timeout)); + ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len, timeout); + + if (ret < 0) { + timed_out = (timeout != 0) && (count > 5); + count += ret == SpiError::ACK_TIMEOUT; + std::this_thread::yield(); + } + } while (ret < 0 && connected && !timed_out); + + if (ret < 0) { + LOGE("transfer failed, after %d tries, %.2fms", count, millis_since_boot() - start_time); + } return ret; } -int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { +int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout) { double start_millis = millis_since_boot(); + if (timeout <= 0) { + timeout = SPI_ACK_TIMEOUT; + } + + spi_ioc_transfer transfer = { + .tx_buf = (uint64_t)tx_buf, + .rx_buf = (uint64_t)rx_buf, + .delay_usecs = 5, + .len = 1 + }; + tx_buf[0] = tx; + while (true) { int ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); if (ret < 0) { @@ -232,20 +261,20 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { break; } else if (rx_buf[0] == SPI_NACK) { LOGD("SPI: got NACK"); - return -1; + return SpiError::NACK; } // handle timeout - if (millis_since_boot() - start_millis > SPI_ACK_TIMEOUT) { + if (millis_since_boot() - start_millis > timeout) { LOGD("SPI: timed out waiting for ACK"); - return -1; + return SpiError::ACK_TIMEOUT; } } return 0; } -int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { +int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout) { int ret; uint16_t rx_data_len; LockEx lock(spi_fd, hw_lock); @@ -277,9 +306,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx } // Wait for (N)ACK - tx_buf[0] = 0x11; - transfer.len = 1; - ret = wait_for_ack(transfer, SPI_HACK); + ret = wait_for_ack(SPI_HACK, 0x11, timeout); if (ret < 0) { goto transfer_fail; } @@ -297,9 +324,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx } // Wait for (N)ACK - tx_buf[0] = 0x13; - transfer.len = 1; - ret = wait_for_ack(transfer, SPI_DACK); + ret = wait_for_ack(SPI_DACK, 0x13, timeout); if (ret < 0) { goto transfer_fail; } From 9ac73b719fe0c7bb6f3dd23514b2c837a3bd17ae Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 22 May 2023 03:33:38 +0800 Subject: [PATCH 019/283] cabana: reject group separator in QDoubleValidator (#28250) --- tools/cabana/signalview.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index cf72b34ccf..1b67659de5 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -284,8 +284,12 @@ void SignalModel::handleSignalRemoved(const cabana::Signal *sig) { SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { name_validator = new NameValidator(this); + + QLocale locale(QLocale::C); + locale.setNumberOptions(QLocale::RejectGroupSeparator); double_validator = new QDoubleValidator(this); - double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system + double_validator->setLocale(locale); // Match locale of QString::toDouble() instead of system + label_font.setPointSize(8); minmax_font.setPixelSize(10); } From dee611a9bc211eabcc4773574ebc29607bb13a4c Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 21 May 2023 14:35:30 -0500 Subject: [PATCH 020/283] VW MQB: Add FW for 2020 Volkswagen Arteon (#28251) * VW MQB: Add FW for 2020 Volkswagen Arteon * mechanical sort --- selfdrive/car/volkswagen/values.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index db28a62439..5ffd047416 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -292,33 +292,35 @@ FW_QUERY_CONFIG = FwQueryConfig( FW_VERSIONS = { CAR.ARTEON_MK1: { (Ecu.engine, 0x7e0, None): [ - b'\xf1\x873G0906259M \xf1\x890003', b'\xf1\x873G0906259F \xf1\x890004', + b'\xf1\x873G0906259G \xf1\x890004', + b'\xf1\x873G0906259G \xf1\x890005', + b'\xf1\x873G0906259M \xf1\x890003', b'\xf1\x873G0906259N \xf1\x890004', b'\xf1\x873G0906259P \xf1\x890001', b'\xf1\x875NA907115H \xf1\x890002', - b'\xf1\x873G0906259G \xf1\x890004', ], (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x870DL300014C \xf1\x893704', b'\xf1\x8709G927158L \xf1\x893611', + b'\xf1\x870DL300014C \xf1\x893704', b'\xf1\x870GC300011L \xf1\x891401', b'\xf1\x870GC300014M \xf1\x892802', b'\xf1\x870GC300040P \xf1\x891401', ], (Ecu.srs, 0x715, None): [ - b'\xf1\x875QF959655AP\xf1\x890755\xf1\x82\x1311110011111311111100110200--1611125F49', b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1616001613121157161111572900', b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1616001613121177161113772900', - b'\xf1\x873Q0959655DL\xf1\x890732\xf1\x82\0161812141812171105141123052J00', b'\xf1\x873Q0959655CK\xf1\x890711\xf1\x82\x0e1712141712141105121122052900', + b'\xf1\x873Q0959655DA\xf1\x890720\xf1\x82\x0e1712141712141105121122052900', + b'\xf1\x873Q0959655DL\xf1\x890732\xf1\x82\0161812141812171105141123052J00', + b'\xf1\x875QF959655AP\xf1\x890755\xf1\x82\x1311110011111311111100110200--1611125F49', ], (Ecu.eps, 0x712, None): [ - b'\xf1\x875WA907145M \xf1\x891051\xf1\x82\x002NB4202N7N', b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571B41815A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571B00817A1', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567B0020800', b'\xf1\x875WA907145M \xf1\x891051\xf1\x82\x002MB4092M7N', + b'\xf1\x875WA907145M \xf1\x891051\xf1\x82\x002NB4202N7N', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572AA\xf1\x890396', From 36dd49e542968bf13943dcd375424dae6c271b63 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 22 May 2023 03:35:45 +0800 Subject: [PATCH 021/283] cabana: use double for minimum value & maximum value (#28252) --- tools/cabana/dbc/dbc.h | 3 ++- tools/cabana/dbc/dbcfile.cc | 8 ++++---- tools/cabana/signalview.cc | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index c88834876b..d074987f50 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -51,7 +51,8 @@ namespace cabana { bool is_signed; double factor, offset; bool is_little_endian; - QString min, max, unit; + double min, max; + QString unit; QString comment; ValueDescription val_desc; int precision = 0; diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index 49579bc7fa..2b270fc30f 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -217,8 +217,8 @@ void DBCFile::parseExtraInfo(const QString &content) { } if (match.hasMatch()) { if (auto s = get_sig(address, match.captured(1))) { - s->min = match.captured(8 + offset); - s->max = match.captured(9 + offset); + s->min = match.captured(8 + offset).toDouble(); + s->max = match.captured(9 + offset).toDouble(); s->unit = match.captured(10 + offset); } } @@ -258,8 +258,8 @@ QString DBCFile::generateDBC() { .arg(sig->is_signed ? '-' : '+') .arg(doubleToString(sig->factor)) .arg(doubleToString(sig->offset)) - .arg(sig->min) - .arg(sig->max) + .arg(doubleToString(sig->min)) + .arg(doubleToString(sig->max)) .arg(sig->unit); if (!sig->comment.isEmpty()) { signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig->name).arg(sig->comment); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 1b67659de5..45bc740859 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -128,8 +128,8 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { case Item::Factor: return doubleToString(item->sig->factor); case Item::Unit: return item->sig->unit; case Item::Comment: return item->sig->comment; - case Item::Min: return item->sig->min; - case Item::Max: return item->sig->max; + case Item::Min: return doubleToString(item->sig->min); + case Item::Max: return doubleToString(item->sig->max); case Item::Desc: { QStringList val_desc; for (auto &[val, desc] : item->sig->val_desc) { @@ -166,8 +166,8 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r case Item::Factor: s.factor = value.toDouble(); break; case Item::Unit: s.unit = value.toString(); break; case Item::Comment: s.comment = value.toString(); break; - case Item::Min: s.min = value.toString(); break; - case Item::Max: s.max = value.toString(); break; + case Item::Min: s.min = value.toDouble(); break; + case Item::Max: s.max = value.toDouble(); break; case Item::Desc: s.val_desc = value.value(); break; default: return false; } @@ -230,7 +230,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { msg = dbc()->msg(msg_id); } - cabana::Signal sig = {.name = dbc()->newSignalName(msg_id), .is_little_endian = little_endian, .factor = 1, .min = "0", .max = QString::number(std::pow(2, size) - 1)}; + cabana::Signal sig = {.name = dbc()->newSignalName(msg_id), .is_little_endian = little_endian, .factor = 1, .min = 0, .max = std::pow(2, size) - 1}; updateSigSizeParamsFromRange(sig, start_bit, size); UndoStack::push(new AddSigCommand(msg_id, sig)); } From e0a2607eee50abc3571459c9e8ca415844da2dd1 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 21 May 2023 21:28:12 -0500 Subject: [PATCH 022/283] VW MQB: Extend Touran supported model-year range (#28247) VW MQB: Extend Touran model-year range --- docs/CARS.md | 2 +- selfdrive/car/volkswagen/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 9068c6ba30..551bf42ae4 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -259,7 +259,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| |Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| |Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| +|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 5ffd047416..0770b74841 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -227,7 +227,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { VWCarInfo("Volkswagen Tiguan 2018-23"), VWCarInfo("Volkswagen Tiguan eHybrid 2021-23"), ], - CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"), + CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2016-23"), CAR.TRANSPORTER_T61: [ VWCarInfo("Volkswagen Caravelle 2020"), VWCarInfo("Volkswagen California 2021"), From 41771ad7f0bc841326b0a8a77836c6461f5277f2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 21 May 2023 21:20:16 -0700 Subject: [PATCH 023/283] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index c898ec7ce8..4dd2735e38 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c898ec7ce8b7d9a5656b18de810f7b80e8ca15d4 +Subproject commit 4dd2735e38b63940ca1e1f42b4522ca4c1a0a1cc From b977e1a4e95eb276f4827b6bb933ee142a7d8de9 Mon Sep 17 00:00:00 2001 From: Mejty38 <131966105+Mejty38@users.noreply.github.com> Date: Mon, 22 May 2023 07:18:37 +0200 Subject: [PATCH 024/283] Skoda: add fw for Superb 2020 (#28229) * Update values.py * sort and remove duplicate --------- Co-authored-by: Cameron Clough --- selfdrive/car/volkswagen/values.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 0770b74841..e4a57ec23d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1256,9 +1256,10 @@ FW_VERSIONS = { b'\xf1\x870D9300012 \xf1\x894940', b'\xf1\x870D9300013A \xf1\x894905', b'\xf1\x870D9300041H \xf1\x894905', - b'\xf1\x870GC300014M \xf1\x892801', - b'\xf1\x870GC300043 \xf1\x892301', b'\xf1\x870D9300043F \xf1\x895202', + b'\xf1\x870GC300014M \xf1\x892801', + b'\xf1\x870GC300019G \xf1\x892803', + b'\xf1\x870GC300043 \xf1\x892301', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\x12111200111121001121110012211292221111', @@ -1267,6 +1268,7 @@ FW_VERSIONS = { b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02331310031313100313131013141319331413100', b'\xf1\x875Q0959655CA\xf1\x890403\xf1\x82\x1331310031313100313151013141319331423100', b'\xf1\x875Q0959655CH\xf1\x890421\xf1\x82\x1333310031313100313152025350539331463100', + b'\xf1\x875Q0959655CH\xf1\x890421\xf1\x82\x1333310031313100313152855372539331463100', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820514UZ070203', From b2e32a7ef86e6572afc2f7ee4f5bcf4810fb2979 Mon Sep 17 00:00:00 2001 From: eFini Date: Mon, 22 May 2023 15:06:39 +0800 Subject: [PATCH 025/283] pandad: app_path -> app_fn (#28253) * Fix pandad.py Should be `app_fn` instead of `app_path`? * fw path --------- Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/boardd/pandad.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/panda b/panda index 4dd2735e38..2a5058d858 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 4dd2735e38b63940ca1e1f42b4522ca4c1a0a1cc +Subproject commit 2a5058d858b36ff7dc5477119a54f0aab137b266 diff --git a/selfdrive/boardd/pandad.py b/selfdrive/boardd/pandad.py index 50027f340f..859a30a1bc 100755 --- a/selfdrive/boardd/pandad.py +++ b/selfdrive/boardd/pandad.py @@ -7,7 +7,7 @@ import subprocess from typing import List, NoReturn from functools import cmp_to_key -from panda import Panda, PandaDFU +from panda import Panda, PandaDFU, FW_PATH from common.basedir import BASEDIR from common.params import Params from system.hardware import HARDWARE @@ -16,7 +16,8 @@ from system.swaglog import cloudlog def get_expected_signature(panda: Panda) -> bytes: try: - return Panda.get_signature_from_firmware(panda.get_mcu_type().config.app_path) + fn = os.path.join(FW_PATH, panda.get_mcu_type().config.app_fn) + return Panda.get_signature_from_firmware(fn) except Exception: cloudlog.exception("Error computing expected signature") return b"" From 18559f41359913cc546837ff3f25ff25428ca20c Mon Sep 17 00:00:00 2001 From: Comma Device Date: Mon, 22 May 2023 00:45:35 -0700 Subject: [PATCH 026/283] boardd: lower timeout for getting serial --- selfdrive/boardd/spi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 92ec1c4cdc..9ec6303d2c 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -94,7 +94,7 @@ PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { } // get hw UID/serial - ret = control_read(0xc3, 0, 0, uid, uid_len, 1000); + ret = control_read(0xc3, 0, 0, uid, uid_len, 100); if (ret == uid_len) { std::stringstream stream; for (int i = 0; i < uid_len; i++) { From 2664dba52e03b45d7a55f17211eb17abb35598c9 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 May 2023 00:48:51 -0700 Subject: [PATCH 027/283] jenkins: switch order of tests --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9b1ea421ac..e0e8511251 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -153,8 +153,8 @@ pipeline { ["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR EXTRA_FILES='tools/' ./build_devel.sh"], ["build openpilot", "cd selfdrive/manager && ./build.py"], ["check dirty", "release/check-dirty.sh"], - ["time to onroad", "cd selfdrive/test/ && pytest test_time_to_onroad.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], + ["time to onroad", "cd selfdrive/test/ && pytest test_time_to_onroad.py"], ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], ]) } From 1b12f17ee3826b7553b9d907f9d33d58799c4688 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 May 2023 01:10:24 -0700 Subject: [PATCH 028/283] test onroad: add gpsLocationExternal to gps proc list --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 327d8d0ff6..69e1443d9a 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -157,7 +157,7 @@ class TestOnroad(unittest.TestCase): continue # skip gps services for now - if s in ('ubloxGnss', 'ubloxRaw', 'gnssMeasurements'): + if s in ('ubloxGnss', 'ubloxRaw', 'gnssMeasurements', 'gpsLocationExternal'): continue with self.subTest(service=s): From 9f5f8b603cf69b06c4804632268491cf38cfac7e Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 22 May 2023 10:17:33 -0700 Subject: [PATCH 029/283] car docs: list all needed hardware (#28212) * generic car parts * better carparts * add part type * more tests * multiple enums * unit tests * just check isinstance * better name * remove _connector suffix * remove those hyundai lines * remove default arg * Revert "remove default arg" This reverts commit 139650a3b6b94358c3b9b12bb5fbe0a326d7abad. * cleaner code structure * use fingerprint * review * abstrac data class + common * no more dataclass * conflict --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 504 ++++++++++++++--------------- selfdrive/car/CARS_template.md | 8 +- selfdrive/car/chrysler/values.py | 10 +- selfdrive/car/docs_definitions.py | 176 ++++++---- selfdrive/car/ford/values.py | 8 +- selfdrive/car/gm/values.py | 6 +- selfdrive/car/honda/values.py | 6 +- selfdrive/car/hyundai/values.py | 148 ++++----- selfdrive/car/mazda/values.py | 4 +- selfdrive/car/nissan/values.py | 8 +- selfdrive/car/subaru/values.py | 8 +- selfdrive/car/tests/test_docs.py | 9 +- selfdrive/car/toyota/values.py | 4 +- selfdrive/car/volkswagen/values.py | 6 +- 14 files changed, 486 insertions(+), 419 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 551bf42ae4..70ee6edf37 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -6,260 +6,260 @@ A supported vehicle is one that just works when you install a comma three. All s # 252 Supported Cars -|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness Kit
 |Video| +|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
|| -|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
|| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
|| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
|| -|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| +|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| -|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|GV70 (2.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|GV70 (3.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Genesis|GV80 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
|| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai O connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai I connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Tucson Hybrid 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro EV 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ram connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Subaru A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Toyota connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
|| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
[10](#footnotes)|| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| -|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
|| +|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 angled mount
- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 angled mount
- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai J connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|GV70 (2.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|GV70 (3.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai M connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Genesis|GV80 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai M connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai B connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai J connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai Q connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai Q connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai B connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai G connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai O connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai I connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai D connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Tucson Hybrid 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai P connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai P connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai G connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro EV 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai D connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai B connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai G connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Mazda connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Mazda connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan B connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| +|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan A connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| +|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan A connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| +|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan A connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| +|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Ram connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
Buy Here
|| +|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
Buy Here
|| +|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| +|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
diff --git a/selfdrive/car/CARS_template.md b/selfdrive/car/CARS_template.md index d1d18b6e3d..1ab8a11955 100644 --- a/selfdrive/car/CARS_template.md +++ b/selfdrive/car/CARS_template.md @@ -1,10 +1,10 @@ {% set footnote_tag = '[{}](#footnotes)' %} {% set star_icon = '[![star](assets/icon-star-{}.svg)](##)' %} {% set video_icon = '' %} -{# Force harness column wider by using a blank image with max width. #} +{# Force hardware column wider by using a blank image with max width. #} {% set width_tag = '%s
 ' %} -{% set harness_col_name = 'Harness Kit' %} -{% set wide_harness_col_name = width_tag|format(harness_col_name) -%} +{% set hardware_col_name = 'Hardware Needed' %} +{% set wide_hardware_col_name = width_tag|format(hardware_col_name) -%} @@ -14,7 +14,7 @@ A supported vehicle is one that just works when you install a comma three. All s # {{all_car_info | length}} Supported Cars -|{{Column | map(attribute='value') | join('|') | replace(harness_col_name, wide_harness_col_name)}}| +|{{Column | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}| |---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%} {% for car_info in all_car_info %} |{% for column in Column %}{{car_info.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %} diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 17ba59f964..b5ee26cee8 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -5,7 +5,7 @@ from typing import Dict, List, Optional, Union from cereal import car from panda.python import uds from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -60,7 +60,7 @@ RAM_CARS = RAM_DT | RAM_HD @dataclass class ChryslerCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC)" - harness_kit: HarnessKit = HarnessKit(Harness.fca) + car_parts: CarParts = CarParts.common([CarPart.fca]) CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { @@ -74,10 +74,10 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { ], CAR.JEEP_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"), CAR.JEEP_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"), - CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", harness_kit=HarnessKit(Harness.ram)), + CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", car_parts=CarParts.common([CarPart.ram])), CAR.RAM_HD: [ - ChryslerCarInfo("Ram 2500 2020-22", harness_kit=HarnessKit(Harness.ram)), - ChryslerCarInfo("Ram 3500 2019-22", harness_kit=HarnessKit(Harness.ram)), + ChryslerCarInfo("Ram 2500 2020-22", car_parts=CarParts.common([CarPart.ram])), + ChryslerCarInfo("Ram 3500 2019-22", car_parts=CarParts.common([CarPart.ram])), ], } diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index bfb182c5e9..f6c63ef4ca 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -1,6 +1,6 @@ import re +from abc import ABC, abstractmethod from collections import namedtuple -import copy from dataclasses import dataclass, field from enum import Enum from typing import Dict, List, Optional, Tuple, Union @@ -21,7 +21,7 @@ class Column(Enum): FSR_STEERING = "No ALC below" STEERING_TORQUE = "Steering Torque" AUTO_RESUME = "Resume from stop" - HARNESS = "Harness Kit" + HARDWARE = "Hardware Needed" VIDEO = "Video" @@ -31,60 +31,120 @@ class Star(Enum): EMPTY = "empty" -class Harness(Enum): - nidec = "Honda Nidec" - bosch_a = "Honda Bosch A" - bosch_b = "Honda Bosch B" - toyota = "Toyota" - subaru_a = "Subaru A" - subaru_b = "Subaru B" - fca = "FCA" - ram = "Ram" - vw = "VW" - j533 = "J533" - hyundai_a = "Hyundai A" - hyundai_b = "Hyundai B" - hyundai_c = "Hyundai C" - hyundai_d = "Hyundai D" - hyundai_e = "Hyundai E" - hyundai_f = "Hyundai F" - hyundai_g = "Hyundai G" - hyundai_h = "Hyundai H" - hyundai_i = "Hyundai I" - hyundai_j = "Hyundai J" - hyundai_k = "Hyundai K" - hyundai_l = "Hyundai L" - hyundai_m = "Hyundai M" - hyundai_n = "Hyundai N" - hyundai_o = "Hyundai O" - hyundai_p = "Hyundai P" - hyundai_q = "Hyundai Q" - custom = "Developer" - obd_ii = "OBD-II" - gm = "GM" - nissan_a = "Nissan A" - nissan_b = "Nissan B" - mazda = "Mazda" - ford_q3 = "Ford Q3" - ford_q4 = "Ford Q4" - none = "None" +class PartType(Enum): + connector = "Connector" + device = "Device" + cable = "Cable" + accessory = "Accessory" + mount = "Mount" -class HarnessPart(Enum): - harness_box = "harness box" - comma_power_v2 = "comma power v2" - rj45_cable = "RJ45 cable (7 ft)" - long_obdc_cable = "long OBD-C cable" - usbc_coupler = "USB-C coupler" +class Part(ABC): + def __init__(self, name: str): + self.name = name + + @property + @abstractmethod + def type(self) -> PartType: + raise NotImplementedError -DEFAULT_HARNESS_PARTS: List[HarnessPart] = [HarnessPart.harness_box, HarnessPart.comma_power_v2, HarnessPart.rj45_cable] +class Connector(Part): + @property + def type(self) -> PartType: + return PartType.connector + + +class Accessory(Part): + @property + def type(self) -> PartType: + return PartType.accessory + + +class Mount(Part): + @property + def type(self) -> PartType: + return PartType.mount + + +class Cable(Part): + @property + def type(self) -> PartType: + return PartType.cable + + +class Device(Part): + @property + def type(self) -> PartType: + return PartType.device + + +class CarPart(Enum): + nidec = Connector("Honda Nidec connector") + bosch_a = Connector("Honda Bosch A connector") + bosch_b = Connector("Honda Bosch B connector") + toyota = Connector("Toyota connector") + subaru_a = Connector("Subaru A connector") + subaru_b = Connector("Subaru B connector") + fca = Connector("FCA connector") + ram = Connector("Ram connector") + vw = Connector("VW connector") + j533 = Connector("J533 connector") + hyundai_a = Connector("Hyundai A connector") + hyundai_b = Connector("Hyundai B connector") + hyundai_c = Connector("Hyundai C connector") + hyundai_d = Connector("Hyundai D connector") + hyundai_e = Connector("Hyundai E connector") + hyundai_f = Connector("Hyundai F connector") + hyundai_g = Connector("Hyundai G connector") + hyundai_h = Connector("Hyundai H connector") + hyundai_i = Connector("Hyundai I connector") + hyundai_j = Connector("Hyundai J connector") + hyundai_k = Connector("Hyundai K connector") + hyundai_l = Connector("Hyundai L connector") + hyundai_m = Connector("Hyundai M connector") + hyundai_n = Connector("Hyundai N connector") + hyundai_o = Connector("Hyundai O connector") + hyundai_p = Connector("Hyundai P connector") + hyundai_q = Connector("Hyundai Q connector") + custom = Connector("Developer connector") + obd_ii = Connector("OBD-II connector") + gm = Connector("GM connector") + nissan_a = Connector("Nissan A connector") + nissan_b = Connector("Nissan B connector") + mazda = Connector("Mazda connector") + ford_q3 = Connector("Ford Q3 connector") + ford_q4 = Connector("Ford Q4 connector") + + comma_3 = Device("comma 3") + red_panda = Device("red panda") + + harness_box = Accessory("harness box") + comma_power_v2 = Accessory("comma power v2") + + mount = Mount("mount") + angled_mount = Mount("angled mount") + + rj45_cable_7ft = Cable("RJ45 cable (7 ft)") + long_obdc_cable = Cable("long OBD-C cable") + usb_a_2_a_cable = Cable("USB A-A cable") + usbc_otg_cable = Cable("USB C OTG cable") + usbc_coupler = Cable("USB-C coupler") + obd_c_cable_1_5ft = Cable("OBD-C cable (1.5 ft)") + right_angle_obd_c_cable_1_5ft = Cable("right angle OBD-C cable (1.5 ft)") + + +DEFAULT_CAR_PARTS: List[CarPart] = [CarPart.harness_box, CarPart.comma_power_v2, CarPart.rj45_cable_7ft, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft] @dataclass -class HarnessKit: - connector: Harness = Harness.none - parts: List[HarnessPart] = field(default_factory=lambda: copy.copy(DEFAULT_HARNESS_PARTS)) +class CarParts: + parts: List[CarPart] = field(default_factory=list) + + @classmethod + def common(cls, add: List[CarPart] = None, remove: List[CarPart] = None): + p = [part for part in (add or []) + DEFAULT_CAR_PARTS if part not in (remove or [])] + return cls(p) CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only", "shop_footnote"], defaults=(False, False)) @@ -154,8 +214,8 @@ class CarInfo: min_steer_speed: Optional[float] = None min_enable_speed: Optional[float] = None - # harness connectors + all the parts needed - harness_kit: HarnessKit = HarnessKit() + # all the parts needed for the supported car + car_parts: CarParts = CarParts() def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]): self.car_name = CP.carName @@ -184,13 +244,13 @@ class CarInfo: if self.min_enable_speed is None: self.min_enable_speed = CP.minEnableSpeed - # harness column - harness_col = self.harness_kit.connector.value - if self.harness_kit.connector is not Harness.none: + # hardware column + hardware_col = "None" + if self.car_parts.parts: model_years = self.model + (' ' + self.years if self.years else '') - harness_connector = f'- 1 {harness_col} connector' - harness_parts = '
'.join([f"- {self.harness_kit.parts.count(part)} {part.value}" for part in sorted(set(self.harness_kit.parts), key=lambda part: part.value)]) - harness_col = f'
View{harness_connector}
{harness_parts}
' + buy_link = f'Buy Here' + parts = '
'.join([f"- {self.car_parts.parts.count(part)} {part.value.name}" for part in sorted(set(self.car_parts.parts), key=lambda part: part.name)]) + hardware_col = f'
View{parts}
{buy_link}
' self.row: Dict[Enum, Union[str, Star]] = { Column.MAKE: self.make, @@ -201,7 +261,7 @@ class CarInfo: Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.STEERING_TORQUE: Star.EMPTY, Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY, - Column.HARNESS: harness_col, + Column.HARDWARE: hardware_col, Column.VIDEO: self.video_link if self.video_link is not None else "", # replaced with an image and link from template in get_column } diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 6425179a27..41fa8f3475 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -4,7 +4,7 @@ from typing import Dict, List, Set, Union from cereal import car from selfdrive.car import AngleRateLimit, dbc_dict -from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -66,7 +66,11 @@ DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base @dataclass class FordCarInfo(CarInfo): package: str = "Co-Pilot360 Assist+" - harness_kit: HarnessKit = HarnessKit(Harness.ford_q3) + car_parts: CarParts = CarParts.common([CarPart.ford_q3]) + + def init_make(self, CP: car.CarParams): + if CP.carFingerprint in (CAR.BRONCO_SPORT_MK1, CAR.MAVERICK_MK1): + self.car_parts = CarParts.common([CarPart.ford_q3, CarPart.angled_mount], remove=[CarPart.mount]) CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 865ba8ed0f..60c76f135b 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -5,7 +5,7 @@ from typing import Dict, List, Union from cereal import car from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit, HarnessPart +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column Ecu = car.CarParams.Ecu @@ -89,9 +89,9 @@ class GMCarInfo(CarInfo): def init_make(self, CP: car.CarParams): if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera: - self.harness_kit = HarnessKit(Harness.gm) + self.car_parts = CarParts.common([CarPart.gm]) else: - self.harness_kit = HarnessKit(Harness.obd_ii, parts=[HarnessPart.long_obdc_cable, HarnessPart.usbc_coupler]) + self.car_parts = CarParts([CarPart.obd_ii, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft]) self.footnotes.append(Footnote.OBD_II) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 05c6f25432..d19281fce7 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -6,7 +6,7 @@ from cereal import car from common.conversions import Conversions as CV from panda.python import uds from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = car.CarParams.Ecu @@ -110,9 +110,9 @@ class HondaCarInfo(CarInfo): def init_make(self, CP: car.CarParams): if CP.carFingerprint in HONDA_BOSCH: - self.harness_kit = HarnessKit(Harness.bosch_b) if CP.carFingerprint in HONDA_BOSCH_RADARLESS else HarnessKit(Harness.bosch_a) + self.car_parts = CarParts.common([CarPart.bosch_b]) if CP.carFingerprint in HONDA_BOSCH_RADARLESS else CarParts.common([CarPart.bosch_a]) else: - self.harness_kit = HarnessKit(Harness.nidec) + self.car_parts = CarParts.common([CarPart.nidec]) CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index b5d35cc9ea..21c63338f5 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -6,7 +6,7 @@ from cereal import car from panda.python import uds from common.conversions import Conversions as CV from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -147,114 +147,114 @@ class HyundaiCarInfo(CarInfo): CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.ELANTRA: [ - HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness_kit=HarnessKit(Harness.hyundai_b)), - HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness_kit=HarnessKit(Harness.hyundai_e)), - HyundaiCarInfo("Hyundai i30 2017-19", harness_kit=HarnessKit(Harness.hyundai_e)), + HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_b])), + HyundaiCarInfo("Hyundai Elantra GT 2017-19", car_parts=CarParts.common([CarPart.hyundai_e])), + HyundaiCarInfo("Hyundai i30 2017-19", car_parts=CarParts.common([CarPart.hyundai_e])), ], - CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness_kit=HarnessKit(Harness.hyundai_k)), - CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness_kit=HarnessKit(Harness.hyundai_k)), + CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarPart.hyundai_k])), + CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarPart.hyundai_k])), CAR.HYUNDAI_GENESIS: [ - HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness_kit=HarnessKit(Harness.hyundai_j)), # TODO: check 2015 packages - HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, harness_kit=HarnessKit(Harness.hyundai_j)), + HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_j])), # TODO: check 2015 packages + HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_j])), ], - CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness_kit=HarnessKit(Harness.hyundai_c)), - CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness_kit=HarnessKit(Harness.hyundai_h)), # TODO: confirm 2020-21 harness - CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness_kit=HarnessKit(Harness.hyundai_c)), - CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", harness_kit=HarnessKit(Harness.hyundai_h)), - CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", harness_kit=HarnessKit(Harness.hyundai_c)), - CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2020-22", "All", harness_kit=HarnessKit(Harness.hyundai_h)), - CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020", harness_kit=HarnessKit(Harness.hyundai_b)), - CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-21", harness_kit=HarnessKit(Harness.hyundai_g)), - CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", harness_kit=HarnessKit(Harness.hyundai_o)), - CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", harness_kit=HarnessKit(Harness.hyundai_i)), # TODO: check packages - CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", harness_kit=HarnessKit(Harness.hyundai_d)), - CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="https://youtu.be/VnHzSTygTS4", harness_kit=HarnessKit(Harness.hyundai_l)), - CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", harness_kit=HarnessKit(Harness.hyundai_l)), - CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness_kit=HarnessKit(Harness.hyundai_l)), - CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", harness_kit=HarnessKit(Harness.hyundai_a)), - CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness_kit=HarnessKit(Harness.hyundai_e)), + CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", car_parts=CarParts.common([CarPart.hyundai_c])), + CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", car_parts=CarParts.common([CarPart.hyundai_h])), # TODO: confirm 2020-21 harness + CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", car_parts=CarParts.common([CarPart.hyundai_c])), + CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", car_parts=CarParts.common([CarPart.hyundai_h])), + CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", car_parts=CarParts.common([CarPart.hyundai_c])), + CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2020-22", "All", car_parts=CarParts.common([CarPart.hyundai_h])), + CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020", car_parts=CarParts.common([CarPart.hyundai_b])), + CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarPart.hyundai_g])), + CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", car_parts=CarParts.common([CarPart.hyundai_o])), + CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", car_parts=CarParts.common([CarPart.hyundai_i])), # TODO: check packages + CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", car_parts=CarParts.common([CarPart.hyundai_d])), + CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="https://youtu.be/VnHzSTygTS4", car_parts=CarParts.common([CarPart.hyundai_l])), + CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", car_parts=CarParts.common([CarPart.hyundai_l])), + CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarPart.hyundai_l])), + CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarPart.hyundai_e])), CAR.TUCSON: [ - HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness_kit=HarnessKit(Harness.hyundai_l)), - HyundaiCarInfo("Hyundai Tucson Diesel 2019", harness_kit=HarnessKit(Harness.hyundai_l)), + HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_l])), + HyundaiCarInfo("Hyundai Tucson Diesel 2019", car_parts=CarParts.common([CarPart.hyundai_l])), ], CAR.PALISADE: [ - HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", harness_kit=HarnessKit(Harness.hyundai_h)), - HyundaiCarInfo("Kia Telluride 2020-22", "All", harness_kit=HarnessKit(Harness.hyundai_h)), + HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", car_parts=CarParts.common([CarPart.hyundai_h])), + HyundaiCarInfo("Kia Telluride 2020-22", "All", car_parts=CarParts.common([CarPart.hyundai_h])), ], - CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness_kit=HarnessKit(Harness.hyundai_e)), - CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness_kit=HarnessKit(Harness.hyundai_a)), + CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_e])), + CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", car_parts=CarParts.common([CarPart.hyundai_a])), CAR.IONIQ_5: [ - HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", harness_kit=HarnessKit(Harness.hyundai_q)), - HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", harness_kit=HarnessKit(Harness.hyundai_k)), - HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", harness_kit=HarnessKit(Harness.hyundai_q)), + HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_q])), + HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarPart.hyundai_k])), + HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarPart.hyundai_q])), ], CAR.TUCSON_4TH_GEN: [ - HyundaiCarInfo("Hyundai Tucson 2022", harness_kit=HarnessKit(Harness.hyundai_n)), - HyundaiCarInfo("Hyundai Tucson 2023", "All", harness_kit=HarnessKit(Harness.hyundai_n)), + HyundaiCarInfo("Hyundai Tucson 2022", car_parts=CarParts.common([CarPart.hyundai_n])), + HyundaiCarInfo("Hyundai Tucson 2023", "All", car_parts=CarParts.common([CarPart.hyundai_n])), ], - CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-23", "All", harness_kit=HarnessKit(Harness.hyundai_n)), - CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", harness_kit=HarnessKit(Harness.hyundai_n)), + CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_n])), + CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", car_parts=CarParts.common([CarPart.hyundai_n])), # Kia CAR.KIA_FORTE: [ - HyundaiCarInfo("Kia Forte 2019-21", harness_kit=HarnessKit(Harness.hyundai_g)), - HyundaiCarInfo("Kia Forte 2023", harness_kit=HarnessKit(Harness.hyundai_e)), + HyundaiCarInfo("Kia Forte 2019-21", car_parts=CarParts.common([CarPart.hyundai_g])), + HyundaiCarInfo("Kia Forte 2023", car_parts=CarParts.common([CarPart.hyundai_e])), ], - CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", harness_kit=HarnessKit(Harness.hyundai_a)), - CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020", harness_kit=HarnessKit(Harness.hyundai_a)), + CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020", car_parts=CarParts.common([CarPart.hyundai_a])), CAR.KIA_NIRO_EV: [ - HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness_kit=HarnessKit(Harness.hyundai_h)), - HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness_kit=HarnessKit(Harness.hyundai_f)), - HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness_kit=HarnessKit(Harness.hyundai_c)), - HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness_kit=HarnessKit(Harness.hyundai_h)), + HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_h])), + HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_f])), + HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_c])), + HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_h])), ], - CAR.KIA_NIRO_EV_2ND_GEN: HyundaiCarInfo("Kia Niro EV 2023", "All", harness_kit=HarnessKit(Harness.hyundai_a)), + CAR.KIA_NIRO_EV_2ND_GEN: HyundaiCarInfo("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarPart.hyundai_a])), CAR.KIA_NIRO_PHEV: [ - HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness_kit=HarnessKit(Harness.hyundai_c)), - HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", harness_kit=HarnessKit(Harness.hyundai_d)), + HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_c])), + HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", car_parts=CarParts.common([CarPart.hyundai_d])), ], CAR.KIA_NIRO_HEV_2021: [ - HyundaiCarInfo("Kia Niro Hybrid 2021-22", harness_kit=HarnessKit(Harness.hyundai_f)), # TODO: 2021 could be hyundai_d, verify + HyundaiCarInfo("Kia Niro Hybrid 2021-22", car_parts=CarParts.common([CarPart.hyundai_f])), # TODO: 2021 could be hyundai_d, verify ], - CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", harness_kit=HarnessKit(Harness.hyundai_a)), - CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", harness_kit=HarnessKit(Harness.hyundai_b)), # TODO: may support 2016, 2018 - CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", harness_kit=HarnessKit(Harness.hyundai_g)), + CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarPart.hyundai_b])), # TODO: may support 2016, 2018 + CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarPart.hyundai_g])), CAR.KIA_OPTIMA_H: [ HyundaiCarInfo("Kia Optima Hybrid 2017", "Advanced Smart Cruise Control"), # TODO: may support adjacent years HyundaiCarInfo("Kia Optima Hybrid 2019"), ], - CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", harness_kit=HarnessKit(Harness.hyundai_a)), - CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", harness_kit=HarnessKit(Harness.hyundai_n)), + CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", car_parts=CarParts.common([CarPart.hyundai_n])), CAR.KIA_SORENTO: [ - HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness_kit=HarnessKit(Harness.hyundai_c)), - HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness_kit=HarnessKit(Harness.hyundai_e)), + HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarPart.hyundai_c])), + HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarPart.hyundai_e])), ], - CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", harness_kit=HarnessKit(Harness.hyundai_k)), - CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", harness_kit=HarnessKit(Harness.hyundai_a)), - CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness_kit=HarnessKit(Harness.hyundai_n)), - CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness_kit=HarnessKit(Harness.hyundai_c)), - CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness_kit=HarnessKit(Harness.hyundai_k)), - CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness_kit=HarnessKit(Harness.hyundai_e)), + CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", car_parts=CarParts.common([CarPart.hyundai_k])), + CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", car_parts=CarParts.common([CarPart.hyundai_n])), + CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", car_parts=CarParts.common([CarPart.hyundai_c])), + CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", car_parts=CarParts.common([CarPart.hyundai_k])), + CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", car_parts=CarParts.common([CarPart.hyundai_e])), CAR.KIA_EV6: [ - HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", harness_kit=HarnessKit(Harness.hyundai_p)), - HyundaiCarInfo("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", harness_kit=HarnessKit(Harness.hyundai_l)), - HyundaiCarInfo("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", harness_kit=HarnessKit(Harness.hyundai_p)) + HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_p])), + HyundaiCarInfo("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarPart.hyundai_l])), + HyundaiCarInfo("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarPart.hyundai_p])) ], # Genesis CAR.GENESIS_GV60_EV_1ST_GEN: [ - HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", harness_kit=HarnessKit(Harness.hyundai_a)), - HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", harness_kit=HarnessKit(Harness.hyundai_k)), + HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", car_parts=CarParts.common([CarPart.hyundai_a])), + HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", car_parts=CarParts.common([CarPart.hyundai_k])), ], - CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness_kit=HarnessKit(Harness.hyundai_f)), - CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness_kit=HarnessKit(Harness.hyundai_f)), + CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", car_parts=CarParts.common([CarPart.hyundai_f])), + CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", car_parts=CarParts.common([CarPart.hyundai_f])), CAR.GENESIS_GV70_1ST_GEN: [ - HyundaiCarInfo("Genesis GV70 (2.5T Trim) 2022-23", "All", harness_kit=HarnessKit(Harness.hyundai_l)), - HyundaiCarInfo("Genesis GV70 (3.5T Trim) 2022-23", "All", harness_kit=HarnessKit(Harness.hyundai_m)), + HyundaiCarInfo("Genesis GV70 (2.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_l])), + HyundaiCarInfo("Genesis GV70 (3.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_m])), ], - CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", harness_kit=HarnessKit(Harness.hyundai_h)), - CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness_kit=HarnessKit(Harness.hyundai_c)), - CAR.GENESIS_GV80: HyundaiCarInfo("Genesis GV80 2023", "All", harness_kit=HarnessKit(Harness.hyundai_m)), + CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarPart.hyundai_h])), + CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", car_parts=CarParts.common([CarPart.hyundai_c])), + CAR.GENESIS_GV80: HyundaiCarInfo("Genesis GV80 2023", "All", car_parts=CarParts.common([CarPart.hyundai_m])), } class Buttons: diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 79f07a1fde..864462186e 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -3,7 +3,7 @@ from typing import Dict, List, Union from cereal import car from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -37,7 +37,7 @@ class CAR: @dataclass class MazdaCarInfo(CarInfo): package: str = "All" - harness_kit: HarnessKit = HarnessKit(Harness.mazda) + car_parts: CarParts = CarParts.common([CarPart.mazda]) CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = { diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index cbe62645d5..1669151025 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -4,7 +4,7 @@ from typing import Dict, List, Optional, Union from cereal import car from panda.python import uds from selfdrive.car import AngleRateLimit, dbc_dict -from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit, HarnessPart +from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -30,13 +30,13 @@ class CAR: ALTIMA = "NISSAN ALTIMA 2020" -NISSAN_HARNESS_PARTS = [HarnessPart.harness_box, HarnessPart.rj45_cable, HarnessPart.long_obdc_cable, HarnessPart.usbc_coupler] +NISSAN_PARTS: List[CarPart] = [CarPart.harness_box, CarPart.rj45_cable_7ft, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft] @dataclass class NissanCarInfo(CarInfo): package: str = "ProPILOT Assist" - harness_kit: HarnessKit = HarnessKit(Harness.nissan_a, parts=NISSAN_HARNESS_PARTS) + car_parts: CarParts = CarParts([CarPart.nissan_a] + NISSAN_PARTS) CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = { @@ -44,7 +44,7 @@ CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = { CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-23", video_link="https://youtu.be/vaMbtAh_0cY"), CAR.LEAF_IC: None, # same platforms CAR.ROGUE: NissanCarInfo("Nissan Rogue 2018-20"), - CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", harness_kit=HarnessKit(Harness.nissan_b, parts=NISSAN_HARNESS_PARTS)), + CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", car_parts=CarParts([CarPart.nissan_b] + NISSAN_PARTS)), } FINGERPRINTS = { diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 1977b43f95..660bdcaaab 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -5,7 +5,7 @@ from typing import Dict, List, Union from cereal import car from panda.python import uds from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = car.CarParams.Ecu @@ -53,13 +53,13 @@ class CAR: @dataclass class SubaruCarInfo(CarInfo): package: str = "EyeSight Driver Assistance" - harness_kit: HarnessKit = HarnessKit(Harness.subaru_a) + car_parts: CarParts = CarParts.common([CarPart.subaru_a]) CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = { CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-21", "All"), - CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All", harness_kit=HarnessKit(Harness.subaru_b)), - CAR.LEGACY: SubaruCarInfo("Subaru Legacy 2020-22", "All", harness_kit=HarnessKit(Harness.subaru_b)), + CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All", car_parts=CarParts.common([CarPart.subaru_b])), + CAR.LEGACY: SubaruCarInfo("Subaru Legacy 2020-22", "All", car_parts=CarParts.common([CarPart.subaru_b])), CAR.IMPREZA: [ SubaruCarInfo("Subaru Impreza 2017-19"), SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"), diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py index e36bdc5ded..4b53489b73 100755 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -5,7 +5,7 @@ import unittest from selfdrive.car.car_helpers import interfaces, get_interface_attr from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info -from selfdrive.car.docs_definitions import Column, Harness, Star +from selfdrive.car.docs_definitions import CarPart, Column, PartType, Star from selfdrive.car.honda.values import CAR as HONDA @@ -74,8 +74,11 @@ class TestCarDocs(unittest.TestCase): if car.name == "comma body": raise unittest.SkipTest - self.assertNotIn(car.harness_kit.connector, [None, Harness.none], f"Need to specify car harness: {car.name}") - self.assertTrue(car.harness_kit.parts, f"Need to specify harness parts: {car.name} with {car.harness_kit.connector.value} connector") + car_part_type = [p.value.type for p in car.car_parts.parts] + self.assertTrue(len(car.car_parts.parts) > 0, f"Need to specify car parts: {car.name}") + self.assertTrue(car_part_type.count(PartType.connector) == 1, f"Need to specify one harness connector: {car.name}") + self.assertTrue(car_part_type.count(PartType.mount) == 1, f"Need to specify one mount: {car.name}") + self.assertTrue(CarPart.right_angle_obd_c_cable_1_5ft in car.car_parts.parts, f"Need to specify a right angle OBD-C cable (1.5ft): {car.name}") if __name__ == "__main__": diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 00552485a8..5738ba30f5 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -6,7 +6,7 @@ from typing import Dict, List, Union from cereal import car from common.conversions import Conversions as CV from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, CarPart, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -102,7 +102,7 @@ class Footnote(Enum): @dataclass class ToyotaCarInfo(CarInfo): package: str = "All" - harness_kit: HarnessKit = HarnessKit(Harness.toyota) + car_parts: CarParts = CarParts.common([CarPart.toyota]) CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index e4a57ec23d..228765a4dc 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -7,7 +7,7 @@ from cereal import car from panda.python import uds from opendbc.can.can_define import CANDefine from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit, HarnessPart +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -160,13 +160,13 @@ class Footnote(Enum): VW_MQB_A0 = CarFootnote( "Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot " + "in software, but doesn't yet have a harness available from the comma store.", - Column.HARNESS) + Column.HARDWARE) @dataclass class VWCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC) & Lane Assist" - harness_kit: HarnessKit = HarnessKit(Harness.j533, parts=[HarnessPart.harness_box, HarnessPart.long_obdc_cable, HarnessPart.usbc_coupler]) + car_parts: CarParts = CarParts([CarPart.j533, CarPart.harness_box, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft]) def init_make(self, CP: car.CarParams): self.footnotes.insert(0, Footnote.VW_EXP_LONG) From a3d59132283f97faadf0be2ca55264b895e4c232 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 May 2023 10:48:15 -0700 Subject: [PATCH 030/283] adjust uploader cpu usage --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 69e1443d9a..efe15266c6 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -54,7 +54,7 @@ PROCS = { "selfdrive.boardd.pandad": 0, "selfdrive.statsd": 0.4, "selfdrive.navd.navd": 0.4, - "system.loggerd.uploader": 4.0, + "system.loggerd.uploader": 3.0, "system.loggerd.deleter": 0.1, "selfdrive.locationd.laikad": None, # TODO: laikad cpu usage is sporadic } From 328b5d9d47ef24140b316c375665e1cfd00cef31 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Mon, 22 May 2023 15:11:04 -0700 Subject: [PATCH 031/283] Nicki Minaj Model (#28218) * New model: 2ff7490f-8a2f-4c0d-87a8-b0fa3a4a6a71 * Updated model_replay_ref_commit --- selfdrive/modeld/models/driving.h | 11 ++++++----- selfdrive/modeld/models/supercombo.onnx | 4 ++-- selfdrive/modeld/runners/thneedmodel.cc | 15 +++++++-------- .../test/process_replay/model_replay_ref_commit | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index 5734c68cb9..2b0902d5cf 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -1,10 +1,5 @@ #pragma once -// gate this here -#define TEMPORAL -#define DESIRE -#define TRAFFIC_CONVENTION - #include #include @@ -17,6 +12,12 @@ #include "selfdrive/modeld/models/nav.h" #include "selfdrive/modeld/runners/run.h" +// gate this here +#define TEMPORAL +#define DESIRE +#define TRAFFIC_CONVENTION +#define NAV + constexpr int FEATURE_LEN = 128; constexpr int HISTORY_BUFFER_LEN = 99; constexpr int DESIRE_LEN = 8; diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index d8a8b5ef13..493f3285d6 100644 --- a/selfdrive/modeld/models/supercombo.onnx +++ b/selfdrive/modeld/models/supercombo.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0007958c9bad4a87eb5c28080b5bfdc24834958fbcbaff448674fa570b0196da -size 46011200 +oid sha256:b8bf95f096b19cef1e473fb4f0caf5f727b74bbde23a642aa586036ad9824e55 +size 46076782 diff --git a/selfdrive/modeld/runners/thneedmodel.cc b/selfdrive/modeld/runners/thneedmodel.cc index 4fdd7ca466..2ac3d64495 100644 --- a/selfdrive/modeld/runners/thneedmodel.cc +++ b/selfdrive/modeld/runners/thneedmodel.cc @@ -41,13 +41,13 @@ void ThneedModel::addExtra(float *extra_input_buf, int buf_size) { } void* ThneedModel::getInputBuf() { - if (use_extra && thneed->input_clmem.size() > 4) return &(thneed->input_clmem[4]); - else if (!use_extra && thneed->input_clmem.size() > 3) return &(thneed->input_clmem[3]); + if (use_extra && thneed->input_clmem.size() > 5) return &(thneed->input_clmem[5]); + else if (!use_extra && thneed->input_clmem.size() > 4) return &(thneed->input_clmem[4]); else return nullptr; } void* ThneedModel::getExtraBuf() { - if (thneed->input_clmem.size() > 3) return &(thneed->input_clmem[3]); + if (thneed->input_clmem.size() > 4) return &(thneed->input_clmem[4]); else return nullptr; } @@ -55,10 +55,10 @@ void ThneedModel::execute() { if (!recorded) { thneed->record = true; if (use_extra) { - float *inputs[5] = {recurrent, trafficConvention, desire, extra, input}; + float *inputs[6] = {recurrent, navFeatures, trafficConvention, desire, extra, input}; thneed->copy_inputs(inputs); } else { - float *inputs[4] = {recurrent, trafficConvention, desire, input}; + float *inputs[5] = {recurrent, navFeatures, trafficConvention, desire, input}; thneed->copy_inputs(inputs); } thneed->clexec(); @@ -68,12 +68,11 @@ void ThneedModel::execute() { recorded = true; } else { if (use_extra) { - float *inputs[5] = {recurrent, trafficConvention, desire, extra, input}; + float *inputs[6] = {recurrent, navFeatures, trafficConvention, desire, extra, input}; thneed->execute(inputs, output); } else { - float *inputs[4] = {recurrent, trafficConvention, desire, input}; + float *inputs[5] = {recurrent, navFeatures, trafficConvention, desire, input}; thneed->execute(inputs, output); } } } - diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index b3cc50e559..448c7b4291 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -9d3cd2e7d5fceaaf0e8a4bd798a24fcf470da7c2 +e3cf1856830902bede2d1c9ca3d0d60e5504ae20 From 577c17bcb8df8f825d06616621da7bce510bfe6b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 May 2023 15:19:23 -0700 Subject: [PATCH 032/283] add new driving model to release notes --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index b2e7be396a..547add8a80 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,6 @@ Version 0.9.3 (2023-06-XX) ======================== +* New driving model Version 0.9.2 (2023-05-22) ======================== From 4751d2b57c986599c45280e45867e778cb8bc9d4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 May 2023 16:53:07 -0700 Subject: [PATCH 033/283] tici: log disk info (#28259) --- system/hardware/tici/hardware.h | 1 + 1 file changed, 1 insertion(+) diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index fba67d96c8..580dc83eec 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -77,6 +77,7 @@ public: static std::map get_init_logs() { std::map ret = { {"/BUILD", util::read_file("/BUILD")}, + {"lsblk", util::check_output("lsblk -o NAME,SIZE,STATE,VENDOR,MODEL,REV,SERIAL")}, }; std::string bs = util::check_output("abctl --boot_slot"); From d433dc693d866fe20786baabe23db63b21eb8bf0 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 22 May 2023 18:43:57 -0700 Subject: [PATCH 034/283] car docs: pass all car parts + types to template (#28260) add car parts + types to template --- selfdrive/car/docs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 74fd4616fd..80554cd894 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -10,7 +10,7 @@ from typing import Dict, List from cereal import car from common.basedir import BASEDIR from selfdrive.car import gen_empty_fingerprint -from selfdrive.car.docs_definitions import CarInfo, Column, CommonFootnote +from selfdrive.car.docs_definitions import CarInfo, CarPart, Column, CommonFootnote, PartType from selfdrive.car.car_helpers import interfaces, get_interface_attr @@ -61,7 +61,8 @@ def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str: template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) footnotes = [fn.value.text for fn in get_all_footnotes()] - cars_md: str = template.render(all_car_info=all_car_info, group_by_make=group_by_make, + cars_md: str = template.render(all_car_info=all_car_info, car_parts=CarPart, + part_types=PartType, group_by_make=group_by_make, footnotes=footnotes, Column=Column) return cars_md From ea1e0a16ddaf0a2f6a253724bd695a04d30af1cc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 May 2023 18:50:03 -0700 Subject: [PATCH 035/283] boardd: set min spi timeout --- selfdrive/boardd/spi.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 9ec6303d2c..fe237d5f27 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -35,7 +35,7 @@ struct __attribute__((packed)) spi_header { uint16_t max_rx_len; }; -const int SPI_ACK_TIMEOUT = 500; // milliseconds +const unsigned int SPI_ACK_TIMEOUT = 500; // milliseconds const std::string SPI_DEVICE = "/dev/spidev0.0"; class LockEx { @@ -238,9 +238,10 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1 int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout) { double start_millis = millis_since_boot(); - if (timeout <= 0) { + if (timeout == 0) { timeout = SPI_ACK_TIMEOUT; } + timeout = std::clamp(timeout, 100U, SPI_ACK_TIMEOUT); spi_ioc_transfer transfer = { .tx_buf = (uint64_t)tx_buf, From 715d7f9e3d4d6b3a667fbde1914ca149d147e74b Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 22 May 2023 19:30:04 -0700 Subject: [PATCH 036/283] car docs: keep similar naming (#28262) better name --- selfdrive/car/docs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 80554cd894..afeb457544 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -61,8 +61,8 @@ def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str: template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) footnotes = [fn.value.text for fn in get_all_footnotes()] - cars_md: str = template.render(all_car_info=all_car_info, car_parts=CarPart, - part_types=PartType, group_by_make=group_by_make, + cars_md: str = template.render(all_car_info=all_car_info, CarPart=CarPart, + PartType=PartType, group_by_make=group_by_make, footnotes=footnotes, Column=Column) return cars_md From eee8a7a4b45150981b9d313fb5546bd2cf7ebcc1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 23 May 2023 00:36:42 -0700 Subject: [PATCH 037/283] car docs: fix diff bot (#28266) * test bot * fix docs bot * revert * use dataclass * sad this doesn't work --- selfdrive/car/docs_definitions.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index f6c63ef4ca..89e7a2db0a 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -1,5 +1,4 @@ import re -from abc import ABC, abstractmethod from collections import namedtuple from dataclasses import dataclass, field from enum import Enum @@ -39,12 +38,11 @@ class PartType(Enum): mount = "Mount" -class Part(ABC): - def __init__(self, name: str): - self.name = name +@dataclass +class Part: + name: str @property - @abstractmethod def type(self) -> PartType: raise NotImplementedError From 3785e161f0ac1b05a0b2fae00bf3245eec9db560 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 23 May 2023 01:40:23 -0700 Subject: [PATCH 038/283] car docs: allow auto_resume override (#28264) * specify auto_resume * format * car compat --------- Co-authored-by: Shane Smiskol --- selfdrive/car/docs_definitions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 89e7a2db0a..619d32e8eb 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -211,6 +211,7 @@ class CarInfo: footnotes: List[Enum] = field(default_factory=list) min_steer_speed: Optional[float] = None min_enable_speed: Optional[float] = None + auto_resume: Optional[bool] = None # all the parts needed for the supported car car_parts: CarParts = CarParts() @@ -242,6 +243,9 @@ class CarInfo: if self.min_enable_speed is None: self.min_enable_speed = CP.minEnableSpeed + if self.auto_resume is None: + self.auto_resume = CP.autoResumeSng + # hardware column hardware_col = "None" if self.car_parts.parts: @@ -258,7 +262,7 @@ class CarInfo: Column.FSR_LONGITUDINAL: f"{max(self.min_enable_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.STEERING_TORQUE: Star.EMPTY, - Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY, + Column.AUTO_RESUME: Star.FULL if self.auto_resume else Star.EMPTY, Column.HARDWARE: hardware_col, Column.VIDEO: self.video_link if self.video_link is not None else "", # replaced with an image and link from template in get_column } @@ -290,7 +294,7 @@ class CarInfo: acc = "" if self.min_enable_speed > 0: acc = f" while driving above {self.min_enable_speed * CV.MS_TO_MPH:.0f} mph" - elif CP.autoResumeSng: + elif self.auto_resume: acc = " that automatically resumes from a stop" if self.row[Column.STEERING_TORQUE] != Star.FULL: From b43a875ba26685d7aa4eab3972c580810d5108d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Tue, 23 May 2023 19:02:22 +0200 Subject: [PATCH 039/283] params: specify path using PARAMS_ROOT (#28257) * Add PARAMS_ROOT env var * Change getenv type signature * Use getenv default_val --- common/util.cc | 2 +- common/util.h | 2 +- system/hardware/hw.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/util.cc b/common/util.cc index ee1080cbdf..a527adcbef 100644 --- a/common/util.cc +++ b/common/util.cc @@ -189,7 +189,7 @@ bool create_directories(const std::string& dir, mode_t mode) { return createDirectory(dir, mode); } -std::string getenv(const char* key, const char* default_val) { +std::string getenv(const char* key, std::string default_val) { const char* val = ::getenv(key); return val ? val : default_val; } diff --git a/common/util.h b/common/util.h index c80dc234f2..34721700e7 100644 --- a/common/util.h +++ b/common/util.h @@ -70,7 +70,7 @@ std::string string_format(const std::string& format, Args... args) { return std::string(buf.get(), buf.get() + size - 1); } -std::string getenv(const char* key, const char* default_val = ""); +std::string getenv(const char* key, std::string default_val = ""); int getenv(const char* key, int default_val); float getenv(const char* key, float default_val); diff --git a/system/hardware/hw.h b/system/hardware/hw.h index 5599e79186..3b0583a10b 100644 --- a/system/hardware/hw.h +++ b/system/hardware/hw.h @@ -19,7 +19,7 @@ inline std::string log_root() { return Hardware::PC() ? util::getenv("HOME") + "/.comma/media/0/realdata" : "/data/media/0/realdata"; } inline std::string params() { - return Hardware::PC() ? util::getenv("HOME") + "/.comma/params" : "/data/params"; + return Hardware::PC() ? util::getenv("PARAMS_ROOT", util::getenv("HOME") + "/.comma/params") : "/data/params"; } inline std::string rsa_file() { return Hardware::PC() ? util::getenv("HOME") + "/.comma/persist/comma/id_rsa" : "/persist/comma/id_rsa"; From bf8e6d0d290e04a2f11f4a71ba6a802691eb5a86 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 May 2023 11:09:40 -0700 Subject: [PATCH 040/283] pre-commit: autoupdate hooks (#28271) Update pre-commit hook versions Co-authored-by: adeebshihadeh --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0b021adfe4..5e5c468f41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -80,6 +80,6 @@ repos: language: script pass_filenames: false - repo: https://github.com/python-poetry/poetry - rev: '1.4.0' + rev: '1.5.0' hooks: - id: poetry-check From 12b3ffcc49c819bf01ee9c6cadf500d3411aacda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Tue, 23 May 2023 21:59:09 +0200 Subject: [PATCH 041/283] process_replay: drain sockets instead recv_one (#28161) * Drain the sockets until the next cycle in python process replay * Add waiting mechanism to native process replay, which mimics the syncing * Sort logs when comparing them. Drain all the sockets instead of only recv_socks. * Reverse the retrieval order of FakeSocket * Change pub order for torqued * Update ref commit --- selfdrive/test/process_replay/compare_logs.py | 1 - .../test/process_replay/process_replay.py | 121 ++++++++++-------- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 69 insertions(+), 55 deletions(-) diff --git a/selfdrive/test/process_replay/compare_logs.py b/selfdrive/test/process_replay/compare_logs.py index 821429a70f..48752d2222 100755 --- a/selfdrive/test/process_replay/compare_logs.py +++ b/selfdrive/test/process_replay/compare_logs.py @@ -83,7 +83,6 @@ def compare_logs(log1, log2, ignore_fields=None, ignore_msgs=None, tolerance=Non diff = [] for msg1, msg2 in zip(log1, log2): if msg1.which() != msg2.which(): - print(msg1.which(), msg2.which()) raise Exception("msgs not aligned between logs") msg1 = remove_ignored_fields(msg1, ignore_fields) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 4ab2d30315..65415b4151 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -5,6 +5,7 @@ import sys import threading import time import signal +from collections import defaultdict from dataclasses import dataclass, field from typing import Dict, List, Optional, Callable @@ -43,6 +44,8 @@ class ProcessConfig: subtest_name: str = "" field_tolerances: Dict[str, float] = field(default_factory=dict) timeout: int = 30 + iter_wait_time: float = 0.0 + drain_sockets: bool = False def wait_for_event(evt): @@ -70,7 +73,7 @@ class FakeSocket: self.recv_called.set() wait_for_event(self.recv_ready) self.recv_ready.clear() - return self.data.pop() + return self.data.pop(0) def send(self, data): if self.wait: @@ -137,35 +140,24 @@ class FakeSubMaster(messaging.SubMaster): class FakePubMaster(messaging.PubMaster): def __init__(self, services): # pylint: disable=super-init-not-called - self.data = {} + self.data = defaultdict(list) self.sock = {} self.last_updated = None for s in services: - try: - data = messaging.new_message(s) - except capnp.lib.capnp.KjException: - data = messaging.new_message(s, 0) - self.data[s] = data.as_reader() self.sock[s] = DumbSocket() - self.send_called = threading.Event() - self.get_called = threading.Event() def send(self, s, dat): self.last_updated = s if isinstance(dat, bytes): - self.data[s] = log.Event.from_bytes(dat) + self.data[s].append(log.Event.from_bytes(dat)) else: - self.data[s] = dat.as_reader() - self.send_called.set() - wait_for_event(self.get_called) - self.get_called.clear() + self.data[s].append(dat.as_reader()) - def wait_for_msg(self): - wait_for_event(self.send_called) - self.send_called.clear() - dat = self.data[self.last_updated] - self.get_called.set() - return dat + def drain(self, s): + msgs = self.data[s] + self.data[s] = [] + + return msgs def fingerprint(msgs, fsm, can_sock, fingerprint): @@ -252,14 +244,12 @@ def torqued_rcv_callback(msg, CP, cfg, fsm): return recv_socks, fsm.frame == 0 or msg.which() == 'liveLocationKalman' -def ublox_rcv_callback(msg, CP, cfg, fsm): - msg_class, msg_id = msg.ubloxRaw[2:4] - if (msg_class, msg_id) in {(1, 7 * 16)}: - return ["gpsLocationExternal"], True - elif (msg_class, msg_id) in {(2, 1 * 16 + 5), (10, 9)}: - return ["ubloxGnss"], True - else: - return [], False +def locationd_rcv_callback(msg, CP, cfg, fsm): + trigger_msg = "accelerometer" if CP is not None and CP.notCar else "cameraOdometry" + if msg.which() == trigger_msg: + return ["liveLocationKalman"], True + + return [], False CONFIGS = [ @@ -286,7 +276,7 @@ CONFIGS = [ proc_name="radard", pub_sub={ "can": ["radarState", "liveTracks"], - "liveParameters": [], "carState": [], "modelV2": [], + "carState": [], "modelV2": [], }, ignore=["logMonoTime", "valid", "radarState.cumLagMs"], init_callback=get_car_params, @@ -309,8 +299,8 @@ CONFIGS = [ ProcessConfig( proc_name="calibrationd", pub_sub={ - "carState": ["liveCalibration"], - "cameraOdometry": [], + "carState": [], + "cameraOdometry": ["liveCalibration"], "carParams": [], }, ignore=["logMonoTime", "valid"], @@ -335,12 +325,13 @@ CONFIGS = [ proc_name="locationd", pub_sub={ "cameraOdometry": ["liveLocationKalman"], - "accelerometer": [], "gyroscope": [], - "gpsLocationExternal": [], "liveCalibration": [], "carState": [], "gpsLocation": [], + "accelerometer": ["liveLocationKalman"], "gyroscope": [], + "gpsLocationExternal": [], "liveCalibration": [], + "carParams": [], "carState": [], "gpsLocation": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, - should_recv_callback=None, + should_recv_callback=locationd_rcv_callback, tolerance=NUMPY_TOLERANCE, fake_pubsubmaster=False, ), @@ -363,9 +354,11 @@ CONFIGS = [ }, ignore=["logMonoTime"], init_callback=None, - should_recv_callback=ublox_rcv_callback, + should_recv_callback=None, tolerance=None, fake_pubsubmaster=False, + iter_wait_time=0.01, + drain_sockets=True ), ProcessConfig( proc_name="laikad", @@ -383,8 +376,8 @@ CONFIGS = [ ProcessConfig( proc_name="torqued", pub_sub={ + "carControl": [], "carState": [], "liveLocationKalman": ["liveTorqueParameters"], - "carState": [], "controlsState": [], }, ignore=["logMonoTime"], init_callback=get_car_params, @@ -463,6 +456,7 @@ def python_replay_process(cfg, lr, fingerprint=None): fsm = FakeSubMaster(pub_sockets, **cfg.submaster_config) fpm = FakePubMaster(sub_sockets) + can_sock = None args = (fsm, fpm) if 'can' in list(cfg.pub_sub.keys()): can_sock = FakeSocket() @@ -514,12 +508,13 @@ def python_replay_process(cfg, lr, fingerprint=None): log_msgs, msg_queue = [], [] for msg in pub_msgs: + recv_socks = cfg.pub_sub[msg.which()] if cfg.should_recv_callback is not None: - recv_socks, should_recv = cfg.should_recv_callback(msg, CP, cfg, fsm) + _, should_recv = cfg.should_recv_callback(msg, CP, cfg, fsm) else: - recv_socks = [s for s in cfg.pub_sub[msg.which()] if - (fsm.frame + 1) % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0] - should_recv = bool(len(recv_socks)) + socks = [s for s in cfg.pub_sub[msg.which()] if + (fsm.frame + 1) % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0] + should_recv = bool(len(socks)) if msg.which() == 'can': can_sock.send(msg.as_builder().to_bytes()) @@ -530,14 +525,18 @@ def python_replay_process(cfg, lr, fingerprint=None): fsm.update_msgs(msg.logMonoTime / 1e9, msg_queue) msg_queue = [] - recv_cnt = len(recv_socks) - while recv_cnt > 0: - m = fpm.wait_for_msg().as_builder() - m.logMonoTime = msg.logMonoTime - m = m.as_reader() + if can_sock is not None: + can_sock.recv_called.wait() + else: + fsm.update_called.wait() + + for s in recv_socks: + ms = fpm.drain(s) + for m in ms: + m = m.as_builder() + m.logMonoTime = msg.logMonoTime + log_msgs.append(m.as_reader()) - log_msgs.append(m) - recv_cnt -= m.which() in recv_socks return log_msgs @@ -550,7 +549,8 @@ def replay_process_with_sockets(cfg, lr, fingerprint=None): pub_msgs = [msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())] # We need to fake SubMaster alive since we can't inject a fake clock - setup_env(simulation=True, cfg=cfg, lr=lr) + CP = [m for m in lr if m.which() == 'carParams'][0].carParams + setup_env(simulation=True, CP=CP, cfg=cfg, lr=lr) if cfg.proc_name == "laikad": ublox = Params().get_bool("UbloxAvailable") @@ -560,6 +560,10 @@ def replay_process_with_sockets(cfg, lr, fingerprint=None): managed_processes[cfg.proc_name].prepare() managed_processes[cfg.proc_name].start() + if cfg.init_callback is not None: + cfg.init_callback(all_msgs, None, None, fingerprint) + CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) + log_msgs = [] try: # Wait for process to startup @@ -572,11 +576,15 @@ def replay_process_with_sockets(cfg, lr, fingerprint=None): # Do the replay cnt = 0 + curr_CP = None for msg in pub_msgs: with Timeout(cfg.timeout, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): + if msg.which() == 'carParams': + curr_CP = msg.carParams + resp_sockets = cfg.pub_sub[msg.which()] if cfg.should_recv_callback is not None: - resp_sockets, _ = cfg.should_recv_callback(msg, None, None, None) + resp_sockets, _ = cfg.should_recv_callback(msg, curr_CP, cfg, None) # Make sure all subscribers are connected if len(log_msgs) == 0 and len(resp_sockets) > 0: @@ -587,11 +595,18 @@ def replay_process_with_sockets(cfg, lr, fingerprint=None): while not pm.all_readers_updated(msg.which()): time.sleep(0) + time.sleep(cfg.iter_wait_time) + for s in resp_sockets: - m = messaging.recv_one_retry(sockets[s]) - m = m.as_builder() - m.logMonoTime = msg.logMonoTime - log_msgs.append(m.as_reader()) + msgs = [] + if cfg.drain_sockets: + msgs.extend(messaging.drain_sock(sockets[s], wait_for_one=True)) + else: + msgs = [messaging.recv_one_retry(sockets[s])] + for m in msgs: + m = m.as_builder() + m.logMonoTime = msg.logMonoTime + log_msgs.append(m.as_reader()) cnt += 1 finally: managed_processes[cfg.proc_name].signal(signal.SIGKILL) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 310d6300d2..bff328d31c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c67a0959201829ef07a7d68d5fb59603b3983587 +89ead2916988a97a938f5e2e10855c37fcbf5d65 From 84886e28df5e39cae331ed60afa437b60a572b8c Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 23 May 2023 16:07:21 -0500 Subject: [PATCH 042/283] VW MQB: Start documenting FtS cars (#28268) * specify auto_resume * format * car compat * VW MQB: Start documenting FtS cars * retry CI --------- Co-authored-by: Maxime Desroches --- docs/CARS.md | 6 +++--- selfdrive/car/volkswagen/values.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 70ee6edf37..26e0f8e960 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -236,11 +236,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 228765a4dc..e64135d086 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -195,11 +195,11 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { ], CAR.GOLF_MK7: [ VWCarInfo("Volkswagen e-Golf 2014-20"), - VWCarInfo("Volkswagen Golf 2015-20"), - VWCarInfo("Volkswagen Golf Alltrack 2015-19"), + VWCarInfo("Volkswagen Golf 2015-20", auto_resume=False), + VWCarInfo("Volkswagen Golf Alltrack 2015-19", auto_resume=False), VWCarInfo("Volkswagen Golf GTD 2015-20"), VWCarInfo("Volkswagen Golf GTE 2015-20"), - VWCarInfo("Volkswagen Golf GTI 2015-21"), + VWCarInfo("Volkswagen Golf GTI 2015-21", auto_resume=False), VWCarInfo("Volkswagen Golf R 2015-19"), VWCarInfo("Volkswagen Golf SportsVan 2015-20"), ], From d0a8b3780c6ca3db07cbb0a1d644f781efad40f0 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Tue, 23 May 2023 16:11:51 -0700 Subject: [PATCH 043/283] fix input order in onnxmodel (#28274) --- selfdrive/modeld/runners/onnxmodel.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/modeld/runners/onnxmodel.cc b/selfdrive/modeld/runners/onnxmodel.cc index 5616a6c9c7..a5a83bccdc 100644 --- a/selfdrive/modeld/runners/onnxmodel.cc +++ b/selfdrive/modeld/runners/onnxmodel.cc @@ -138,14 +138,14 @@ void ONNXModel::execute() { if (desire_input_buf != NULL) { pwrite(desire_input_buf, desire_state_size); } - if (nav_features_input_buf != NULL) { - pwrite(nav_features_input_buf, nav_features_size); + if (traffic_convention_input_buf != NULL) { + pwrite(traffic_convention_input_buf, traffic_convention_size); } if (driving_style_input_buf != NULL) { pwrite(driving_style_input_buf, driving_style_size); } - if (traffic_convention_input_buf != NULL) { - pwrite(traffic_convention_input_buf, traffic_convention_size); + if (nav_features_input_buf != NULL) { + pwrite(nav_features_input_buf, nav_features_size); } if (calib_input_buf != NULL) { pwrite(calib_input_buf, calib_size); From e6ac6320ace377657446a1a16ccccd75091f5453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 24 May 2023 02:24:16 +0200 Subject: [PATCH 044/283] process_replay: universal replay mechanism using cereal fake sockets (#28115) * replay_process_with_fake_sockets implementation * add missing polled_pubs to configs * drained_pubs field * updated cereal * Remove python/native variations of process replay. Replace with universal one using cereal fake sockets * Replace old py FakeSocket with DummySocket * Invalidate and deregister fake sockets after replay is done * Remove unused import * Set up new prefix for each replay * Fixes for radard * Refactor ReplayContext and ProcessConfig * Minor fixes * Reimplement controlsd fingerprinting callback * time.sleep for sockets to safely reconnect * Fix fingerprinting for controlsd * Fixes for regen to work * Fix replay loop to respect submaster frames * Fix profiler to use new ProcessConfig fields * Remove tqdm * Refactor tests to use new ProcessConfig * Add FrequencyBasedRcvCallback * Make tolerance None by default * Update cereal * Add get_process_config utility func * Update cereal. Simplify sync procedure * Chain context managers * New sub-socket reconnection procedure * Fix linter issues * Revert chaining of context managers * Init controlsState only when replaying controlsd. Update cereal * Update cereal * Update process_replay to use new cereal API * Update cereal * Update cereal * Update cereal * Simplify radard recv callback * Update release/files_common --- cereal | 2 +- release/files_common | 5 + selfdrive/controls/tests/test_alerts.py | 5 +- .../test/process_replay/process_replay.py | 723 +++++++----------- selfdrive/test/process_replay/regen.py | 3 +- selfdrive/test/process_replay/test_fuzzy.py | 2 +- selfdrive/test/profiling/profiler.py | 2 +- 7 files changed, 305 insertions(+), 437 deletions(-) diff --git a/cereal b/cereal index e0cf7e09ae..9b6b53396f 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit e0cf7e09ae2864034bc370fb6c3db71a83eaf3e6 +Subproject commit 9b6b53396fff6ec7541a5415901d892e57756b91 diff --git a/release/files_common b/release/files_common index 6f671e1781..0280d14b63 100644 --- a/release/files_common +++ b/release/files_common @@ -469,6 +469,7 @@ body/crypto/** cereal/.gitignore cereal/__init__.py cereal/car.capnp +cereal/custom.capnp cereal/legacy.capnp cereal/log.capnp cereal/services.py @@ -478,6 +479,10 @@ cereal/logger/logger.h cereal/messaging/.gitignore cereal/messaging/__init__.py cereal/messaging/bridge.cc +cereal/messaging/event.cc +cereal/messaging/event.h +cereal/messaging/impl_fake.cc +cereal/messaging/impl_fake.h cereal/messaging/impl_msgq.cc cereal/messaging/impl_msgq.h cereal/messaging/impl_zmq.cc diff --git a/selfdrive/controls/tests/test_alerts.py b/selfdrive/controls/tests/test_alerts.py index 9ed7eee122..60c080163f 100755 --- a/selfdrive/controls/tests/test_alerts.py +++ b/selfdrive/controls/tests/test_alerts.py @@ -6,11 +6,12 @@ import random from PIL import Image, ImageDraw, ImageFont from cereal import log, car +from cereal.messaging import SubMaster from common.basedir import BASEDIR from common.params import Params from selfdrive.controls.lib.events import Alert, EVENTS, ET from selfdrive.controls.lib.alertmanager import set_offroad_alert -from selfdrive.test.process_replay.process_replay import FakeSubMaster, CONFIGS +from selfdrive.test.process_replay.process_replay import CONFIGS AlertSize = log.ControlsState.AlertSize @@ -34,7 +35,7 @@ class TestAlerts(unittest.TestCase): cls.CS = car.CarState.new_message() cls.CP = car.CarParams.new_message() cfg = [c for c in CONFIGS if c.proc_name == 'controlsd'][0] - cls.sm = FakeSubMaster(cfg.pub_sub.keys()) + cls.sm = SubMaster(cfg.pubs) def test_events_defined(self): # Ensure all events in capnp schema are defined in events.py diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 65415b4151..0a572a7502 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -1,27 +1,21 @@ #!/usr/bin/env python3 -import importlib import os -import sys -import threading import time import signal -from collections import defaultdict +from collections import OrderedDict from dataclasses import dataclass, field from typing import Dict, List, Optional, Callable -import capnp - import cereal.messaging as messaging -from cereal import car, log +from cereal import car from cereal.services import service_list from common.params import Params from common.timeout import Timeout from common.realtime import DT_CTRL from panda.python import ALTERNATIVE_EXPERIENCE from selfdrive.car.car_helpers import get_car, interfaces -from selfdrive.test.process_replay.helpers import OpenpilotPrefix -from selfdrive.manager.process import PythonProcess from selfdrive.manager.process_config import managed_processes +from selfdrive.test.process_replay.helpers import OpenpilotPrefix # Numpy gives different results based on CPU features after version 19 NUMPY_TOLERANCE = 1e-7 @@ -30,373 +24,400 @@ TIMEOUT = 15 PROC_REPLAY_DIR = os.path.dirname(os.path.abspath(__file__)) FAKEDATA = os.path.join(PROC_REPLAY_DIR, "fakedata/") + +class ReplayContext: + def __init__(self, cfg): + self.proc_name = cfg.proc_name + self.pubs = cfg.pubs + self.drained_pub = cfg.drained_pub + assert(len(self.pubs) != 0 or self.drained_pub is not None) + + def __enter__(self): + messaging.toggle_fake_events(True) + messaging.set_fake_prefix(self.proc_name) + + if self.drained_pub is None: + self.events = OrderedDict() + for pub in self.pubs: + self.events[pub] = messaging.fake_event_handle(pub, enable=True) + else: + self.events = {self.drained_pub: messaging.fake_event_handle(self.drained_pub, enable=True)} + + return self + + def __exit__(self, exc_type, exc_obj, exc_tb): + del self.events + + messaging.toggle_fake_events(False) + messaging.delete_fake_prefix() + + @property + def all_recv_called_events(self): + return [man.recv_called_event for man in self.events.values()] + + @property + def all_recv_ready_events(self): + return [man.recv_ready_event for man in self.events.values()] + + def send_sync(self, pm, endpoint, dat): + self.events[endpoint].recv_called_event.wait() + self.events[endpoint].recv_called_event.clear() + pm.send(endpoint, dat) + self.events[endpoint].recv_ready_event.set() + + def unlock_sockets(self): + expected_sets = len(self.events) + while expected_sets > 0: + index = messaging.wait_for_one_event(self.all_recv_called_events) + self.all_recv_called_events[index].clear() + self.all_recv_ready_events[index].set() + expected_sets -= 1 + + def wait_for_recv_called(self): + messaging.wait_for_one_event(self.all_recv_called_events) + + def wait_for_next_recv(self, end_of_cycle): + index = messaging.wait_for_one_event(self.all_recv_called_events) + if self.drained_pub is not None and end_of_cycle: + self.all_recv_called_events[index].clear() + self.all_recv_ready_events[index].set() + self.all_recv_called_events[index].wait() + + @dataclass class ProcessConfig: proc_name: str - pub_sub: Dict[str, List[str]] + pubs: List[str] + subs: List[str] ignore: List[str] + config_callback: Optional[Callable] init_callback: Optional[Callable] should_recv_callback: Optional[Callable] - tolerance: Optional[float] - fake_pubsubmaster: bool - submaster_config: Dict[str, List[str]] = field(default_factory=dict) + tolerance: Optional[float] = None environ: Dict[str, str] = field(default_factory=dict) subtest_name: str = "" field_tolerances: Dict[str, float] = field(default_factory=dict) timeout: int = 30 - iter_wait_time: float = 0.0 - drain_sockets: bool = False + simulation: bool = True + drained_pub: Optional[str] = None -def wait_for_event(evt): - if not evt.wait(TIMEOUT): - if threading.currentThread().getName() == "MainThread": - # tested process likely died. don't let test just hang - raise Exception(f"Timeout reached. Tested process {os.environ['PROC_NAME']} likely crashed.") - else: - # done testing this process, let it die - sys.exit(0) - - -class FakeSocket: - def __init__(self, wait=True): +class DummySocket: + def __init__(self): self.data = [] - self.wait = wait - self.recv_called = threading.Event() - self.recv_ready = threading.Event() def receive(self, non_blocking=False): if non_blocking: return None - if self.wait: - self.recv_called.set() - wait_for_event(self.recv_ready) - self.recv_ready.clear() - return self.data.pop(0) + return self.data.pop() def send(self, data): - if self.wait: - wait_for_event(self.recv_called) - self.recv_called.clear() - self.data.append(data) - if self.wait: - self.recv_ready.set() - def wait_for_recv(self): - wait_for_event(self.recv_called) - - -class DumbSocket: - def __init__(self, s=None): - if s is not None: - try: - dat = messaging.new_message(s) - except capnp.lib.capnp.KjException: # pylint: disable=c-extension-no-member - # lists - dat = messaging.new_message(s, 0) - - self.data = dat.to_bytes() - - def receive(self, non_blocking=False): - return self.data - - def send(self, dat): - pass - - -class FakeSubMaster(messaging.SubMaster): - def __init__(self, services, ignore_alive=None, ignore_avg_freq=None): - super().__init__(services, ignore_alive=ignore_alive, ignore_avg_freq=ignore_avg_freq, addr=None) - self.sock = {s: DumbSocket(s) for s in services} - self.update_called = threading.Event() - self.update_ready = threading.Event() - self.wait_on_getitem = False - - def __getitem__(self, s): - # hack to know when fingerprinting is done - if self.wait_on_getitem: - self.update_called.set() - wait_for_event(self.update_ready) - self.update_ready.clear() - return self.data[s] - - def update(self, timeout=-1): - self.update_called.set() - wait_for_event(self.update_ready) - self.update_ready.clear() - - def update_msgs(self, cur_time, msgs): - wait_for_event(self.update_called) - self.update_called.clear() - super().update_msgs(cur_time, msgs) - self.update_ready.set() - - def wait_for_update(self): - wait_for_event(self.update_called) - - -class FakePubMaster(messaging.PubMaster): - def __init__(self, services): # pylint: disable=super-init-not-called - self.data = defaultdict(list) - self.sock = {} - self.last_updated = None - for s in services: - self.sock[s] = DumbSocket() - - def send(self, s, dat): - self.last_updated = s - if isinstance(dat, bytes): - self.data[s].append(log.Event.from_bytes(dat)) - else: - self.data[s].append(dat.as_reader()) - - def drain(self, s): - msgs = self.data[s] - self.data[s] = [] - - return msgs - - -def fingerprint(msgs, fsm, can_sock, fingerprint): +def controlsd_fingerprint_callback(rc, pm, msgs, fingerprint): print("start fingerprinting") - fsm.wait_on_getitem = True + params = Params() + canmsgs = [msg for msg in msgs if msg.which() == "can"][:300] - # populate fake socket with data for fingerprinting - canmsgs = [msg for msg in msgs if msg.which() == "can"] - wait_for_event(can_sock.recv_called) - can_sock.recv_called.clear() - can_sock.data = [msg.as_builder().to_bytes() for msg in canmsgs[:300]] - can_sock.recv_ready.set() - can_sock.wait = False + # controlsd expects one arbitrary can and pandaState + rc.send_sync(pm, "can", messaging.new_message("can", 1)) + pm.send("pandaStates", messaging.new_message("pandaStates", 1)) + rc.send_sync(pm, "can", messaging.new_message("can", 1)) + rc.wait_for_next_recv(True) - # we know fingerprinting is done when controlsd sets sm['lateralPlan'].sensorValid - wait_for_event(fsm.update_called) - fsm.update_called.clear() + # fingerprinting is done, when CarParams is set + while params.get("CarParams") is None: + if len(canmsgs) == 0: + raise ValueError("Fingerprinting failed. Run out of can msgs") - fsm.wait_on_getitem = False - can_sock.wait = True - can_sock.data = [] - - fsm.update_ready.set() + m = canmsgs.pop(0) + rc.send_sync(pm, "can", m.as_builder().to_bytes()) + rc.wait_for_next_recv(False) -def get_car_params(msgs, fsm, can_sock, fingerprint): +def get_car_params_callback(rc, pm, msgs, fingerprint): if fingerprint: CarInterface, _, _ = interfaces[fingerprint] CP = CarInterface.get_non_essential_params(fingerprint) else: - can = FakeSocket(wait=False) - sendcan = FakeSocket(wait=False) + can = DummySocket() + sendcan = DummySocket() - canmsgs = [msg for msg in msgs if msg.which() == 'can'] + canmsgs = [msg for msg in msgs if msg.which() == "can"] for m in canmsgs[:300]: can.send(m.as_builder().to_bytes()) _, CP = get_car(can, sendcan, Params().get_bool("ExperimentalLongitudinalEnabled")) Params().put("CarParams", CP.to_bytes()) -def controlsd_rcv_callback(msg, CP, cfg, fsm): +def controlsd_rcv_callback(msg, CP, cfg, frame): # no sendcan until controlsd is initialized - socks = [s for s in cfg.pub_sub[msg.which()] if - (fsm.frame + 1) % int(service_list[msg.which()].frequency / service_list[s].frequency) == 0] - if "sendcan" in socks and fsm.frame < 2000: - socks.remove("sendcan") - return socks, len(socks) > 0 - - -def radar_rcv_callback(msg, CP, cfg, fsm): if msg.which() != "can": - return [], False - elif CP.radarUnavailable: - return ["radarState", "liveTracks"], True + return False - radar_msgs = {"honda": [0x445], "toyota": [0x19f, 0x22f], "gm": [0x474], - "chrysler": [0x2d4]}.get(CP.carName, None) - - if radar_msgs is None: - raise NotImplementedError - - for m in msg.can: - if m.src == 1 and m.address in radar_msgs: - return ["radarState", "liveTracks"], True - return [], False + socks = [ + s for s in cfg.subs if + frame % int(service_list[msg.which()].frequency / service_list[s].frequency) == 0 + ] + if "sendcan" in socks and (frame - 1) < 2000: + socks.remove("sendcan") + return len(socks) > 0 -def calibration_rcv_callback(msg, CP, cfg, fsm): +def radar_rcv_callback(msg, CP, cfg, frame): + return msg.which() == "can" + + +def calibration_rcv_callback(msg, CP, cfg, frame): # calibrationd publishes 1 calibrationData every 5 cameraOdometry packets. # should_recv always true to increment frame - recv_socks = [] - frame = fsm.frame + 1 # incrementing hasn't happened yet in SubMaster - if frame == 0 or (msg.which() == 'cameraOdometry' and (frame % 5) == 0): - recv_socks = ["liveCalibration"] - return recv_socks, fsm.frame == 0 or msg.which() == 'cameraOdometry' + return (frame - 1) == 0 or msg.which() == 'cameraOdometry' -def torqued_rcv_callback(msg, CP, cfg, fsm): +def torqued_rcv_callback(msg, CP, cfg, frame): # should_recv always true to increment frame - recv_socks = [] - frame = fsm.frame + 1 # incrementing hasn't happened yet in SubMaster - if msg.which() == 'liveLocationKalman' and (frame % 5) == 0: - recv_socks = ["liveTorqueParameters"] - return recv_socks, fsm.frame == 0 or msg.which() == 'liveLocationKalman' + return (frame - 1) == 0 or msg.which() == 'liveLocationKalman' -def locationd_rcv_callback(msg, CP, cfg, fsm): - trigger_msg = "accelerometer" if CP is not None and CP.notCar else "cameraOdometry" - if msg.which() == trigger_msg: - return ["liveLocationKalman"], True +class FrequencyBasedRcvCallback: + def __init__(self, trigger_msg_type): + self.trigger_msg_type = trigger_msg_type + + def __call__(self, msg, CP, cfg, frame): + if msg.which() != self.trigger_msg_type: + return False + + resp_sockets = [ + s for s in cfg.subs + if frame % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0 + ] + return bool(len(resp_sockets)) + + +def laikad_config_pubsub_callback(params, cfg): + ublox = params.get_bool("UbloxAvailable") + drained_key = "ubloxGnss" if ublox else "qcomGnss" + sub_keys = ({"qcomGnss", } if ublox else {"ubloxGnss", }) + + return set(cfg.pubs) - sub_keys, drained_key + + +def locationd_config_pubsub_callback(params, cfg): + ublox = params.get_bool("UbloxAvailable") + sub_keys = ({"gpsLocation", } if ublox else {"gpsLocationExternal", }) - return [], False + return set(cfg.pubs) - sub_keys, None CONFIGS = [ ProcessConfig( proc_name="controlsd", - pub_sub={ - "can": ["controlsState", "carState", "carControl", "sendcan", "carEvents", "carParams"], - "deviceState": [], "pandaStates": [], "peripheralState": [], "liveCalibration": [], "driverMonitoringState": [], - "longitudinalPlan": [], "lateralPlan": [], "liveLocationKalman": [], "liveParameters": [], "radarState": [], - "modelV2": [], "driverCameraState": [], "roadCameraState": [], "wideRoadCameraState": [], "managerState": [], - "testJoystick": [], "liveTorqueParameters": [], - }, + pubs=[ + "can", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState", + "longitudinalPlan", "lateralPlan", "liveLocationKalman", "liveParameters", "radarState", + "modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState", + "testJoystick", "liveTorqueParameters" + ], + subs=["controlsState", "carState", "carControl", "sendcan", "carEvents", "carParams"], ignore=["logMonoTime", "valid", "controlsState.startMonoTime", "controlsState.cumLagMs"], - init_callback=fingerprint, + config_callback=None, + init_callback=controlsd_fingerprint_callback, should_recv_callback=controlsd_rcv_callback, tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, - submaster_config={ - 'ignore_avg_freq': ['radarState', 'longitudinalPlan', 'driverCameraState', 'driverMonitoringState'], # dcam is expected at 20 Hz - 'ignore_alive': [], - } + simulation=False, + drained_pub="can", ), ProcessConfig( proc_name="radard", - pub_sub={ - "can": ["radarState", "liveTracks"], - "carState": [], "modelV2": [], - }, + pubs=["can", "carState", "modelV2"], + subs=["radarState", "liveTracks"], ignore=["logMonoTime", "valid", "radarState.cumLagMs"], - init_callback=get_car_params, + config_callback=None, + init_callback=get_car_params_callback, should_recv_callback=radar_rcv_callback, - tolerance=None, - fake_pubsubmaster=True, + drained_pub="can", ), ProcessConfig( proc_name="plannerd", - pub_sub={ - "modelV2": ["lateralPlan", "longitudinalPlan", "uiPlan"], - "carControl": [], "carState": [], "controlsState": [], "radarState": [], - }, + pubs=["modelV2", "carControl", "carState", "controlsState", "radarState"], + subs=["lateralPlan", "longitudinalPlan", "uiPlan"], ignore=["logMonoTime", "valid", "longitudinalPlan.processingDelay", "longitudinalPlan.solverExecutionTime", "lateralPlan.solverExecutionTime"], - init_callback=get_car_params, - should_recv_callback=None, + config_callback=None, + init_callback=get_car_params_callback, + should_recv_callback=FrequencyBasedRcvCallback("modelV2"), tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, ), ProcessConfig( proc_name="calibrationd", - pub_sub={ - "carState": [], - "cameraOdometry": ["liveCalibration"], - "carParams": [], - }, + pubs=["carState", "cameraOdometry", "carParams"], + subs=["liveCalibration"], ignore=["logMonoTime", "valid"], - init_callback=get_car_params, + config_callback=None, + init_callback=get_car_params_callback, should_recv_callback=calibration_rcv_callback, - tolerance=None, - fake_pubsubmaster=True, ), ProcessConfig( proc_name="dmonitoringd", - pub_sub={ - "driverStateV2": ["driverMonitoringState"], - "liveCalibration": [], "carState": [], "modelV2": [], "controlsState": [], - }, + pubs=["driverStateV2", "liveCalibration", "carState", "modelV2", "controlsState"], + subs=["driverMonitoringState"], ignore=["logMonoTime", "valid"], - init_callback=get_car_params, - should_recv_callback=None, + config_callback=None, + init_callback=get_car_params_callback, + should_recv_callback=FrequencyBasedRcvCallback("driverStateV2"), tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, ), ProcessConfig( proc_name="locationd", - pub_sub={ - "cameraOdometry": ["liveLocationKalman"], - "accelerometer": ["liveLocationKalman"], "gyroscope": [], - "gpsLocationExternal": [], "liveCalibration": [], - "carParams": [], "carState": [], "gpsLocation": [], - }, + pubs=[ + "cameraOdometry", "accelerometer", "gyroscope", "gpsLocationExternal", + "liveCalibration", "carState", "carParams", "gpsLocation" + ], + subs=["liveLocationKalman"], ignore=["logMonoTime", "valid"], - init_callback=get_car_params, - should_recv_callback=locationd_rcv_callback, + config_callback=locationd_config_pubsub_callback, + init_callback=get_car_params_callback, + should_recv_callback=None, tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=False, ), ProcessConfig( proc_name="paramsd", - pub_sub={ - "liveLocationKalman": ["liveParameters"], - "carState": [] - }, + pubs=["liveLocationKalman", "carState"], + subs=["liveParameters"], ignore=["logMonoTime", "valid"], - init_callback=get_car_params, - should_recv_callback=None, + config_callback=None, + init_callback=get_car_params_callback, + should_recv_callback=FrequencyBasedRcvCallback("liveLocationKalman"), tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, ), ProcessConfig( proc_name="ubloxd", - pub_sub={ - "ubloxRaw": ["ubloxGnss", "gpsLocationExternal"], - }, + pubs=["ubloxRaw"], + subs=["ubloxGnss", "gpsLocationExternal"], ignore=["logMonoTime"], + config_callback=None, init_callback=None, should_recv_callback=None, - tolerance=None, - fake_pubsubmaster=False, - iter_wait_time=0.01, - drain_sockets=True ), ProcessConfig( proc_name="laikad", - pub_sub={ - "ubloxGnss": ["gnssMeasurements"], - "qcomGnss": ["gnssMeasurements"], - }, + pubs=["ubloxGnss", "qcomGnss"], + subs=["gnssMeasurements"], ignore=["logMonoTime"], - init_callback=get_car_params, + config_callback=laikad_config_pubsub_callback, + init_callback=get_car_params_callback, should_recv_callback=None, tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=False, timeout=60*10, # first messages are blocked on internet assistance + drained_pub="ubloxGnss", # config_callback will switch this to qcom if needed ), ProcessConfig( proc_name="torqued", - pub_sub={ - "carControl": [], "carState": [], - "liveLocationKalman": ["liveTorqueParameters"], - }, + pubs=["liveLocationKalman", "carState", "carControl"], + subs=["liveTorqueParameters"], ignore=["logMonoTime"], - init_callback=get_car_params, + config_callback=None, + init_callback=get_car_params_callback, should_recv_callback=torqued_rcv_callback, tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, ), ] +def get_process_config(name): + try: + return next(c for c in CONFIGS if c.proc_name == name) + except StopIteration as ex: + raise Exception(f"Cannot find process config with name: {name}") from ex + + def replay_process(cfg, lr, fingerprint=None): with OpenpilotPrefix(): - if cfg.fake_pubsubmaster: - return python_replay_process(cfg, lr, fingerprint) + controlsState = None + initialized = False + if cfg.proc_name == "controlsd": + for msg in lr: + if msg.which() == 'controlsState': + controlsState = msg.controlsState + if initialized: + break + elif msg.which() == 'carEvents': + initialized = car.CarEvent.EventName.controlsInitializing not in [e.name for e in msg.carEvents] + + assert controlsState is not None and initialized, "controlsState never initialized" + + CP = [m for m in lr if m.which() == 'carParams'][0].carParams + if fingerprint is not None: + setup_env(cfg=cfg, controlsState=controlsState, lr=lr, fingerprint=fingerprint) else: - return replay_process_with_sockets(cfg, lr, fingerprint) + setup_env(CP=CP, cfg=cfg, controlsState=controlsState, lr=lr) + + if cfg.config_callback is not None: + params = Params() + cfg.pubs, cfg.drained_pub = cfg.config_callback(params, cfg) + + all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) + pub_msgs = [msg for msg in all_msgs if msg.which() in set(cfg.pubs)] + + with ReplayContext(cfg) as rc: + pm = messaging.PubMaster(cfg.pubs) + sockets = {s: messaging.sub_sock(s, timeout=100) for s in cfg.subs} + + managed_processes[cfg.proc_name].prepare() + managed_processes[cfg.proc_name].start() + + if cfg.init_callback is not None: + cfg.init_callback(rc, pm, all_msgs, fingerprint) + CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) + + log_msgs, msg_queue = [], [] + try: + # Wait for process to startup + with Timeout(10, error_msg=f"timed out waiting for process to start: {repr(cfg.proc_name)}"): + while not all(pm.all_readers_updated(s) for s in cfg.pubs): + time.sleep(0) + + # Do the replay + cnt = 0 + for msg in pub_msgs: + with Timeout(cfg.timeout, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): + resp_sockets, end_of_cycle = cfg.subs, True + if cfg.should_recv_callback is not None: + end_of_cycle = cfg.should_recv_callback(msg, CP, cfg, cnt) + + msg_queue.append(msg) + if end_of_cycle: + rc.wait_for_recv_called() + + # call recv to let sub-sockets reconnect, after we know the process is ready + if cnt == 0: + for s in sockets.values(): + messaging.recv_one_or_none(s) + + for m in msg_queue: + pm.send(m.which(), m.as_builder()) + msg_queue = [] + + rc.unlock_sockets() + rc.wait_for_next_recv(True) + + for s in resp_sockets: + ms = messaging.drain_sock(sockets[s]) + for m in ms: + m = m.as_builder() + m.logMonoTime = msg.logMonoTime + log_msgs.append(m.as_reader()) + cnt += 1 + assert(managed_processes[cfg.proc_name].proc.is_alive()) + finally: + managed_processes[cfg.proc_name].signal(signal.SIGKILL) + managed_processes[cfg.proc_name].stop() + + return log_msgs -def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): +def setup_env(CP=None, cfg=None, controlsState=None, lr=None, fingerprint=None): params = Params() params.clear_all() params.put_bool("OpenpilotEnabledToggle", True) @@ -407,8 +428,12 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): os.environ["NO_RADAR_SLEEP"] = "1" os.environ["REPLAY"] = "1" - os.environ["SKIP_FW_QUERY"] = "" - os.environ["FINGERPRINT"] = "" + if fingerprint is not None: + os.environ['SKIP_FW_QUERY'] = "1" + os.environ['FINGERPRINT'] = fingerprint + else: + os.environ["SKIP_FW_QUERY"] = "" + os.environ["FINGERPRINT"] = "" if lr is not None: services = {m.which() for m in lr} @@ -424,7 +449,7 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): os.environ.update(cfg.environ) os.environ['PROC_NAME'] = cfg.proc_name - if simulation: + if cfg is not None and cfg.simulation: os.environ["SIMULATION"] = "1" elif "SIMULATION" in os.environ: del os.environ["SIMULATION"] @@ -440,181 +465,19 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): if CP.alternativeExperience == ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS: params.put_bool("DisengageOnAccelerator", False) - if CP.fingerprintSource == "fw": - params.put("CarParamsCache", CP.as_builder().to_bytes()) - else: - os.environ['SKIP_FW_QUERY'] = "1" - os.environ['FINGERPRINT'] = CP.carFingerprint + if fingerprint is None: + if CP.fingerprintSource == "fw": + params.put("CarParamsCache", CP.as_builder().to_bytes()) + os.environ['SKIP_FW_QUERY'] = "" + os.environ['FINGERPRINT'] = "" + else: + os.environ['SKIP_FW_QUERY'] = "1" + os.environ['FINGERPRINT'] = CP.carFingerprint if CP.openpilotLongitudinalControl: params.put_bool("ExperimentalLongitudinalEnabled", True) -def python_replay_process(cfg, lr, fingerprint=None): - sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] - pub_sockets = [s for s in cfg.pub_sub.keys() if s != 'can'] - - fsm = FakeSubMaster(pub_sockets, **cfg.submaster_config) - fpm = FakePubMaster(sub_sockets) - can_sock = None - args = (fsm, fpm) - if 'can' in list(cfg.pub_sub.keys()): - can_sock = FakeSocket() - args = (fsm, fpm, can_sock) - - all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) - pub_msgs = [msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())] - - controlsState = None - initialized = False - for msg in lr: - if msg.which() == 'controlsState': - controlsState = msg.controlsState - if initialized: - break - elif msg.which() == 'carEvents': - initialized = car.CarEvent.EventName.controlsInitializing not in [e.name for e in msg.carEvents] - - assert controlsState is not None and initialized, "controlsState never initialized" - - if fingerprint is not None: - os.environ['SKIP_FW_QUERY'] = "1" - os.environ['FINGERPRINT'] = fingerprint - setup_env(cfg=cfg, controlsState=controlsState, lr=lr) - else: - CP = [m for m in lr if m.which() == 'carParams'][0].carParams - setup_env(CP=CP, cfg=cfg, controlsState=controlsState, lr=lr) - - assert(type(managed_processes[cfg.proc_name]) is PythonProcess) - managed_processes[cfg.proc_name].prepare() - mod = importlib.import_module(managed_processes[cfg.proc_name].module) - - thread = threading.Thread(target=mod.main, args=args) - thread.daemon = True - thread.start() - - if cfg.init_callback is not None: - if 'can' not in list(cfg.pub_sub.keys()): - can_sock = None - cfg.init_callback(all_msgs, fsm, can_sock, fingerprint) - - CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) - - # wait for started process to be ready - if 'can' in list(cfg.pub_sub.keys()): - can_sock.wait_for_recv() - else: - fsm.wait_for_update() - - log_msgs, msg_queue = [], [] - for msg in pub_msgs: - recv_socks = cfg.pub_sub[msg.which()] - if cfg.should_recv_callback is not None: - _, should_recv = cfg.should_recv_callback(msg, CP, cfg, fsm) - else: - socks = [s for s in cfg.pub_sub[msg.which()] if - (fsm.frame + 1) % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0] - should_recv = bool(len(socks)) - - if msg.which() == 'can': - can_sock.send(msg.as_builder().to_bytes()) - else: - msg_queue.append(msg.as_builder()) - - if should_recv: - fsm.update_msgs(msg.logMonoTime / 1e9, msg_queue) - msg_queue = [] - - if can_sock is not None: - can_sock.recv_called.wait() - else: - fsm.update_called.wait() - - for s in recv_socks: - ms = fpm.drain(s) - for m in ms: - m = m.as_builder() - m.logMonoTime = msg.logMonoTime - log_msgs.append(m.as_reader()) - - return log_msgs - - -def replay_process_with_sockets(cfg, lr, fingerprint=None): - pm = messaging.PubMaster(cfg.pub_sub.keys()) - sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] - sockets = {s: messaging.sub_sock(s, timeout=100) for s in sub_sockets} - - all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) - pub_msgs = [msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())] - - # We need to fake SubMaster alive since we can't inject a fake clock - CP = [m for m in lr if m.which() == 'carParams'][0].carParams - setup_env(simulation=True, CP=CP, cfg=cfg, lr=lr) - - if cfg.proc_name == "laikad": - ublox = Params().get_bool("UbloxAvailable") - keys = set(cfg.pub_sub.keys()) - ({"qcomGnss", } if ublox else {"ubloxGnss", }) - pub_msgs = [msg for msg in pub_msgs if msg.which() in keys] - - managed_processes[cfg.proc_name].prepare() - managed_processes[cfg.proc_name].start() - - if cfg.init_callback is not None: - cfg.init_callback(all_msgs, None, None, fingerprint) - CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) - - log_msgs = [] - try: - # Wait for process to startup - with Timeout(10, error_msg=f"timed out waiting for process to start: {repr(cfg.proc_name)}"): - while not any(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): - time.sleep(0) - - for s in sockets.values(): - messaging.recv_one_or_none(s) - - # Do the replay - cnt = 0 - curr_CP = None - for msg in pub_msgs: - with Timeout(cfg.timeout, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): - if msg.which() == 'carParams': - curr_CP = msg.carParams - - resp_sockets = cfg.pub_sub[msg.which()] - if cfg.should_recv_callback is not None: - resp_sockets, _ = cfg.should_recv_callback(msg, curr_CP, cfg, None) - - # Make sure all subscribers are connected - if len(log_msgs) == 0 and len(resp_sockets) > 0: - for s in sockets.values(): - messaging.recv_one_or_none(s) - - pm.send(msg.which(), msg.as_builder()) - while not pm.all_readers_updated(msg.which()): - time.sleep(0) - - time.sleep(cfg.iter_wait_time) - - for s in resp_sockets: - msgs = [] - if cfg.drain_sockets: - msgs.extend(messaging.drain_sock(sockets[s], wait_for_one=True)) - else: - msgs = [messaging.recv_one_retry(sockets[s])] - for m in msgs: - m = m.as_builder() - m.logMonoTime = msg.logMonoTime - log_msgs.append(m.as_reader()) - cnt += 1 - finally: - managed_processes[cfg.proc_name].signal(signal.SIGKILL) - managed_processes[cfg.proc_name].stop() - - return log_msgs - - def check_enabled(msgs): cur_enabled_count = 0 max_enabled_count = 0 diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index dea9a737e8..fbabc1bd29 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -283,10 +283,9 @@ def regen_segment(lr, frs=None, daemons="all", outdir=FAKEDATA, disable_tqdm=Fal # TODO add configs for modeld, dmonitoringmodeld fakeable_daemons = {} for config in CONFIGS: - replayable_messages = set([msg for sub in config.pub_sub.values() for msg in sub]) processes = [ multiprocessing.Process(target=replay_service, args=(msg, lr)) - for msg in replayable_messages + for msg in config.subs ] fakeable_daemons[config.proc_name] = processes diff --git a/selfdrive/test/process_replay/test_fuzzy.py b/selfdrive/test/process_replay/test_fuzzy.py index 29fdf641f1..12f5fca37d 100755 --- a/selfdrive/test/process_replay/test_fuzzy.py +++ b/selfdrive/test/process_replay/test_fuzzy.py @@ -99,7 +99,7 @@ def get_strategy_for_events(event_types, finite=False): def get_strategy_for_process(process, finite=False): - return get_strategy_for_events(get_process_config(process).pub_sub.keys(), finite) + return get_strategy_for_events(get_process_config(process).pubs, finite) def convert_to_lr(msgs): diff --git a/selfdrive/test/profiling/profiler.py b/selfdrive/test/profiling/profiler.py index 732a69eebd..a0940b327b 100755 --- a/selfdrive/test/profiling/profiler.py +++ b/selfdrive/test/profiling/profiler.py @@ -25,7 +25,7 @@ CARS = { def get_inputs(msgs, process, fingerprint): for config in CONFIGS: if config.proc_name == process: - sub_socks = list(config.pub_sub.keys()) + sub_socks = list(config.pubs) trigger = sub_socks[0] break From 00ff096ca2f9ca5e1c0f6a78702dc3cc78978092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 24 May 2023 04:48:57 +0200 Subject: [PATCH 045/283] replay: replay deprecated pandaState if pandaStates is whitelisted (#28275) --- tools/replay/replay.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index b68330f688..95315fe71b 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -30,6 +30,9 @@ Replay::Replay(QString route, QStringList allow, QStringList block, SubMaster *s // the following events are needed for replay to work properly. allow_list.insert(cereal::Event::Which::INIT_DATA); allow_list.insert(cereal::Event::Which::CAR_PARAMS); + if (sockets_[cereal::Event::Which::PANDA_STATES] != nullptr) { + allow_list.insert(cereal::Event::Which::PANDA_STATE_D_E_P_R_E_C_A_T_E_D); + } } qDebug() << "services " << s; From 115fc66514dbbdac0591d2d59734ed5233fd0dd8 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 May 2023 19:49:54 -0700 Subject: [PATCH 046/283] remove sleep on launch (#28236) --- launch_chffrplus.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 9fe9b1bd15..a91bd677aa 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -9,11 +9,6 @@ source "$BASEDIR/launch_env.sh" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" function agnos_init { - # wait longer for weston to come up - if [ -f "$BASEDIR/prebuilt" ]; then - sleep 3 - fi - # TODO: move this to agnos sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta From 347004fdad21cb063ba81f05bb83ad6e5be1e9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 24 May 2023 04:50:56 +0200 Subject: [PATCH 047/283] aarch64: disable carla and onnxruntime-gpu on non-x64 hosts (#28261) Disable carla and onnxrunner-gpu on aarch64 --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2963337733..fa03248b9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ libusb1 = "^3.0.0" nose = "^1.3.7" numpy = "^1.23.0" onnx = "^1.12.0" -onnxruntime-gpu = { version = "^1.11.1", platform = "linux" } +onnxruntime-gpu = { version = "^1.11.1", platform = "linux", markers = "platform_machine == 'x86_64'" } pillow = "^9.2.0" poetry = "==1.2.2" protobuf = "==3.20.1" @@ -66,7 +66,7 @@ sconscontrib = {git = "https://github.com/SCons/scons-contrib.git"} av = "^9.2.0" azure-storage-blob = "~2.1" breathe = "^4.34.0" -carla = { version = "==0.9.13", platform = "linux" } +carla = { version = "==0.9.13", platform = "linux", markers = "platform_machine == 'x86_64'" } control = "^0.9.2" coverage = "^6.4.1" dictdiffer = "^0.9.0" From 696b69aa23ac6eefd42de5bf0f146f29598e05ec Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 23 May 2023 20:51:15 -0700 Subject: [PATCH 048/283] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 2a5058d858..2da9b8d173 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2a5058d858b36ff7dc5477119a54f0aab137b266 +Subproject commit 2da9b8d17319be80d48402eb73bb67a36c001d30 From 2c65b843a573f260f378489457d32c9061f4a139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 24 May 2023 11:41:01 +0200 Subject: [PATCH 049/283] Calibrationd: allow more pitch angle (#28255) * Calibrationd: allow more pitch angle * Update ref_commit --- selfdrive/locationd/calibrationd.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index dc4ffbb1f7..42fa3b7c94 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -33,8 +33,8 @@ MAX_ALLOWED_SPREAD = np.radians(2) RPY_INIT = np.array([0.0,0.0,0.0]) WIDE_FROM_DEVICE_EULER_INIT = np.array([0.0, 0.0, 0.0]) -# These values are needed to accommodate biggest modelframe -PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657]) +# These values are needed to accommodate the model frame in the narrow cam of the C3 +PITCH_LIMITS = np.array([-0.09074112085129739, 0.17]) YAW_LIMITS = np.array([-0.06912048084718224, 0.06912048084718235]) DEBUG = os.getenv("DEBUG") is not None diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index bff328d31c..802d936bc9 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -89ead2916988a97a938f5e2e10855c37fcbf5d65 +5c68f066452f7fcfb315abc5cb9b7a50794fbd3f From 9f3c0a778113313e7d390f672abfe40a0d242b7d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 24 May 2023 10:04:53 -0700 Subject: [PATCH 050/283] update loggerd and ui cpu --- selfdrive/test/test_onroad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index efe15266c6..acc98c85d6 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -25,12 +25,12 @@ from tools.lib.logreader import LogReader # Baseline CPU usage by process PROCS = { "selfdrive.controls.controlsd": 39.0, - "./loggerd": 10.0, + "./loggerd": 14.0, "./encoderd": 17.0, "./camerad": 14.5, "./locationd": 11.0, "selfdrive.controls.plannerd": 16.5, - "./_ui": 19.2, + "./_ui": 21.0, "selfdrive.locationd.paramsd": 9.0, "./_sensord": 12.0, "selfdrive.controls.radard": 4.5, From ac0272d0cc1b33893b3fbbea0b9653f68f2e1a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 24 May 2023 22:16:22 +0200 Subject: [PATCH 051/283] process_replay: use PARAMS_ROOT (#28282) Use PARAMS_ROOT in process_replay --- selfdrive/test/process_replay/process_replay.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 0a572a7502..f271335611 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -418,6 +418,8 @@ def replay_process(cfg, lr, fingerprint=None): def setup_env(CP=None, cfg=None, controlsState=None, lr=None, fingerprint=None): + os.environ["PARAMS_ROOT"] = "/dev/shm/params" + params = Params() params.clear_all() params.put_bool("OpenpilotEnabledToggle", True) From 94937e0694d600bf15c4180452acf1a2029bf81c Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 24 May 2023 15:00:17 -0700 Subject: [PATCH 052/283] UI: reduce margin around software version (#28283) --- selfdrive/ui/qt/home.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 3f3c9a5885..273ee6595c 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -102,11 +102,11 @@ void HomeWindow::mouseDoubleClickEvent(QMouseEvent* e) { OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { QVBoxLayout* main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(40, 40, 40, 45); + main_layout->setContentsMargins(40, 40, 40, 40); // top header QHBoxLayout* header_layout = new QHBoxLayout(); - header_layout->setContentsMargins(15, 15, 15, 0); + header_layout->setContentsMargins(0, 0, 0, 0); header_layout->setSpacing(16); update_notif = new QPushButton(tr("UPDATE")); From d6592436481e448933e8124541a8d5654a3b3d34 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 24 May 2023 15:41:14 -0700 Subject: [PATCH 053/283] UI: cleanup OffroadHome layout (#28284) --- selfdrive/ui/qt/home.cc | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 273ee6595c..2b8974f73a 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -130,27 +130,29 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { main_layout->addSpacing(25); center_layout = new QStackedLayout(); - // Vertical experimental button and drive stats layout - QWidget* statsAndExperimentalModeButtonWidget = new QWidget(this); - QVBoxLayout* statsAndExperimentalModeButton = new QVBoxLayout(statsAndExperimentalModeButtonWidget); - statsAndExperimentalModeButton->setSpacing(30); - statsAndExperimentalModeButton->setMargin(0); + QWidget *home_widget = new QWidget(this); + { + QHBoxLayout *home_layout = new QHBoxLayout(home_widget); + home_layout->setContentsMargins(0, 0, 0, 0); + home_layout->setSpacing(30); - ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); - QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); + // left: ExperimentalModeButton, DriveStats + QWidget* left_widget = new QWidget(this); + QVBoxLayout* left_column = new QVBoxLayout(left_widget); + left_column->setContentsMargins(0, 0, 0, 0); + left_column->setSpacing(30); - statsAndExperimentalModeButton->addWidget(experimental_mode, 1); - statsAndExperimentalModeButton->addWidget(new DriveStats, 1); + ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); + QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); + left_column->addWidget(experimental_mode, 1); + left_column->addWidget(new DriveStats, 1); - // Horizontal experimental + drive stats and setup widget - QWidget* statsAndSetupWidget = new QWidget(this); - QHBoxLayout* statsAndSetup = new QHBoxLayout(statsAndSetupWidget); - statsAndSetup->setMargin(0); - statsAndSetup->setSpacing(30); - statsAndSetup->addWidget(statsAndExperimentalModeButtonWidget, 1); - statsAndSetup->addWidget(new SetupWidget); + home_layout->addWidget(left_widget, 1); - center_layout->addWidget(statsAndSetupWidget); + // right: SetupWidget + home_layout->addWidget(new SetupWidget); + } + center_layout->addWidget(home_widget); // add update & alerts widgets update_widget = new UpdateAlert(); From 394f0d2c3083782c5bf568ffe265a61cc8989528 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 24 May 2023 16:29:34 -0700 Subject: [PATCH 054/283] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 2da9b8d173..00c2689487 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2da9b8d17319be80d48402eb73bb67a36c001d30 +Subproject commit 00c26894876484d2c5a5b63a1c33c28f0f9b15dd From 2ea7b69e2689591772cc23181bd09724831f4d71 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 24 May 2023 17:08:19 -0700 Subject: [PATCH 055/283] CARS.md: footnotes header (#28285) footnotes --- docs/CARS.md | 2 +- selfdrive/car/CARS_template.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 26e0f8e960..c783bb8af2 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -261,7 +261,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| |Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| - +### Footnotes 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
diff --git a/selfdrive/car/CARS_template.md b/selfdrive/car/CARS_template.md index 1ab8a11955..4d76e253cc 100644 --- a/selfdrive/car/CARS_template.md +++ b/selfdrive/car/CARS_template.md @@ -21,7 +21,7 @@ A supported vehicle is one that just works when you install a comma three. All s {% endfor %} - +### Footnotes {% for footnote in footnotes %} {{loop.index}}{{footnote}}
{% endfor %} From 26064196d0362d7719ce7b1ee835eb2193a3dc57 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 24 May 2023 17:28:33 -0700 Subject: [PATCH 056/283] ui: smooth wide cam transition (#28277) * horribly messy * bit simpler * is this right? * simpler and should work? * used to be int/frames, but added easing so treat as float * end slow (start fast) * little faster * clean up * not needed * try ease in/ease out and fix * remove debugging print * fix * revert to previous curve * based on speed * not right * fix * fix * this kinda works * Revert zoom by speed Revert "this kinda works" This reverts commit 48aa30b945148b8eb79fbe33eb58e3fc3a6a7009. Revert "fix" This reverts commit 4ff2d33486231727d7cd68d366342c2273e3a315. Revert "fix" This reverts commit 15b22f8e8284eb017000856abb05b5e8973a6c0e. Revert "not right" This reverts commit 378b9965e14250c57ed39e1976de60d89054c2c8. Revert "based on speed" This reverts commit 1f7bfa5d73a2dee3740096da64eda24b33288b51. Revert "Revert "not right"" This reverts commit 1beeb402534a755208d19771eb4a2afdc69b8739. * better curve * revert * use constants and fixes * up here too * feels more intuitive to make zoom_transition=1 be zoomed in * rm line * fix * cmt * better handling * better name * zoom if ANY other stream is requested * Update selfdrive/ui/qt/widgets/cameraview.cc --- common/modeldata.h | 3 +++ selfdrive/ui/qt/widgets/cameraview.cc | 24 ++++++++++++++++++++---- selfdrive/ui/qt/widgets/cameraview.h | 6 ++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/common/modeldata.h b/common/modeldata.h index a00d3d49d3..fdb5dd078d 100644 --- a/common/modeldata.h +++ b/common/modeldata.h @@ -34,6 +34,9 @@ const mat3 ecam_intrinsic_matrix = (mat3){{567.0, 0.0, 1928.0 / 2, 0.0, 567.0, 1208.0 / 2, 0.0, 0.0, 1.0}}; +// zoom multiplier between cameras +const float ecam_to_fcam_zoom = fcam_intrinsic_matrix.v[0] / ecam_intrinsic_matrix.v[0]; + static inline mat3 get_model_yuv_transform() { float db_s = 1.0; const mat3 transform = (mat3){{ diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 016129c348..d4f7e294dd 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -201,6 +201,12 @@ void CameraWidget::updateFrameMat() { int w = glWidth(), h = glHeight(); if (zoomed_view) { + if (active_stream_type != VISION_STREAM_WIDE_ROAD) { + // Always ready to switch if wide is not active, start at full zoom + zoom_transition = 1; + ready_to_switch_stream = true; + } + if (active_stream_type == VISION_STREAM_DRIVER) { frame_mat = get_driver_view_transform(w, h, stream_width, stream_height); } else { @@ -209,11 +215,21 @@ void CameraWidget::updateFrameMat() { // for narrow come and a little lower for wide cam. // TODO: use proper perspective transform? if (active_stream_type == VISION_STREAM_WIDE_ROAD) { + // If narrow road camera is requested, start zooming in. + // Mark ready to switch once we're fully zoomed in + if (requested_stream_type != VISION_STREAM_WIDE_ROAD) { + zoom_transition += zoom_transition * 0.2 + 0.01; + } else { + zoom_transition -= (1.0 - zoom_transition) * 0.2 + 0.01; + } + zoom_transition = std::clamp(zoom_transition, 0.0f, 1.0f); + ready_to_switch_stream = fabs(zoom_transition - 1) < 1e-3; + intrinsic_matrix = ecam_intrinsic_matrix; - zoom = 2.0; + zoom = util::map_val(zoom_transition, 0.0f, 1.0f, ecam_zoom, ecam_to_fcam_zoom * fcam_zoom); } else { intrinsic_matrix = fcam_intrinsic_matrix; - zoom = 1.1; + zoom = fcam_zoom; } const vec3 inf = {{1000., 0., 0.}}; const vec3 Ep = matvecmul3(calibration, inf); @@ -372,13 +388,13 @@ void CameraWidget::vipcThread() { VisionIpcBufExtra meta_main = {0}; while (!QThread::currentThread()->isInterruptionRequested()) { - if (!vipc_client || cur_stream != requested_stream_type) { + if (!vipc_client || ((cur_stream != requested_stream_type) && ready_to_switch_stream)) { clearFrames(); qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; cur_stream = requested_stream_type; vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); + active_stream_type = cur_stream; } - active_stream_type = cur_stream; if (!vipc_client->connected) { clearFrames(); diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 8a140e5290..931e85e842 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -73,6 +73,8 @@ protected: int stream_width = 0; int stream_height = 0; int stream_stride = 0; + bool ready_to_switch_stream = true; // stream transition may be delayed by a zoom animation + float zoom_transition = 0; std::atomic active_stream_type; std::atomic requested_stream_type; std::set available_streams; @@ -85,6 +87,10 @@ protected: mat3 calibration = DEFAULT_CALIBRATION; mat3 intrinsic_matrix = fcam_intrinsic_matrix; + // Calibration constants + const float ecam_zoom = 2.0; + const float fcam_zoom = 1.1; + std::recursive_mutex frame_lock; std::deque> frames; uint32_t draw_frame_id = 0; From 2c44c8980c3893c01453049dd06a396e6f2358ad Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 25 May 2023 11:45:58 +0800 Subject: [PATCH 057/283] ui/MainWindow: use switch in eventFilter (#28276) --- selfdrive/ui/qt/window.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index 198b1edbf6..a1aa4b8315 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -79,11 +79,16 @@ void MainWindow::closeSettings() { } bool MainWindow::eventFilter(QObject *obj, QEvent *event) { - const static QSet evts({QEvent::MouseButtonPress, QEvent::MouseMove, - QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd}); - - if (evts.contains(event->type())) { - device.resetInteractiveTimout(); + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + device.resetInteractiveTimout(); + break; + default: + break; } return false; } From 634280ca5117a014cc7f2620e94ebc62c050d70e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 25 May 2023 11:46:27 +0800 Subject: [PATCH 058/283] ui: update DM icon at every frame (#28226) --- selfdrive/ui/qt/onroad.cc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 51c3f3dbbb..af07f179c4 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -281,14 +281,12 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { // update engageability/experimental mode button experimental_btn->updateState(s); - // update DM icons at 2Hz - if (sm.frame % (UI_FREQ / 2) == 0) { - setProperty("dmActive", sm["driverMonitoringState"].getDriverMonitoringState().getIsActiveMode()); - setProperty("rightHandDM", sm["driverMonitoringState"].getDriverMonitoringState().getIsRHD()); - } - + // update DM icon + auto dm_state = sm["driverMonitoringState"].getDriverMonitoringState(); + setProperty("dmActive", dm_state.getIsActiveMode()); + setProperty("rightHandDM", dm_state.getIsRHD()); // DM icon transition - dm_fade_state = fmax(0.0, fmin(1.0, dm_fade_state+0.2*(0.5-(float)(dmActive)))); + dm_fade_state = std::clamp(dm_fade_state+0.2*(0.5-dmActive), 0.0, 1.0); } void AnnotatedCameraWidget::drawHud(QPainter &p) { From dee7ced00ee7e8cdec883989958f43d94c01e4bb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 24 May 2023 20:46:44 -0700 Subject: [PATCH 059/283] controlsd: check longitudinalPlan avg freq (#28200) --- selfdrive/controls/controlsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 959740d97d..a1620194bd 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -87,7 +87,7 @@ class Controls: self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'testJoystick'] + self.camera_packets, - ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan', 'testJoystick']) + ignore_alive=ignore, ignore_avg_freq=['radarState', 'testJoystick']) if CI is None: # wait for one pandaState and one CAN packet From 75fc0291307e78ae6462e21a088e3229bca58305 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 24 May 2023 20:46:59 -0700 Subject: [PATCH 060/283] manager: clear onroad/offroad transition params on start (#28199) * clear onroad transition params * all offroad params also have manager start --- selfdrive/manager/manager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index a1efd564f0..c6b135935f 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -34,6 +34,8 @@ def manager_init() -> None: params = Params() params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) + params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) + params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) default_params: List[Tuple[str, Union[str, bytes]]] = [ ("CompletedTrainingVersion", "0"), From a26e6d1633b994029e67611f7954250517f71acd Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 25 May 2023 11:47:37 +0800 Subject: [PATCH 061/283] cabana: supports switching streams on the fly (#28081) * open stream * use std::atomic::exchange * emit streamStarted immediately --- tools/cabana/cabana.cc | 27 ++----- tools/cabana/chart/chartswidget.cc | 1 + tools/cabana/chart/chartswidget.h | 1 - tools/cabana/detailwidget.cc | 5 +- tools/cabana/detailwidget.h | 4 +- tools/cabana/mainwin.cc | 102 ++++++++++++++----------- tools/cabana/mainwin.h | 15 ++-- tools/cabana/messageswidget.cc | 17 ----- tools/cabana/messageswidget.h | 2 - tools/cabana/signalview.cc | 2 +- tools/cabana/streams/abstractstream.cc | 19 +++-- tools/cabana/streams/abstractstream.h | 12 ++- tools/cabana/streams/devicestream.cc | 5 +- tools/cabana/streams/livestream.cc | 11 +-- tools/cabana/streams/livestream.h | 2 +- tools/cabana/streams/pandastream.cc | 1 - tools/cabana/streams/replaystream.cc | 44 ++++------- tools/cabana/streams/replaystream.h | 4 +- tools/cabana/streamselector.cc | 27 +++++-- tools/cabana/streamselector.h | 4 +- tools/cabana/videowidget.cc | 45 ++++------- tools/cabana/videowidget.h | 5 -- 22 files changed, 164 insertions(+), 191 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 6e354da315..0215ec3c4e 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -1,7 +1,6 @@ #include #include -#include "common/prefix.h" #include "selfdrive/ui/qt/util.h" #include "tools/cabana/mainwin.h" #include "tools/cabana/streamselector.h" @@ -35,17 +34,15 @@ int main(int argc, char *argv[]) { QString dbc_file = cmd_parser.isSet("dbc") ? cmd_parser.value("dbc") : ""; - std::unique_ptr op_prefix; - std::unique_ptr stream; - + AbstractStream *stream = nullptr; if (cmd_parser.isSet("stream")) { - stream.reset(new DeviceStream(&app, cmd_parser.value("zmq"))); + stream = new DeviceStream(&app, cmd_parser.value("zmq")); } else if (cmd_parser.isSet("panda") || cmd_parser.isSet("panda-serial")) { PandaStreamConfig config = {}; if (cmd_parser.isSet("panda-serial")) { config.serial = cmd_parser.value("panda-serial"); } - stream.reset(new PandaStream(&app, config)); + stream = new PandaStream(&app, config); } else { uint32_t replay_flags = REPLAY_FLAG_NONE; if (cmd_parser.isSet("ecam")) { @@ -65,36 +62,26 @@ int main(int argc, char *argv[]) { } if (route.isEmpty()) { - AbstractStream *out_stream = nullptr; - StreamSelector dlg; - dlg.addStreamWidget(ReplayStream::widget(&out_stream)); - dlg.addStreamWidget(PandaStream::widget(&out_stream)); - dlg.addStreamWidget(DeviceStream::widget(&out_stream)); + StreamSelector dlg(&stream); if (!dlg.exec()) { return 0; } dbc_file = dlg.dbcFile(); - stream.reset(out_stream); } else { - // TODO: Remove when OpenpilotPrefix supports ZMQ -#ifndef __APPLE__ - op_prefix.reset(new OpenpilotPrefix()); -#endif auto replay_stream = new ReplayStream(&app); - stream.reset(replay_stream); if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { return 0; } + stream = replay_stream; } } MainWindow w; - - // Load DBC if (!dbc_file.isEmpty()) { w.loadFile(dbc_file); } - + assert(stream != nullptr); + stream->start(); w.show(); return app.exec(); } diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc index d244b0c6cc..567fceebad 100644 --- a/tools/cabana/chart/chartswidget.cc +++ b/tools/cabana/chart/chartswidget.cc @@ -398,6 +398,7 @@ void ChartsWidget::removeAll() { tabbar->removeTab(1); } tab_charts.clear(); + zoomReset(); if (!charts.isEmpty()) { for (auto c : charts) { diff --git a/tools/cabana/chart/chartswidget.h b/tools/cabana/chart/chartswidget.h index ee0c07292d..0d9f79062a 100644 --- a/tools/cabana/chart/chartswidget.h +++ b/tools/cabana/chart/chartswidget.h @@ -124,4 +124,3 @@ public: ChartsWidget *charts; std::pair prev_range, range; }; - diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 0feb4642f4..c05b76c878 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -5,6 +5,7 @@ #include #include "tools/cabana/commands.h" +#include "tools/cabana/mainwin.h" // DetailWidget @@ -218,7 +219,7 @@ void EditMessageDialog::validateName(const QString &text) { // CenterWidget -CenterWidget::CenterWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { +CenterWidget::CenterWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->addWidget(welcome_widget = createWelcomeWidget()); @@ -228,7 +229,7 @@ void CenterWidget::setMessage(const MessageId &msg_id) { if (!detail_widget) { delete welcome_widget; welcome_widget = nullptr; - layout()->addWidget(detail_widget = new DetailWidget(charts, this)); + layout()->addWidget(detail_widget = new DetailWidget(((MainWindow*)parentWidget())->charts_widget, this)); } detail_widget->setMessage(msg_id); } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index ce65adb34e..c4406bd39a 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -10,6 +10,7 @@ #include "tools/cabana/historylog.h" #include "tools/cabana/signalview.h" +class MainWindow; class EditMessageDialog : public QDialog { public: EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent); @@ -54,7 +55,7 @@ private: class CenterWidget : public QWidget { Q_OBJECT public: - CenterWidget(ChartsWidget* charts, QWidget *parent); + CenterWidget(QWidget *parent); void setMessage(const MessageId &msg_id); void clear(); @@ -62,5 +63,4 @@ private: QWidget *createWelcomeWidget(); DetailWidget *detail_widget = nullptr; QWidget *welcome_widget = nullptr; - ChartsWidget *charts; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 7b2d23a3f9..1f5a13aebb 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -18,7 +18,6 @@ #include "tools/cabana/commands.h" #include "tools/cabana/streamselector.h" -#include "tools/cabana/streams/replaystream.h" #include "tools/cabana/tools/findsignal.h" static MainWindow *main_win = nullptr; @@ -29,8 +28,7 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const MainWindow::MainWindow() : QMainWindow() { createDockWindows(); - center_widget = new CenterWidget(charts_widget, this); - setCentralWidget(center_widget); + setCentralWidget(center_widget = new CenterWidget(this)); createActions(); createStatusBar(); createShortcuts(); @@ -68,23 +66,18 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(this, &MainWindow::showMessage, statusBar(), &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); - QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); - QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); - QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::streamStarted); - QObject::connect(can, &AbstractStream::sourcesUpdated, dbc(), &DBCManager::updateSources); - QObject::connect(can, &AbstractStream::sourcesUpdated, this, &MainWindow::updateLoadSaveMenus); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MainWindow::undoStackIndexChanged); QObject::connect(&settings, &Settings::changed, this, &MainWindow::updateStatus); + QObject::connect(StreamNotifier::instance(), &StreamNotifier::changingStream, this, &MainWindow::changingStream); + QObject::connect(StreamNotifier::instance(), &StreamNotifier::streamStarted, this, &MainWindow::streamStarted); } void MainWindow::createActions() { QMenu *file_menu = menuBar()->addMenu(tr("&File")); - if (!can->liveStreaming()) { - file_menu->addAction(tr("Open Route..."), this, &MainWindow::openRoute); - file_menu->addSeparator(); - } + file_menu->addAction(tr("Open Stream..."), this, &MainWindow::openStream); + file_menu->addSeparator(); file_menu->addAction(tr("New DBC File"), [this]() { newFile(); })->setShortcuts(QKeySequence::New); file_menu->addAction(tr("Open DBC File..."), [this]() { openFile(); })->setShortcuts(QKeySequence::Open); @@ -151,14 +144,22 @@ void MainWindow::createActions() { } void MainWindow::createDockWindows() { - // left panel + messages_dock = new QDockWidget(tr("MESSAGES"), this); + messages_dock->setObjectName("MessagesPanel"); + messages_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + messages_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + addDockWidget(Qt::LeftDockWidgetArea, messages_dock); + + video_dock = new QDockWidget("", this); + video_dock->setObjectName(tr("VideoPanel")); + video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + addDockWidget(Qt::RightDockWidgetArea, video_dock); +} + +void MainWindow::createDockWidgets() { messages_widget = new MessagesWidget(this); - QDockWidget *dock = new QDockWidget(tr("MESSAGES"), this); - dock->setObjectName("MessagesPanel"); - dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); - dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); - dock->setWidget(messages_widget); - addDockWidget(Qt::LeftDockWidgetArea, dock); + messages_dock->setWidget(messages_widget); // right panel charts_widget = new ChartsWidget(this); @@ -176,17 +177,8 @@ void MainWindow::createDockWindows() { video_splitter->addWidget(charts_container); video_splitter->setStretchFactor(1, 1); video_splitter->restoreState(settings.video_splitter_state); - if (can->liveStreaming() || video_splitter->sizes()[0] == 0) { - // display video at minimum size. - video_splitter->setSizes({1, 1}); - } - - video_dock = new QDockWidget(can->routeName(), this); - video_dock->setObjectName(tr("VideoPanel")); - video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); video_dock->setWidget(video_splitter); - addDockWidget(Qt::RightDockWidgetArea, video_dock); + QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); } void MainWindow::createStatusBar() { @@ -242,15 +234,15 @@ void MainWindow::DBCFileChanged() { updateLoadSaveMenus(); } -void MainWindow::openRoute() { - StreamSelector dlg(this); - dlg.addStreamWidget(ReplayStream::widget(&can)); +void MainWindow::openStream() { + AbstractStream *stream = nullptr; + StreamSelector dlg(&stream, this); if (dlg.exec()) { - center_widget->clear(); - charts_widget->removeAll(); + if (!dlg.dbcFile().isEmpty()) { + loadFile(dlg.dbcFile()); + } + stream->start(); statusBar()->showMessage(tr("Route %1 loaded").arg(can->routeName()), 2000); - } else if (dlg.failed()) { - close(); } } @@ -319,24 +311,42 @@ void MainWindow::loadFromClipboard(SourceSet s, bool close_all) { } } -void MainWindow::streamStarted() { - auto fingerprint = can->carFingerprint(); - if (can->liveStreaming()) { - video_dock->setWindowTitle(can->routeName()); - } else { - video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPRINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); - } +void MainWindow::changingStream() { + center_widget->clear(); + delete messages_widget; + delete video_splitter; +} +void MainWindow::streamStarted() { + createDockWidgets(); + + video_dock->setWindowTitle(can->routeName()); + if (can->liveStreaming() || video_splitter->sizes()[0] == 0) { + // display video at minimum size. + video_splitter->setSizes({1, 1}); + } // Don't overwrite already loaded DBC if (!dbc()->msgCount()) { - if (!fingerprint.isEmpty()) { + newFile(); + } + + QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); + QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::eventsMerged); + QObject::connect(can, &AbstractStream::sourcesUpdated, dbc(), &DBCManager::updateSources); + QObject::connect(can, &AbstractStream::sourcesUpdated, this, &MainWindow::updateLoadSaveMenus); +} + +void MainWindow::eventsMerged() { + if (!can->liveStreaming()) { + auto fingerprint = can->carFingerprint(); + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPRINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); + // Don't overwrite already loaded DBC + if (!dbc()->msgCount() && !fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { loadDBCFromOpendbc(dbc_name.toString()); - return; } } - newFile(); } } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 9db999e6c9..e227ce593f 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -22,14 +22,17 @@ public: void dockCharts(bool dock); void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); } void loadFile(const QString &fn, SourceSet s = SOURCE_ALL); + ChartsWidget *charts_widget = nullptr; public slots: - void openRoute(); + void openStream(); + void changingStream(); + void streamStarted(); + void newFile(SourceSet s = SOURCE_ALL); void openFile(SourceSet s = SOURCE_ALL); void openRecentFile(); void loadDBCFromOpendbc(const QString &name); - void streamStarted(); void save(); void saveAs(); void saveToClipboard(); @@ -67,18 +70,20 @@ protected: void toggleFullScreen(); void updateStatus(); void updateLoadSaveMenus(); + void createDockWidgets(); + void eventsMerged(); VideoWidget *video_widget = nullptr; QDockWidget *video_dock; - MessagesWidget *messages_widget; + QDockWidget *messages_dock; + MessagesWidget *messages_widget = nullptr; CenterWidget *center_widget; - ChartsWidget *charts_widget; QWidget *floating_window = nullptr; QVBoxLayout *charts_layout; QProgressBar *progress_bar; QLabel *status_label; QJsonDocument fingerprint_to_dbc; - QSplitter *video_splitter;; + QSplitter *video_splitter = nullptr; enum { MAX_RECENT_FILES = 15 }; QAction *recent_files_acts[MAX_RECENT_FILES] = {}; QMenu *open_recent_menu = nullptr; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 60aadb3673..76bd1d6a0e 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -81,7 +81,6 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { settings.suppress_defined_signals = (state == Qt::Checked); }); QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); - QObject::connect(can, &AbstractStream::streamStarted, this, &MessagesWidget::reset); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MessagesWidget::dbcModified); QObject::connect(dbc(), &DBCManager::msgUpdated, this, &MessagesWidget::dbcModified); QObject::connect(dbc(), &DBCManager::msgRemoved, this, &MessagesWidget::dbcModified); @@ -146,14 +145,6 @@ void MessagesWidget::updateSuppressedButtons() { } } -void MessagesWidget::reset() { - current_msg_id = std::nullopt; - view->selectionModel()->clear(); - model->reset(); - updateSuppressedButtons(); -} - - // MessageListModel QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -419,14 +410,6 @@ void MessageListModel::clearSuppress() { suppressed_bytes.clear(); } -void MessageListModel::reset() { - beginResetModel(); - filter_str.clear(); - msgs.clear(); - clearSuppress(); - endResetModel(); -} - void MessageListModel::forceResetModel() { beginResetModel(); endResetModel(); diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 036758e636..1a217656b2 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -38,7 +38,6 @@ public: void fetchData(); void suppress(); void clearSuppress(); - void reset(); void forceResetModel(); void dbcModified(); std::vector msgs; @@ -100,7 +99,6 @@ public: QByteArray saveHeaderState() const { return view->header()->saveState(); } bool restoreHeaderState(const QByteArray &state) const { return view->header()->restoreState(state); } void updateSuppressedButtons(); - void reset(); public slots: void dbcModified(); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 45bc740859..0b74455d7c 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -481,10 +481,10 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); QObject::connect(dbc(), &DBCManager::signalAdded, [this](MessageId id, const cabana::Signal *sig) { selectSignal(sig); }); - QObject::connect(can, &AbstractStream::msgsReceived, this, &SignalView::updateState); QObject::connect(dbc(), &DBCManager::signalUpdated, this, &SignalView::handleSignalUpdated); QObject::connect(tree->verticalScrollBar(), &QScrollBar::valueChanged, [this]() { updateState(); }); QObject::connect(tree->verticalScrollBar(), &QScrollBar::rangeChanged, [this]() { updateState(); }); + QObject::connect(can, &AbstractStream::msgsReceived, this, &SignalView::updateState); setWhatsThis(tr(R"( Signal view
diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 701ecbb258..dc23421a8c 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -4,10 +4,20 @@ AbstractStream *can = nullptr; -AbstractStream::AbstractStream(QObject *parent) : QObject(parent) { - can = this; - new_msgs = std::make_unique>(); +StreamNotifier *StreamNotifier::instance() { + static StreamNotifier notifier; + return ¬ifier; +} + +AbstractStream::AbstractStream(QObject *parent) : new_msgs(new QHash()), QObject(parent) { + assert(parent != nullptr); QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); + QObject::connect(this, &AbstractStream::streamStarted, [this]() { + emit StreamNotifier::instance()->changingStream(); + delete can; + can = this; + emit StreamNotifier::instance()->streamStarted(); + }); } void AbstractStream::updateMessages(QHash *messages) { @@ -37,8 +47,7 @@ void AbstractStream::updateEvent(const MessageId &id, double sec, const uint8_t bool AbstractStream::postEvents() { // delay posting CAN message if UI thread is busy - if (!processing) { - processing = true; + if (processing.exchange(true) == false) { for (auto it = new_msgs->begin(); it != new_msgs->end(); ++it) { it.value() = all_msgs[it.key()]; } diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 9b317b3ed6..57e6c3cf1a 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -40,6 +40,7 @@ class AbstractStream : public QObject { public: AbstractStream(QObject *parent); virtual ~AbstractStream() {}; + virtual void start() = 0; inline bool liveStreaming() const { return route() == nullptr; } virtual void seekTo(double ts) {} virtual QString routeName() const = 0; @@ -90,7 +91,6 @@ protected: }; class AbstractOpenStreamWidget : public QWidget { - Q_OBJECT public: AbstractOpenStreamWidget(AbstractStream **stream, QWidget *parent = nullptr) : stream(stream), QWidget(parent) {} virtual bool open() = 0; @@ -100,5 +100,15 @@ protected: AbstractStream **stream = nullptr; }; +class StreamNotifier : public QObject { + Q_OBJECT +public: + StreamNotifier(QObject *parent = nullptr) : QObject(parent) {} + static StreamNotifier* instance(); +signals: + void streamStarted(); + void changingStream(); +}; + // A global pointer referring to the unique AbstractStream object extern AbstractStream *can; diff --git a/tools/cabana/streams/devicestream.cc b/tools/cabana/streams/devicestream.cc index 5bbe527773..5631f64d68 100644 --- a/tools/cabana/streams/devicestream.cc +++ b/tools/cabana/streams/devicestream.cc @@ -9,13 +9,10 @@ // DeviceStream DeviceStream::DeviceStream(QObject *parent, QString address) : zmq_address(address), LiveStream(parent) { - startStreamThread(); } void DeviceStream::streamThread() { - if (!zmq_address.isEmpty()) { - setenv("ZMQ", "1", 1); - } + zmq_address.isEmpty() ? unsetenv("ZMQ") : setenv("ZMQ", "1", 1); std::unique_ptr context(Context::create()); std::string address = zmq_address.isEmpty() ? "127.0.0.1" : zmq_address.toStdString(); diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 6546860089..6ad929b2ee 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -1,7 +1,5 @@ #include "tools/cabana/streams/livestream.h" -#include - LiveStream::LiveStream(QObject *parent) : AbstractStream(parent) { if (settings.log_livestream) { std::string path = (settings.log_path + "/" + QDateTime::currentDateTime().toString("yyyy-MM-dd--hh-mm-ss") + "--0").toStdString(); @@ -21,11 +19,9 @@ void LiveStream::startUpdateTimer() { timer_id = update_timer.timerId(); } -void LiveStream::startStreamThread() { - // delay the start of the thread to avoid calling startStreamThread - // in the constructor when other classes' slots have not been connected to - // the signals of the livestream. - QTimer::singleShot(0, [this]() { stream_thread->start(); }); +void LiveStream::start() { + emit streamStarted(); + stream_thread->start(); startUpdateTimer(); } @@ -71,7 +67,6 @@ void LiveStream::updateEvents() { if (first_update_ts == 0) { first_update_ts = nanos_since_boot(); first_event_ts = current_event_ts = all_events_.back()->mono_time; - emit streamStarted(); } if (paused_ || prev_speed != speed_) { diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 87ba7a0133..577074b415 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -10,6 +10,7 @@ class LiveStream : public AbstractStream { public: LiveStream(QObject *parent); virtual ~LiveStream(); + void start() override; inline double routeStartTime() const override { return begin_event_ts / 1e9; } inline double currentSec() const override { return (current_event_ts - begin_event_ts) / 1e9; } void setSpeed(float speed) override { speed_ = speed; } @@ -20,7 +21,6 @@ public: protected: virtual void streamThread() = 0; - void startStreamThread(); void handleEvent(const char *data, const size_t size); private: diff --git a/tools/cabana/streams/pandastream.cc b/tools/cabana/streams/pandastream.cc index 5b3bf890e8..275ed84f43 100644 --- a/tools/cabana/streams/pandastream.cc +++ b/tools/cabana/streams/pandastream.cc @@ -20,7 +20,6 @@ PandaStream::PandaStream(QObject *parent, PandaStreamConfig config_) : config(co if (!connect()) { throw std::runtime_error("Failed to connect to panda"); } - startStreamThread(); } bool PandaStream::connect() { diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 46103764be..b5ea44be0c 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -6,18 +6,17 @@ #include #include -#include "common/prefix.h" - ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent) { + unsetenv("ZMQ"); + // TODO: Remove when OpenpilotPrefix supports ZMQ +#ifndef __APPLE__ + op_prefix = std::make_unique(); +#endif QObject::connect(&settings, &Settings::changed, [this]() { if (replay) replay->setSegmentCacheLimit(settings.max_cached_minutes); }); } -ReplayStream::~ReplayStream() { - if (replay) replay->stop(); -} - static bool event_filter(const Event *e, void *opaque) { return ((ReplayStream *)opaque)->eventFilter(e); } @@ -37,13 +36,13 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint replay->setSegmentCacheLimit(settings.max_cached_minutes); replay->installEventFilter(event_filter, this); QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo); - QObject::connect(replay.get(), &Replay::streamStarted, this, &AbstractStream::streamStarted); QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments); - if (replay->load()) { - replay->start(); - return true; - } - return false; + return replay->load(); +} + +void ReplayStream::start() { + emit streamStarted(); + replay->start(); } bool ReplayStream::eventFilter(const Event *event) { @@ -78,8 +77,6 @@ AbstractOpenStreamWidget *ReplayStream::widget(AbstractStream **stream) { // OpenReplayWidget -static std::unique_ptr op_prefix; - OpenReplayWidget::OpenReplayWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { // TODO: get route list from api.comma.ai QGridLayout *grid_layout = new QGridLayout(); @@ -118,26 +115,17 @@ bool OpenReplayWidget::open() { route = route.mid(idx + 1); } - bool ret = false; bool is_valid_format = Route::parseRoute(route).str.size() > 0; if (!is_valid_format) { QMessageBox::warning(nullptr, tr("Warning"), tr("Invalid route format: '%1'").arg(route)); } else { - // TODO: Remove when OpenpilotPrefix supports ZMQ -#ifndef __APPLE__ - op_prefix.reset(new OpenpilotPrefix()); -#endif uint32_t flags[] = {REPLAY_FLAG_NO_VIPC, REPLAY_FLAG_NONE, REPLAY_FLAG_ECAM, REPLAY_FLAG_DCAM, REPLAY_FLAG_QCAMERA}; - ReplayStream *replay_stream = *stream ? (ReplayStream *)*stream : new ReplayStream(qApp); - ret = replay_stream->loadRoute(route, data_dir, flags[choose_video_cb->currentIndex()]); - if (!ret) { - if (replay_stream != *stream) { - delete replay_stream; - } - QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to load route: '%1'").arg(route)); + auto replay_stream = std::make_unique(qApp); + if (replay_stream->loadRoute(route, data_dir, flags[choose_video_cb->currentIndex()])) { + *stream = replay_stream.release(); } else { - *stream = replay_stream; + QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to load route: '%1'").arg(route)); } } - return ret; + return *stream != nullptr; } diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index aefc763d20..a5705a14a6 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -1,5 +1,6 @@ #pragma once +#include "common/prefix.h" #include "tools/cabana/streams/abstractstream.h" class ReplayStream : public AbstractStream { @@ -7,7 +8,7 @@ class ReplayStream : public AbstractStream { public: ReplayStream(QObject *parent); - ~ReplayStream(); + void start() override; bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); bool eventFilter(const Event *event); void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); }; @@ -29,6 +30,7 @@ private: void mergeSegments(); std::unique_ptr replay = nullptr; std::set processed_segments; + std::unique_ptr op_prefix; }; class OpenReplayWidget : public AbstractOpenStreamWidget { diff --git a/tools/cabana/streamselector.cc b/tools/cabana/streamselector.cc index bfd6ff24d9..6da44ecd1a 100644 --- a/tools/cabana/streamselector.cc +++ b/tools/cabana/streamselector.cc @@ -6,13 +6,19 @@ #include #include -StreamSelector::StreamSelector(QWidget *parent) : QDialog(parent) { +#include "tools/cabana/streams/devicestream.h" +#include "tools/cabana/streams/pandastream.h" +#include "tools/cabana/streams/replaystream.h" + +StreamSelector::StreamSelector(AbstractStream **stream, QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Open stream")); QVBoxLayout *main_layout = new QVBoxLayout(this); + QWidget *w = new QWidget(this); + QVBoxLayout *layout = new QVBoxLayout(w); tab = new QTabWidget(this); tab->setTabBarAutoHide(true); - main_layout->addWidget(tab); + layout->addWidget(tab); QHBoxLayout *dbc_layout = new QHBoxLayout(); dbc_file = new QLineEdit(this); @@ -22,20 +28,29 @@ StreamSelector::StreamSelector(QWidget *parent) : QDialog(parent) { dbc_layout->addWidget(new QLabel(tr("dbc File"))); dbc_layout->addWidget(dbc_file); dbc_layout->addWidget(file_btn); - main_layout->addLayout(dbc_layout); + layout->addLayout(dbc_layout); QFrame *line = new QFrame(this); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); - main_layout->addWidget(line); + layout->addWidget(line); + main_layout->addWidget(w); auto btn_box = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel); main_layout->addWidget(btn_box); + addStreamWidget(ReplayStream::widget(stream)); + addStreamWidget(PandaStream::widget(stream)); + addStreamWidget(DeviceStream::widget(stream)); + QObject::connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); QObject::connect(btn_box, &QDialogButtonBox::accepted, [=]() { - success = ((AbstractOpenStreamWidget *)tab->currentWidget())->open(); - if (success) { + btn_box->button(QDialogButtonBox::Open)->setEnabled(false); + w->setEnabled(false); + if (((AbstractOpenStreamWidget *)tab->currentWidget())->open()) { accept(); + } else { + btn_box->button(QDialogButtonBox::Open)->setEnabled(true); + w->setEnabled(true); } }); QObject::connect(file_btn, &QPushButton::clicked, [this]() { diff --git a/tools/cabana/streamselector.h b/tools/cabana/streamselector.h index ecd0e8530c..19b438d55a 100644 --- a/tools/cabana/streamselector.h +++ b/tools/cabana/streamselector.h @@ -10,13 +10,11 @@ class StreamSelector : public QDialog { Q_OBJECT public: - StreamSelector(QWidget *parent = nullptr); + StreamSelector(AbstractStream **stream, QWidget *parent = nullptr); void addStreamWidget(AbstractOpenStreamWidget *w); QString dbcFile() const { return dbc_file->text(); } - inline bool failed() const { return !success; } private: QLineEdit *dbc_file; QTabWidget *tab; - bool success = true; }; diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 846a83c24c..ed0704a676 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -1,10 +1,12 @@ #include "tools/cabana/videowidget.h" #include +#include #include #include #include #include +#include #include #include @@ -20,18 +22,6 @@ static const QColor timeline_colors[] = { [(int)TimelineType::AlertCritical] = QColor(199, 0, 57), }; -bool sortTimelineBasedOnEventPriority(const std::tuple &left, const std::tuple &right){ - const static std::map timelinePriority = { - { TimelineType::None, 0 }, - { TimelineType::Engaged, 10 }, - { TimelineType::AlertInfo, 20 }, - { TimelineType::AlertWarning, 30 }, - { TimelineType::AlertCritical, 40 }, - { TimelineType::UserFlag, 35 } - }; - return timelinePriority.at(std::get<2>(left)) < timelinePriority.at(std::get<2>(right)); -} - VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); auto main_layout = new QVBoxLayout(this); @@ -100,7 +90,7 @@ QWidget *VideoWidget::createCameraWidget() { l->addLayout(stacked); // slider controls - slider_layout = new QHBoxLayout(); + auto slider_layout = new QHBoxLayout(); time_label = new QLabel("00:00"); slider_layout->addWidget(time_label); @@ -111,12 +101,13 @@ QWidget *VideoWidget::createCameraWidget() { end_time_label = new QLabel(this); slider_layout->addWidget(end_time_label); l->addLayout(slider_layout); + + setMaximumTime(can->totalSeconds()); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); }); QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(utils::formatSeconds(value / 1000)); }); QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); - QObject::connect(can, &AbstractStream::streamStarted, [this]() { setMaximumTime(can->totalSeconds()); }); return w; } @@ -157,14 +148,16 @@ void VideoWidget::updatePlayBtnState() { } // Slider -Slider::Slider(QWidget *parent) : timer(this), thumbnail_label(parent), QSlider(Qt::Horizontal, parent) { - timer.callOnTimeout([this]() { +Slider::Slider(QWidget *parent) : thumbnail_label(parent), QSlider(Qt::Horizontal, parent) { + setMouseTracking(true); + auto timer = new QTimer(this); + timer->callOnTimeout([this]() { timeline = can->getTimeline(); - std::sort(timeline.begin(), timeline.end(), sortTimelineBasedOnEventPriority); + std::sort(timeline.begin(), timeline.end(), [](auto &l, auto &r) { return std::get<2>(l) < std::get<2>(r); }); update(); }); - setMouseTracking(true); - QObject::connect(can, &AbstractStream::streamStarted, this, &Slider::streamStarted); + timer->start(2000); + thumnail_future = QtConcurrent::run(this, &Slider::loadThumbnails); } Slider::~Slider() { @@ -172,16 +165,6 @@ Slider::~Slider() { thumnail_future.waitForFinished(); } -void Slider::streamStarted() { - abort_load_thumbnail = true; - thumnail_future.waitForFinished(); - abort_load_thumbnail = false; - thumbnails.clear(); - timeline.clear(); - timer.start(2000); - thumnail_future = QtConcurrent::run(this, &Slider::loadThumbnails); -} - void Slider::loadThumbnails() { const auto &segments = can->route()->segments(); double max_time = 0; @@ -318,9 +301,7 @@ void InfoLabel::showAlert(const AlertInfo &alert) { alert_info = alert; pixmap = {}; setVisible(!alert_info.text1.isEmpty()); - if (isVisible()) { - update(); - } + update(); } void InfoLabel::paintEvent(QPaintEvent *event) { diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index c2ec759919..59bc112bd0 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -3,12 +3,10 @@ #include #include -#include #include #include #include #include -#include #include "selfdrive/ui/qt/widgets/cameraview.h" #include "tools/cabana/streams/abstractstream.h" @@ -46,7 +44,6 @@ private: bool event(QEvent *event) override; void sliderChange(QAbstractSlider::SliderChange change) override; void paintEvent(QPaintEvent *ev) override; - void streamStarted(); void loadThumbnails(); double max_sec = 0; @@ -58,7 +55,6 @@ private: std::map alerts; QFuture thumnail_future; InfoLabel thumbnail_label; - QTimer timer; friend class VideoWidget; }; @@ -79,7 +75,6 @@ protected: double maximum_time = 0; QLabel *end_time_label; QLabel *time_label; - QHBoxLayout *slider_layout; QPushButton *play_btn; InfoLabel *alert_label; Slider *slider; From 2bd37acef37f2526c562865eddeaf0b5cd856a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 25 May 2023 07:41:45 +0200 Subject: [PATCH 062/283] ubloxd: enable satReport parsing (#28037) * Uncomment satReport parsing. New ublox recv callback logic in process_replay * Typo * Update replay ref commit * Update ref commit again --- selfdrive/test/process_replay/ref_commit | 2 +- system/ubloxd/ublox_msg.cc | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 802d936bc9..dfb9106b8b 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5c68f066452f7fcfb315abc5cb9b7a50794fbd3f +02b8c1e21f2bd3551aa4a2b94c73dcac762d3148 diff --git a/system/ubloxd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc index a01187d560..92a2ba678c 100644 --- a/system/ubloxd/ublox_msg.cc +++ b/system/ubloxd/ublox_msg.cc @@ -112,8 +112,7 @@ std::pair> UbloxMsgParser::gen_msg() { case 0x0a0b: return {"ubloxGnss", gen_mon_hw2(static_cast(body))}; case 0x0135: - // TODO return {"ubloxGnss", gen_nav_sat(static_cast(body))}; - return {"ubloxGnss", kj::Array()}; + return {"ubloxGnss", gen_nav_sat(static_cast(body))}; default: LOGE("Unknown message type %x", ubx_message.msg_type()); return {"ubloxGnss", kj::Array()}; From 488975f06ec6a282e023dbd5db9e265299458f4c Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 24 May 2023 22:44:10 -0700 Subject: [PATCH 063/283] UI: add missing QPushButton pressed styles (#28289) * UI: add missing QPushButton pressed styles * keyboard is special --- selfdrive/ui/qt/offroad/onboarding.cc | 3 +++ selfdrive/ui/qt/setup/reset.cc | 12 +++++++++++- selfdrive/ui/qt/setup/updater.cc | 12 +++++++++++- selfdrive/ui/qt/widgets/input.cc | 13 +++++++++---- selfdrive/ui/qt/widgets/keyboard.cc | 9 ++++++++- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc index 64cb357994..72c341fdf9 100644 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ b/selfdrive/ui/qt/offroad/onboarding.cc @@ -111,6 +111,9 @@ void TermsPage::showEvent(QShowEvent *event) { QPushButton { background-color: #465BEA; } + QPushButton:pressed { + background-color: #3049F4; + } QPushButton:disabled { background-color: #4F4F4F; } diff --git a/selfdrive/ui/qt/setup/reset.cc b/selfdrive/ui/qt/setup/reset.cc index ccf9bf8053..7999dd640b 100644 --- a/selfdrive/ui/qt/setup/reset.cc +++ b/selfdrive/ui/qt/setup/reset.cc @@ -79,7 +79,14 @@ Reset::Reset(ResetMode mode, QWidget *parent) : QWidget(parent) { #endif confirmBtn = new QPushButton(tr("Confirm")); - confirmBtn->setStyleSheet("background-color: #465BEA;"); + confirmBtn->setStyleSheet(R"( + QPushButton { + background-color: #465BEA; + } + QPushButton:pressed { + background-color: #3049F4; + } + )"); blayout->addWidget(confirmBtn); QObject::connect(confirmBtn, &QPushButton::clicked, this, &Reset::confirm); @@ -111,6 +118,9 @@ Reset::Reset(ResetMode mode, QWidget *parent) : QWidget(parent) { border-radius: 10px; background-color: #333333; } + QPushButton:pressed { + background-color: #444444; + } )"); } diff --git a/selfdrive/ui/qt/setup/updater.cc b/selfdrive/ui/qt/setup/updater.cc index fd7148c534..ae5f26c77e 100644 --- a/selfdrive/ui/qt/setup/updater.cc +++ b/selfdrive/ui/qt/setup/updater.cc @@ -46,7 +46,14 @@ Updater::Updater(const QString &updater_path, const QString &manifest_path, QWid QPushButton *install = new QPushButton(tr("Install")); install->setObjectName("navBtn"); - install->setStyleSheet("background-color: #465BEA;"); + install->setStyleSheet(R"( + QPushButton { + background-color: #465BEA; + } + QPushButton:pressed { + background-color: #3049F4; + } + )"); QObject::connect(install, &QPushButton::clicked, this, &Updater::installUpdate); hlayout->addWidget(install); } @@ -124,6 +131,9 @@ Updater::Updater(const QString &updater_path, const QString &manifest_path, QWid border-radius: 10px; background-color: #333333; } + QPushButton#navBtn:pressed { + background-color: #444444; + } QProgressBar { border: none; background-color: #292929; diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index 2026a70478..49fbdff222 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -71,10 +71,15 @@ InputDialog::InputDialog(const QString &title, QWidget *parent, const QString &s QPushButton* cancel_btn = new QPushButton(tr("Cancel")); cancel_btn->setFixedSize(386, 125); cancel_btn->setStyleSheet(R"( - font-size: 48px; - border-radius: 10px; - color: #E4E4E4; - background-color: #444444; + QPushButton { + font-size: 48px; + border-radius: 10px; + color: #E4E4E4; + background-color: #333333; + } + QPushButton:pressed { + background-color: #444444; + } )"); header_layout->addWidget(cancel_btn, 0, Qt::AlignRight); QObject::connect(cancel_btn, &QPushButton::clicked, this, &InputDialog::reject); diff --git a/selfdrive/ui/qt/widgets/keyboard.cc b/selfdrive/ui/qt/widgets/keyboard.cc index 1c59686535..162d27db02 100644 --- a/selfdrive/ui/qt/widgets/keyboard.cc +++ b/selfdrive/ui/qt/widgets/keyboard.cc @@ -59,7 +59,14 @@ KeyboardLayout::KeyboardLayout(QWidget* parent, const std::vectorsetAutoRepeat(true); } else if (p == ENTER_KEY) { - btn->setStyleSheet("background-color: #465BEA;"); + btn->setStyleSheet(R"( + QPushButton { + background-color: #465BEA; + } + QPushButton:pressed { + background-color: #444444; + } + )"); } btn->setFixedHeight(135 + key_spacing_vertical); btn_group->addButton(btn); From 2f625f64f003fdb785cfa75d5e8e714e321166f0 Mon Sep 17 00:00:00 2001 From: wileytom65 Date: Wed, 24 May 2023 23:06:54 -0800 Subject: [PATCH 064/283] Car Port for Hyundai Santa FE Hybrid 2023 (non-HDA2) (#28279) * Added 2023 Hyundai Santa Fe HEV * Added 2023 Hyundai Sante_FE_HEV Additional info added for 2023my of Hyundai SANTA_FE_HEV (nonHDA2) * fix FW versions * update docs --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c783bb8af2..37064537a1 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -92,7 +92,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| |Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai D connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| |Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| |Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| |Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 21c63338f5..bbfeca9b0e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -169,7 +169,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", car_parts=CarParts.common([CarPart.hyundai_i])), # TODO: check packages CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", car_parts=CarParts.common([CarPart.hyundai_d])), CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="https://youtu.be/VnHzSTygTS4", car_parts=CarParts.common([CarPart.hyundai_l])), - CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", car_parts=CarParts.common([CarPart.hyundai_l])), + CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_l])), CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarPart.hyundai_l])), CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", car_parts=CarParts.common([CarPart.hyundai_a])), CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarPart.hyundai_e])), @@ -851,18 +851,22 @@ FW_VERSIONS = { (Ecu.eps, 0x7d4, None): [ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102', b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105', + b'\xf1\x00TM MDPS C 1.00 1.02 56310-GA000 4TSHA100', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00TMH MFC AT EUR LHD 1.00 1.06 99211-S1500 220727', b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224', + b'\xf1\x00TMA MFC AT USA LHD 1.00 1.03 99211-S2500 220414', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2H16SA3\xa3\x1b\xe14', b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2H16UA3I\x94\xac\x8f', b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TTM2H16SA2\x80\xd7l\xb2', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x87391312MTC1', b'\xf1\x87391312MTE0', + b'\xf1\x87391312MTL0', ], }, CAR.SANTA_FE_PHEV_2022: { From 53190e926c7320f95a108874ab44536ca57a7cfd Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 May 2023 01:50:36 +0800 Subject: [PATCH 065/283] cabana/MessageViewHeader: fixed header position issue (#28291) --- tools/cabana/messageswidget.cc | 31 +++++++++++-------------------- tools/cabana/messageswidget.h | 1 - 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 76bd1d6a0e..0a44cb931c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -491,22 +491,6 @@ MessageViewHeader::MessageViewHeader(QWidget *parent, MessageListModel *model) : QObject::connect(this, &QHeaderView::sectionMoved, this, &MessageViewHeader::updateHeaderPositions); } -void MessageViewHeader::showEvent(QShowEvent *e) { - - for (int i = 0; i < count(); i++) { - if (!editors[i]) { - QString column_name = model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); - editors[i] = new QLineEdit(this); - editors[i]->setClearButtonEnabled(true); - editors[i]->setPlaceholderText(tr("Filter %1").arg(column_name)); - - QObject::connect(editors[i], &QLineEdit::textChanged, this, &MessageViewHeader::updateFilters); - } - editors[i]->show(); - } - QHeaderView::showEvent(e); -} - void MessageViewHeader::updateFilters() { QMap filters; for (int i = 0; i < count(); i++) { @@ -539,11 +523,18 @@ void MessageViewHeader::updateHeaderPositions() { } void MessageViewHeader::updateGeometries() { - if (editors[0]) { - setViewportMargins(0, 0, 0, editors[0]->sizeHint().height()); - } else { - setViewportMargins(0, 0, 0, 0); + for (int i = 0; i < count(); i++) { + if (!editors[i]) { + QString column_name = model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); + editors[i] = new QLineEdit(this); + editors[i]->setClearButtonEnabled(true); + editors[i]->setPlaceholderText(tr("Filter %1").arg(column_name)); + + QObject::connect(editors[i], &QLineEdit::textChanged, this, &MessageViewHeader::updateFilters); + } } + setViewportMargins(0, 0, 0, editors[0] ? editors[0]->sizeHint().height() : 0); + QHeaderView::updateGeometries(); updateHeaderPositions(); } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 1a217656b2..57011e51b4 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -70,7 +70,6 @@ class MessageViewHeader : public QHeaderView { Q_OBJECT public: MessageViewHeader(QWidget *parent, MessageListModel *model); - void showEvent(QShowEvent *e) override; void updateHeaderPositions(); void updateGeometries() override; From d5d1ca11d4a5ba5ffcb067fd842540d5334e9360 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 May 2023 01:51:28 +0800 Subject: [PATCH 066/283] cabana: support editing dbc files without a stream (#28294) * no stream mode * disable tools menu if no stream * disable splitter * cleanup * refactor matchMessage --- tools/cabana/cabana.cc | 10 +-- tools/cabana/dbc/dbcmanager.cc | 17 +--- tools/cabana/dbc/dbcmanager.h | 1 - tools/cabana/mainwin.cc | 19 ++++- tools/cabana/mainwin.h | 4 + tools/cabana/messageswidget.cc | 116 +++++++------------------- tools/cabana/streams/abstractstream.h | 9 ++ tools/cabana/tools/findsimilarbits.cc | 6 +- 8 files changed, 70 insertions(+), 112 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 0215ec3c4e..0a4b9eb112 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -63,9 +63,7 @@ int main(int argc, char *argv[]) { if (route.isEmpty()) { StreamSelector dlg(&stream); - if (!dlg.exec()) { - return 0; - } + dlg.exec(); dbc_file = dlg.dbcFile(); } else { auto replay_stream = new ReplayStream(&app); @@ -77,11 +75,13 @@ int main(int argc, char *argv[]) { } MainWindow w; + if (!stream) { + stream = new DummyStream(&app); + } + stream->start(); if (!dbc_file.isEmpty()) { w.loadFile(dbc_file); } - assert(stream != nullptr); - stream->start(); w.show(); return app.exec(); } diff --git a/tools/cabana/dbc/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc index 9667dd8f2a..000035bd2c 100644 --- a/tools/cabana/dbc/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -1,12 +1,5 @@ #include "tools/cabana/dbc/dbcmanager.h" - -#include -#include -#include -#include -#include -#include - +#include bool DBCManager::open(SourceSet s, const QString &dbc_file_name, QString *error) { for (int i = 0; i < dbc_files.size(); i++) { @@ -280,13 +273,7 @@ int DBCManager::dbcCount() const { } int DBCManager::nonEmptyDBCCount() const { - int cnt = 0; - for (auto &[_, dbc_file] : dbc_files) { - if (!dbc_file->isEmpty()) { - cnt++; - } - } - return cnt; + return std::count_if(dbc_files.cbegin(), dbc_files.cend(), [](auto &f) { return !f.second->isEmpty(); }); } void DBCManager::updateSources(const SourceSet &s) { diff --git a/tools/cabana/dbc/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h index 699c280b4c..0d7055588b 100644 --- a/tools/cabana/dbc/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -8,7 +8,6 @@ #include #include #include -#include #include "tools/cabana/dbc/dbc.h" #include "tools/cabana/dbc/dbcfile.h" diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 1f5a13aebb..d3da4a1500 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -77,6 +76,8 @@ MainWindow::MainWindow() : QMainWindow() { void MainWindow::createActions() { QMenu *file_menu = menuBar()->addMenu(tr("&File")); file_menu->addAction(tr("Open Stream..."), this, &MainWindow::openStream); + close_stream_act = file_menu->addAction(tr("Close stream"), this, &MainWindow::closeStream); + close_stream_act->setEnabled(false); file_menu->addSeparator(); file_menu->addAction(tr("New DBC File"), [this]() { newFile(); })->setShortcuts(QKeySequence::New); @@ -134,7 +135,7 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(new QUndoView(UndoStack::instance())); commands_menu->addAction(commands_act); - QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); + tools_menu = menuBar()->addMenu(tr("&Tools")); tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); tools_menu->addAction(tr("&Find Signal"), this, &MainWindow::findSignal); @@ -177,6 +178,7 @@ void MainWindow::createDockWidgets() { video_splitter->addWidget(charts_container); video_splitter->setStretchFactor(1, 1); video_splitter->restoreState(settings.video_splitter_state); + video_splitter->handle(1)->setEnabled(!can->liveStreaming()); video_dock->setWidget(video_splitter); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); } @@ -246,6 +248,15 @@ void MainWindow::openStream() { } } +void MainWindow::closeStream() { + AbstractStream *stream = new DummyStream(this); + stream->start(); + if (dbc()->nonEmptyDBCCount() > 0) { + emit dbc()->DBCFileChanged(); + } + statusBar()->showMessage(tr("stream closed")); +} + void MainWindow::newFile(SourceSet s) { closeFile(s); dbc()->open(s, "", ""); @@ -318,6 +329,9 @@ void MainWindow::changingStream() { } void MainWindow::streamStarted() { + bool has_stream = dynamic_cast(can) == nullptr; + close_stream_act->setEnabled(has_stream); + tools_menu->setEnabled(has_stream); createDockWidgets(); video_dock->setWindowTitle(can->routeName()); @@ -462,6 +476,7 @@ void MainWindow::updateLoadSaveMenus() { std::sort(sources_sorted.begin(), sources_sorted.end()); manage_dbcs_menu->clear(); + manage_dbcs_menu->setEnabled(dynamic_cast(can) == nullptr); for (uint8_t source : sources_sorted) { if (source >= 64) continue; // Sent and blocked buses are handled implicitly diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index e227ce593f..f56d37a252 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ public: public slots: void openStream(); + void closeStream(); void changingStream(); void streamStarted(); @@ -88,6 +90,8 @@ protected: QAction *recent_files_acts[MAX_RECENT_FILES] = {}; QMenu *open_recent_menu = nullptr; QMenu *manage_dbcs_menu = nullptr; + QMenu *tools_menu = nullptr; + QAction *close_stream_act = nullptr; QAction *save_dbc = nullptr; QAction *save_dbc_as = nullptr; QAction *copy_dbc_to_clipboard = nullptr; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 0a44cb931c..1d8499fa41 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -5,6 +5,8 @@ #include #include +#include "tools/cabana/commands.h" + MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0 ,0, 0, 0); @@ -82,11 +84,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { }); QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MessagesWidget::dbcModified); - QObject::connect(dbc(), &DBCManager::msgUpdated, this, &MessagesWidget::dbcModified); - QObject::connect(dbc(), &DBCManager::msgRemoved, this, &MessagesWidget::dbcModified); - QObject::connect(dbc(), &DBCManager::signalAdded, this, &MessagesWidget::dbcModified); - QObject::connect(dbc(), &DBCManager::signalRemoved, this, &MessagesWidget::dbcModified); - QObject::connect(dbc(), &DBCManager::signalUpdated, this, &MessagesWidget::dbcModified); + QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MessagesWidget::dbcModified); QObject::connect(model, &MessageListModel::modelReset, [this]() { if (current_msg_id) { selectMessage(*current_msg_id); @@ -245,104 +243,55 @@ void MessageListModel::sortMessages(std::vector &new_msgs) { } } -static std::pair parseRange(const QString &filter, bool *ok = nullptr, int base = 10) { +static bool parseRange(const QString &filter, uint32_t value, int base = 10) { // Parse out filter string into a range (e.g. "1" -> {1, 1}, "1-3" -> {1, 3}, "1-" -> {1, inf}) - bool ok1 = true, ok2 = true; - unsigned int parsed1 = std::numeric_limits::min(); - unsigned int parsed2 = std::numeric_limits::max(); - + unsigned int min = std::numeric_limits::min(); + unsigned int max = std::numeric_limits::max(); auto s = filter.split('-'); - if (s.size() == 1) { - parsed1 = s[0].toUInt(ok, base); - return {parsed1, parsed1}; - } else if (s.size() == 2) { - if (!s[0].isEmpty()) parsed1 = s[0].toUInt(&ok1, base); - if (!s[1].isEmpty()) parsed2 = s[1].toUInt(&ok2, base); - - *ok = ok1 & ok2; - return {parsed1, parsed2}; - } else { - *ok = false; - return {0, 0}; - } + bool ok = s.size() <= 2; + if (ok && !s[0].isEmpty()) min = s[0].toUInt(&ok, base); + if (ok && s.size() == 2 && !s[1].isEmpty()) max = s[1].toUInt(&ok, base); + return ok && value >= min && value <= max; } bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, const QMap &filters) { - auto cs = Qt::CaseInsensitive; bool match = true; - bool convert_ok; - - for (int column = Column::NAME; column <= Column::DATA; column++) { - if (!filters.contains(column)) continue; - const QString &txt = filters[column]; - + for (auto it = filters.cbegin(); it != filters.cend() && match; ++it) { + const QString &txt = it.value(); QRegularExpression re(txt, QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption); - - switch (column) { - case Column::NAME: - { - bool name_match = re.match(msgName(id)).hasMatch(); - - // Message signals - if (const auto msg = dbc()->msg(id)) { - for (auto s : msg->getSignals()) { - if (re.match(s->name).hasMatch()) { - name_match = true; - break; - } - } - } - if (!name_match) match = false; - } + switch (it.key()) { + case Column::NAME: { + const auto msg = dbc()->msg(id); + match = re.match(msg ? msg->name : UNTITLED).hasMatch(); + match |= msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), [&re](const auto &s) { return re.match(s.name).hasMatch(); }); break; + } case Column::SOURCE: - { - auto source = parseRange(txt, &convert_ok); - bool source_match = convert_ok && (id.source >= source.first && id.source <= source.second); - if (!source_match) match = false; - } + match = parseRange(txt, id.source); break; - case Column::ADDRESS: - { - bool address_re_match = re.match(QString::number(id.address, 16)).hasMatch(); - - auto address = parseRange(txt, &convert_ok, 16); - bool address_match = convert_ok && (id.address >= address.first && id.address <= address.second); - - if (!address_re_match && !address_match) match = false; - } + case Column::ADDRESS: { + match = re.match(QString::number(id.address, 16)).hasMatch(); + match |= parseRange(txt, id.address, 16); break; + } case Column::FREQ: - { - // TODO: Hide stale messages? - auto freq = parseRange(txt, &convert_ok); - bool freq_match = convert_ok && (data.freq >= freq.first && data.freq <= freq.second); - if (!freq_match) match = false; - } + // TODO: Hide stale messages? + match = parseRange(txt, data.freq); break; case Column::COUNT: - { - auto count = parseRange(txt, &convert_ok); - bool count_match = convert_ok && (data.count >= count.first && data.count <= count.second); - if (!count_match) match = false; - } + match = parseRange(txt, data.count); break; - case Column::DATA: - { - bool data_match = false; - data_match |= QString(data.dat.toHex()).contains(txt, cs); - data_match |= re.match(QString(data.dat.toHex())).hasMatch(); - data_match |= re.match(QString(data.dat.toHex(' '))).hasMatch(); - - if (!data_match) match = false; - } + case Column::DATA: { + match = QString(data.dat.toHex()).contains(txt, Qt::CaseInsensitive); + match |= re.match(QString(data.dat.toHex())).hasMatch(); + match |= re.match(QString(data.dat.toHex(' '))).hasMatch(); break; + } } } return match; } - void MessageListModel::fetchData() { std::vector new_msgs; new_msgs.reserve(can->last_msgs.size() + dbc_address.size()); @@ -459,11 +408,10 @@ void MessageView::headerContextMenuEvent(const QPoint &pos) { QMenu *menu = new QMenu(this); int cur_index = header()->logicalIndexAt(pos); - QString column_name; QAction *action; for (int visual_index = 0; visual_index < header()->count(); visual_index++) { int logical_index = header()->logicalIndex(visual_index); - column_name = model()->headerData(logical_index, Qt::Horizontal).toString(); + QString column_name = model()->headerData(logical_index, Qt::Horizontal).toString(); // Hide show action if (header()->isSectionHidden(logical_index)) { diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 57e6c3cf1a..cdb939b948 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -100,6 +100,15 @@ protected: AbstractStream **stream = nullptr; }; +class DummyStream : public AbstractStream { + Q_OBJECT +public: + DummyStream(QObject *parent) : AbstractStream(parent) {} + QString routeName() const override { return tr("No Stream"); } + void start() override { emit streamStarted(); } + double currentSec() const override { return 0; } +}; + class StreamNotifier : public QObject { Q_OBJECT public: diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 9d81ebd5d0..add4ee7928 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -20,12 +20,8 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi QHBoxLayout *src_layout = new QHBoxLayout(); src_bus_combo = new QComboBox(this); find_bus_combo = new QComboBox(this); - SourceSet bus_set; - for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { - bus_set << it.key().source; - } for (auto cb : {src_bus_combo, find_bus_combo}) { - for (uint8_t bus : bus_set) { + for (uint8_t bus : can->sources) { cb->addItem(QString::number(bus), bus); } cb->model()->sort(0); From 1f0ff21eee457f635059325bdcde61fc1bc6f0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 25 May 2023 20:34:10 +0200 Subject: [PATCH 067/283] laikad: unit test refactor (#28295) Refactor laika tests to use replay_process --- selfdrive/locationd/test/test_laikad.py | 63 +++++++++---------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index e184dc3ec4..2902790fa5 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -2,12 +2,9 @@ import time import unittest from cereal import log -import cereal.messaging as messaging from common.params import Params from datetime import datetime from unittest import mock -#from unittest.mock import patch -from tqdm import tqdm from laika.constants import SECS_IN_DAY @@ -19,45 +16,22 @@ from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom from selfdrive.locationd.laikad import EPHEMERIS_CACHE, Laikad from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader -from selfdrive.manager.process_config import managed_processes -from selfdrive.test.process_replay.helpers import OpenpilotPrefix +from selfdrive.test.process_replay.process_replay import get_process_config, replay_process + +GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC = GPSTime.from_datetime(datetime(2022, month=1, day=29, hour=12)) -def get_ublox_gnss(ubloxraw): - with OpenpilotPrefix(): - managed_processes['ubloxd'].start() - timeout_ms = 30 - pm = messaging.PubMaster(['ubloxRaw']) - sock = messaging.sub_sock('ubloxGnss', timeout=timeout_ms) - - log_msgs = [] - log_t = [] - for x in tqdm(ubloxraw): - pm.send(x.which(), x.as_builder()) - ret = messaging.recv_one(sock) - if ret is not None: - msg = log.Event.new_message(ubloxGnss=ret.ubloxGnss.to_dict()) - msg.logMonoTime = x.logMonoTime - log_msgs.append(msg) - log_t.append(1e-9 * x.logMonoTime) - assert managed_processes['ubloxd'].get_process_state_msg().running - assert len(log_msgs) > 1 or len(ubloxraw) == 0 - managed_processes['ubloxd'].stop() - return log_t, log_msgs - - - -def get_log(segs=range(0)): +def get_log_ublox(segs=range(0)): logs = [] for i in segs: logs.extend(LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", i))) - raw_logs = [m for m in logs if m.which() == 'ubloxRaw'] - all_logs = get_ublox_gnss(raw_logs)[1] + ublox_cfg = get_process_config("ubloxd") + all_logs = replay_process(ublox_cfg, logs) low_gnss = [] for m in all_logs: - if m.ubloxGnss.which() != 'measurementReport': + if m.which() != "ubloxGnss" or m.ubloxGnss.which() != 'measurementReport': continue MAX_MEAS = 7 @@ -72,6 +46,7 @@ def get_log(segs=range(0)): low_gnss.append(m) return all_logs, low_gnss + def get_log_qcom(segs=range(0)): logs = [] for i in segs: @@ -79,13 +54,16 @@ def get_log_qcom(segs=range(0)): all_logs = [m for m in logs if m.which() == 'qcomGnss'] return all_logs + def verify_messages(lr, laikad, return_one_success=False): good_msgs = [] for m in lr: if m.which() == 'ubloxGnss': gnss_msg = m.ubloxGnss - else: + elif m.which() == 'qcomGnss': gnss_msg = m.qcomGnss + else: + continue msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=True) if msg is not None and len(msg.gnssMeasurements.correctedMeasurements) > 0: good_msgs.append(msg) @@ -101,7 +79,7 @@ def get_first_gps_time(logs): new_meas = read_raw_ublox(m.ubloxGnss.measurementReport) if len(new_meas) > 0: return new_meas[0].recv_time - else: + elif m.which() == "qcomGnss": if m.qcomGnss.which == 'measurementReport': new_meas = read_raw_qcom(m.qcomGnss.measurementReport) if len(new_meas) > 0: @@ -116,14 +94,11 @@ def get_measurement_mock(gpstime, sat_ephemeris): return meas -GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC = GPSTime.from_datetime(datetime(2022, month=1, day=29, hour=12)) - - class TestLaikad(unittest.TestCase): @classmethod def setUpClass(cls): - logs, low_gnss = get_log(range(1)) + logs, low_gnss = get_log_ublox(range(1)) cls.logs = logs cls.low_gnss = low_gnss cls.logs_qcom = get_log_qcom(range(1)) @@ -190,6 +165,9 @@ class TestLaikad(unittest.TestCase): self.assertFalse(all(laikad.kf_valid(m.logMonoTime * 1e-9))) kf_valid = False for m in self.logs: + if m.which() != 'ubloxGnss': + continue + laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=True) kf_valid = all(laikad.kf_valid(m.logMonoTime * 1e-9)) if kf_valid: @@ -247,6 +225,9 @@ class TestLaikad(unittest.TestCase): seen_internet_eph = False for m in logs: + if m.which() != 'ubloxGnss' and m.which() != 'qcomGnss': + continue + gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) if laikad.orbit_fetch_future is not None: @@ -301,8 +282,6 @@ class TestLaikad(unittest.TestCase): self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) - - #TODO test cache with only orbits #with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: # # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently @@ -333,5 +312,7 @@ class TestLaikad(unittest.TestCase): def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) + + if __name__ == "__main__": unittest.main() From 387e865793a72011a6dfa096557987601c816809 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 25 May 2023 13:01:51 -0700 Subject: [PATCH 068/283] UI: update "Finish Setup" widget style (#28287) * UI: update SetupWidget registration design * SetupWidget: add icon * Revert "SetupWidget: add icon" This reverts commit 325d2d390496f287953beb1634b229ff4ff31717. --- selfdrive/ui/qt/widgets/prime.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc index 7f88b049ae..9cb4fa55a6 100644 --- a/selfdrive/ui/qt/widgets/prime.cc +++ b/selfdrive/ui/qt/widgets/prime.cc @@ -227,33 +227,31 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { // Unpaired, registration prompt layout - QWidget* finishRegistration = new QWidget; + QFrame* finishRegistration = new QFrame; finishRegistration->setObjectName("primeWidget"); QVBoxLayout* finishRegistationLayout = new QVBoxLayout(finishRegistration); - finishRegistationLayout->setContentsMargins(30, 75, 30, 45); - finishRegistationLayout->setSpacing(0); + finishRegistationLayout->setSpacing(40); + finishRegistationLayout->setContentsMargins(64, 64, 64, 64); QLabel* registrationTitle = new QLabel(tr("Finish Setup")); - registrationTitle->setStyleSheet("font-size: 75px; font-weight: bold; margin-left: 55px;"); + registrationTitle->setStyleSheet("font-size: 75px; font-weight: bold;"); finishRegistationLayout->addWidget(registrationTitle); - finishRegistationLayout->addSpacing(30); - QLabel* registrationDescription = new QLabel(tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.")); registrationDescription->setWordWrap(true); - registrationDescription->setStyleSheet("font-size: 55px; font-weight: light; margin-left: 55px;"); + registrationDescription->setStyleSheet("font-size: 55px; font-weight: light;"); finishRegistationLayout->addWidget(registrationDescription); finishRegistationLayout->addStretch(); QPushButton* pair = new QPushButton(tr("Pair device")); - pair->setFixedHeight(220); pair->setStyleSheet(R"( QPushButton { font-size: 55px; - font-weight: 400; + font-weight: 500; border-radius: 10px; background-color: #465BEA; + padding: 64px; } QPushButton:pressed { background-color: #3049F4; From 54506774f05a867ff0f6ab4ab494eeec792f838f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 May 2023 04:38:58 +0800 Subject: [PATCH 069/283] cabana: support editing comments for messages (#28299) --- tools/cabana/commands.cc | 11 ++++++----- tools/cabana/commands.h | 4 ++-- tools/cabana/dbc/dbc.h | 1 + tools/cabana/dbc/dbcfile.cc | 19 +++++++++++++++---- tools/cabana/dbc/dbcfile.h | 2 +- tools/cabana/dbc/dbcmanager.cc | 4 ++-- tools/cabana/dbc/dbcmanager.h | 2 +- tools/cabana/detailwidget.cc | 7 ++++++- tools/cabana/detailwidget.h | 2 ++ tools/cabana/messageswidget.cc | 5 +++++ tools/cabana/signalview.cc | 2 +- tools/cabana/tools/findsignal.cc | 2 +- tools/cabana/util.cc | 11 ----------- tools/cabana/util.h | 1 - 14 files changed, 43 insertions(+), 30 deletions(-) diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index 337de1c702..d64e173338 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -4,11 +4,12 @@ // EditMsgCommand -EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &name, int size, QUndoCommand *parent) - : id(id), new_name(name), new_size(size), QUndoCommand(parent) { +EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &name, int size, const QString &comment, QUndoCommand *parent) + : id(id), new_name(name), new_size(size), new_comment(comment), QUndoCommand(parent) { if (auto msg = dbc()->msg(id)) { old_name = msg->name; old_size = msg->size; + old_comment = msg->comment; setText(QObject::tr("edit message %1:%2").arg(name).arg(id.address)); } else { setText(QObject::tr("new message %1:%2").arg(name).arg(id.address)); @@ -19,11 +20,11 @@ void EditMsgCommand::undo() { if (old_name.isEmpty()) dbc()->removeMsg(id); else - dbc()->updateMsg(id, old_name, old_size); + dbc()->updateMsg(id, old_name, old_size, old_comment); } void EditMsgCommand::redo() { - dbc()->updateMsg(id, new_name, new_size); + dbc()->updateMsg(id, new_name, new_size, new_comment); } // RemoveMsgCommand @@ -37,7 +38,7 @@ RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : void RemoveMsgCommand::undo() { if (!message.name.isEmpty()) { - dbc()->updateMsg(id, message.name, message.size); + dbc()->updateMsg(id, message.name, message.size, message.comment); for (auto s : message.getSignals()) dbc()->addSignal(id, *s); } diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 84d1a6e2a1..2552115229 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -8,13 +8,13 @@ class EditMsgCommand : public QUndoCommand { public: - EditMsgCommand(const MessageId &id, const QString &name, int size, QUndoCommand *parent = nullptr); + EditMsgCommand(const MessageId &id, const QString &name, int size, const QString &comment, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: const MessageId id; - QString old_name, new_name; + QString old_name, new_name, old_comment, new_comment; int old_size = 0, new_size = 0; }; diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index d074987f50..b43d9cdecc 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -64,6 +64,7 @@ namespace cabana { uint32_t address; QString name; uint32_t size; + QString comment; QList sigs; QList mask; diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index 2b270fc30f..4679831ddc 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -125,11 +125,12 @@ void DBCFile::removeSignal(const MessageId &id, const QString &sig_name) { } } -void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size) { +void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) { auto &m = msgs[id.address]; m.address = id.address; m.name = name; m.size = size; + m.comment = comment; } void DBCFile::removeMsg(const MessageId &id) { @@ -193,6 +194,7 @@ void DBCFile::parseExtraInfo(const QString &content) { static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); + static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"(.*)\";)"); static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"(.*)\";)"); static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (.*);)"); auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * { @@ -235,6 +237,12 @@ void DBCFile::parseExtraInfo(const QString &content) { } } } + } else if (line.startsWith("CM_ BO_")) { + if (auto match = msg_comment_regexp.match(line); match.hasMatch()) { + if (auto m = (cabana::Msg *)msg(match.captured(1).toUInt())) { + m->comment = match.captured(2).trimmed(); + } + } } else if (line.startsWith("CM_ SG_ ")) { if (auto match = sg_comment_regexp.match(line); match.hasMatch()) { if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { @@ -246,9 +254,12 @@ void DBCFile::parseExtraInfo(const QString &content) { } QString DBCFile::generateDBC() { - QString dbc_string, signal_comment, val_desc; - for (auto &[address, m] : msgs) { + QString dbc_string, signal_comment, message_comment, val_desc; + for (const auto &[address, m] : msgs) { dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); + if (!m.comment.isEmpty()) { + message_comment += QString("CM_ BO_ %1 \"%2\";\n").arg(address).arg(m.comment); + } for (auto sig : m.getSignals()) { dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") .arg(sig->name) @@ -274,5 +285,5 @@ QString DBCFile::generateDBC() { } dbc_string += "\n"; } - return dbc_string + signal_comment + val_desc; + return dbc_string + message_comment + signal_comment + val_desc; } diff --git a/tools/cabana/dbc/dbcfile.h b/tools/cabana/dbc/dbcfile.h index 9f140f44d9..1ed9e9cd0a 100644 --- a/tools/cabana/dbc/dbcfile.h +++ b/tools/cabana/dbc/dbcfile.h @@ -31,7 +31,7 @@ public: cabana::Signal *getSignal(const MessageId &id, const QString &sig_name); void removeSignal(const MessageId &id, const QString &sig_name); - void updateMsg(const MessageId &id, const QString &name, uint32_t size); + void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment); void removeMsg(const MessageId &id); QString newMsgName(const MessageId &id); diff --git a/tools/cabana/dbc/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc index 000035bd2c..2176635caa 100644 --- a/tools/cabana/dbc/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -144,12 +144,12 @@ void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { } } -void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size) { +void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) { auto sources_dbc_file = findDBCFile(id); assert(sources_dbc_file); // This should be impossible auto [dbc_sources, dbc_file] = *sources_dbc_file; - dbc_file->updateMsg(id, name, size); + dbc_file->updateMsg(id, name, size, comment); for (uint8_t source : dbc_sources) { emit msgUpdated({.source = source, .address = id.address}); diff --git a/tools/cabana/dbc/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h index 0d7055588b..ba590ee56e 100644 --- a/tools/cabana/dbc/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -33,7 +33,7 @@ public: void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig); void removeSignal(const MessageId &id, const QString &sig_name); - void updateMsg(const MessageId &id, const QString &name, uint32_t size); + void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment); void removeMsg(const MessageId &id); QString newMsgName(const MessageId &id); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index c05b76c878..92851761f9 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -167,7 +167,7 @@ void DetailWidget::editMsg() { int size = msg ? msg->size : can->lastMessage(msg_id).dat.size(); EditMessageDialog dlg(msg_id, msgName(msg_id), size, this); if (dlg.exec()) { - UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); + UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text().trimmed(), dlg.size_spin->value(), dlg.comment_edit->toPlainText().trimmed())); } } @@ -194,6 +194,11 @@ EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &tit size_spin->setValue(size); form_layout->addRow(tr("Size"), size_spin); + form_layout->addRow(tr("Comment"), comment_edit = new QTextEdit(this)); + if (auto msg = dbc()->msg(msg_id)) { + comment_edit->setText(msg->comment); + } + btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); validateName(name_edit->text()); form_layout->addRow(btn_box); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index c4406bd39a..10c6a6c46e 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/binaryview.h" @@ -20,6 +21,7 @@ public: QString original_name; QDialogButtonBox *btn_box; QLineEdit *name_edit; + QTextEdit *comment_edit; QLabel *error_label; QSpinBox *size_spin; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 1d8499fa41..2b591a26d7 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -192,6 +192,11 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { return QVariant::fromValue(colors); } else if (role == BytesRole && index.column() == Column::DATA && id.source != INVALID_SOURCE) { return can_data.dat; + } else if (role == Qt::ToolTipRole && index.column() == Column::NAME) { + auto msg = dbc()->msg(id); + auto tooltip = msg ? msg->name : UNTITLED; + if (msg && !msg->comment.isEmpty()) tooltip += "
" + msg->comment + ""; + return tooltip; } return {}; } diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 0b74455d7c..b501f14a7c 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -226,7 +226,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { auto msg = dbc()->msg(msg_id); if (!msg) { QString name = dbc()->newMsgName(msg_id); - UndoStack::push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size())); + UndoStack::push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size(), "")); msg = dbc()->msg(msg_id); } diff --git a/tools/cabana/tools/findsignal.cc b/tools/cabana/tools/findsignal.cc index bc969356d4..7b4a5633f6 100644 --- a/tools/cabana/tools/findsignal.cc +++ b/tools/cabana/tools/findsignal.cc @@ -262,7 +262,7 @@ void FindSignalDlg::customMenuRequested(const QPoint &pos) { auto &s = model->filtered_signals[index.row()]; auto msg = dbc()->msg(s.id); if (!msg) { - UndoStack::push(new EditMsgCommand(s.id, dbc()->newMsgName(s.id), can->lastMessage(s.id).dat.size())); + UndoStack::push(new EditMsgCommand(s.id, dbc()->newMsgName(s.id), can->lastMessage(s.id).dat.size(), "")); msg = dbc()->msg(s.id); } s.sig.name = dbc()->newSignalName(s.id); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index d95d6ac525..a75d10139d 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -82,17 +82,6 @@ QSize MessageBytesDelegate::sizeHint(const QStyleOptionViewItem &option, const Q return size; } -bool MessageBytesDelegate::helpEvent(QHelpEvent *e, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { - if (e->type() == QEvent::ToolTip && index.column() == 0) { - if (view->visualRect(index).width() < QStyledItemDelegate::sizeHint(option, index).width()) { - QToolTip::showText(e->globalPos(), index.data(Qt::DisplayRole).toString(), view); - return true; - } - } - QToolTip::hideText(); - return false; -} - void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto data = index.data(BytesRole); if (!data.isValid()) { diff --git a/tools/cabana/util.h b/tools/cabana/util.h index dcf1ac0cbf..3955ab82c5 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -67,7 +67,6 @@ public: MessageBytesDelegate(QObject *parent, bool multiple_lines = false); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; - bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override; void setMultipleLines(bool v); int widthForBytes(int n) const; bool multipleLines() const { return multiple_lines; } From 13cf6957384f0ce620c6f74f87f77d04e19800c3 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 25 May 2023 16:40:40 -0700 Subject: [PATCH 070/283] UI: PrimeUserWidget cleanup (#28300) * cleanup * setMargin is obsolete * more --- selfdrive/ui/qt/widgets/prime.cc | 22 ++++++++++------------ selfdrive/ui/qt/widgets/prime.h | 10 +++++++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc index 9cb4fa55a6..2fa84a232f 100644 --- a/selfdrive/ui/qt/widgets/prime.cc +++ b/selfdrive/ui/qt/widgets/prime.cc @@ -114,31 +114,30 @@ PairingPopup::PairingPopup(QWidget *parent) : QDialogBase(parent) { } -PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QWidget(parent) { - mainLayout = new QVBoxLayout(this); - mainLayout->setMargin(0); +PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QFrame(parent) { + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(30); // subscribed prime layout QWidget *primeWidget = new QWidget; primeWidget->setObjectName("primeWidget"); QVBoxLayout *primeLayout = new QVBoxLayout(primeWidget); - primeLayout->setMargin(0); - primeWidget->setContentsMargins(60, 50, 60, 50); + primeLayout->setContentsMargins(60, 50, 60, 50); - QLabel* subscribed = new QLabel(tr("✓ SUBSCRIBED")); + QLabel *subscribed = new QLabel(tr("✓ SUBSCRIBED")); subscribed->setStyleSheet("font-size: 41px; font-weight: bold; color: #86FF4E;"); primeLayout->addWidget(subscribed, 0, Qt::AlignTop); primeLayout->addSpacing(60); - QLabel* commaPrime = new QLabel(tr("comma prime")); + QLabel *commaPrime = new QLabel(tr("comma prime")); commaPrime->setStyleSheet("font-size: 75px; font-weight: bold;"); primeLayout->addWidget(commaPrime, 0, Qt::AlignTop); primeLayout->addSpacing(20); - QLabel* connectUrl = new QLabel(tr("CONNECT.COMMA.AI")); + QLabel *connectUrl = new QLabel(tr("CONNECT.COMMA.AI")); connectUrl->setStyleSheet("font-size: 41px; font-family: Inter SemiBold; color: #A0A0A0;"); primeLayout->addWidget(connectUrl, 0, Qt::AlignTop); @@ -148,10 +147,9 @@ PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QWidget(parent) { QWidget *pointsWidget = new QWidget; pointsWidget->setObjectName("primeWidget"); QVBoxLayout *pointsLayout = new QVBoxLayout(pointsWidget); - pointsLayout->setMargin(0); - pointsWidget->setContentsMargins(60, 50, 60, 50); + pointsLayout->setContentsMargins(60, 50, 60, 50); - QLabel* commaPoints = new QLabel(tr("COMMA POINTS")); + QLabel *commaPoints = new QLabel(tr("COMMA POINTS")); commaPoints->setStyleSheet("font-size: 41px; font-family: Inter SemiBold;"); pointsLayout->addWidget(commaPoints, 0, Qt::AlignTop); @@ -183,7 +181,7 @@ void PrimeUserWidget::replyFinished(const QString &response) { } PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QFrame(parent) { - QVBoxLayout* main_layout = new QVBoxLayout(this); + QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(80, 90, 80, 60); main_layout->setSpacing(0); diff --git a/selfdrive/ui/qt/widgets/prime.h b/selfdrive/ui/qt/widgets/prime.h index 0a1d93250d..c5732799b8 100644 --- a/selfdrive/ui/qt/widgets/prime.h +++ b/selfdrive/ui/qt/widgets/prime.h @@ -15,6 +15,7 @@ enum PrimeType { MAGENTA_NEW = 4, }; + // pairing QR code class PairingQRWidget : public QWidget { Q_OBJECT @@ -34,6 +35,7 @@ private slots: void refresh(); }; + // pairing popup widget class PairingPopup : public QDialogBase { Q_OBJECT @@ -42,15 +44,16 @@ public: explicit PairingPopup(QWidget* parent); }; + // widget for paired users with prime -class PrimeUserWidget : public QWidget { +class PrimeUserWidget : public QFrame { Q_OBJECT + public: explicit PrimeUserWidget(QWidget* parent = 0); private: - QVBoxLayout* mainLayout; - QLabel* points; + QLabel *points; private slots: void replyFinished(const QString &response); @@ -64,6 +67,7 @@ public: explicit PrimeAdWidget(QWidget* parent = 0); }; + // container widget class SetupWidget : public QFrame { Q_OBJECT From 21f88f997d80430dac16513c9dafb358ce3494ae Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 25 May 2023 19:23:50 -0700 Subject: [PATCH 071/283] Revert "ui: smooth wide cam transition" (#28298) Revert "ui: smooth wide cam transition (#28277)" This reverts commit 26064196d0362d7719ce7b1ee835eb2193a3dc57. --- common/modeldata.h | 3 --- selfdrive/ui/qt/widgets/cameraview.cc | 24 ++++-------------------- selfdrive/ui/qt/widgets/cameraview.h | 6 ------ 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/common/modeldata.h b/common/modeldata.h index fdb5dd078d..a00d3d49d3 100644 --- a/common/modeldata.h +++ b/common/modeldata.h @@ -34,9 +34,6 @@ const mat3 ecam_intrinsic_matrix = (mat3){{567.0, 0.0, 1928.0 / 2, 0.0, 567.0, 1208.0 / 2, 0.0, 0.0, 1.0}}; -// zoom multiplier between cameras -const float ecam_to_fcam_zoom = fcam_intrinsic_matrix.v[0] / ecam_intrinsic_matrix.v[0]; - static inline mat3 get_model_yuv_transform() { float db_s = 1.0; const mat3 transform = (mat3){{ diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index d4f7e294dd..016129c348 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -201,12 +201,6 @@ void CameraWidget::updateFrameMat() { int w = glWidth(), h = glHeight(); if (zoomed_view) { - if (active_stream_type != VISION_STREAM_WIDE_ROAD) { - // Always ready to switch if wide is not active, start at full zoom - zoom_transition = 1; - ready_to_switch_stream = true; - } - if (active_stream_type == VISION_STREAM_DRIVER) { frame_mat = get_driver_view_transform(w, h, stream_width, stream_height); } else { @@ -215,21 +209,11 @@ void CameraWidget::updateFrameMat() { // for narrow come and a little lower for wide cam. // TODO: use proper perspective transform? if (active_stream_type == VISION_STREAM_WIDE_ROAD) { - // If narrow road camera is requested, start zooming in. - // Mark ready to switch once we're fully zoomed in - if (requested_stream_type != VISION_STREAM_WIDE_ROAD) { - zoom_transition += zoom_transition * 0.2 + 0.01; - } else { - zoom_transition -= (1.0 - zoom_transition) * 0.2 + 0.01; - } - zoom_transition = std::clamp(zoom_transition, 0.0f, 1.0f); - ready_to_switch_stream = fabs(zoom_transition - 1) < 1e-3; - intrinsic_matrix = ecam_intrinsic_matrix; - zoom = util::map_val(zoom_transition, 0.0f, 1.0f, ecam_zoom, ecam_to_fcam_zoom * fcam_zoom); + zoom = 2.0; } else { intrinsic_matrix = fcam_intrinsic_matrix; - zoom = fcam_zoom; + zoom = 1.1; } const vec3 inf = {{1000., 0., 0.}}; const vec3 Ep = matvecmul3(calibration, inf); @@ -388,13 +372,13 @@ void CameraWidget::vipcThread() { VisionIpcBufExtra meta_main = {0}; while (!QThread::currentThread()->isInterruptionRequested()) { - if (!vipc_client || ((cur_stream != requested_stream_type) && ready_to_switch_stream)) { + if (!vipc_client || cur_stream != requested_stream_type) { clearFrames(); qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; cur_stream = requested_stream_type; vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); - active_stream_type = cur_stream; } + active_stream_type = cur_stream; if (!vipc_client->connected) { clearFrames(); diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 931e85e842..8a140e5290 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -73,8 +73,6 @@ protected: int stream_width = 0; int stream_height = 0; int stream_stride = 0; - bool ready_to_switch_stream = true; // stream transition may be delayed by a zoom animation - float zoom_transition = 0; std::atomic active_stream_type; std::atomic requested_stream_type; std::set available_streams; @@ -87,10 +85,6 @@ protected: mat3 calibration = DEFAULT_CALIBRATION; mat3 intrinsic_matrix = fcam_intrinsic_matrix; - // Calibration constants - const float ecam_zoom = 2.0; - const float fcam_zoom = 1.1; - std::recursive_mutex frame_lock; std::deque> frames; uint32_t draw_frame_id = 0; From 78df554217fc27211d1b0cb227421a0f3f2153cd Mon Sep 17 00:00:00 2001 From: Comma Device Date: Thu, 25 May 2023 19:17:58 -0700 Subject: [PATCH 072/283] boardd: only look for new usb pandas --- selfdrive/boardd/boardd.cc | 18 ++++++++++++++---- selfdrive/boardd/panda.cc | 10 ++++++---- selfdrive/boardd/panda.h | 2 +- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 6248da7d4b..6f293d1c0d 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -472,6 +472,11 @@ void panda_state_thread(PubMaster *pm, std::vector pandas, bool spoofin bool is_onroad_last = false; std::future safety_future; + std::vector connected_serials; + for (Panda *p : pandas) { + connected_serials.push_back(p->hw_serial()); + } + LOGD("start panda state thread"); // run at 2hz @@ -499,10 +504,15 @@ void panda_state_thread(PubMaster *pm, std::vector pandas, bool spoofin LOGE("Reconnecting, communication to pandas not healthy"); do_exit = true; - // TODO: list is slow, takes 16ms - } else if (pandas.size() != Panda::list().size()) { - LOGW("Reconnecting to changed amount of pandas!"); - do_exit = true; + } else { + // check for new pandas + for (std::string &s : Panda::list(true)) { + if (!std::count(connected_serials.begin(), connected_serials.end(), s)) { + LOGW("Reconnecting to new panda: %s", s.c_str()); + do_exit = true; + break; + } + } } if (do_exit) { diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 1e7b510eca..72c3ea36ca 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -44,13 +44,15 @@ std::string Panda::hw_serial() { return handle->hw_serial; } -std::vector Panda::list() { +std::vector Panda::list(bool usb_only) { std::vector serials = PandaUsbHandle::list(); #ifndef __APPLE__ - for (auto s : PandaSpiHandle::list()) { - if (std::find(serials.begin(), serials.end(), s) == serials.end()) { - serials.push_back(s); + if (!usb_only) { + for (auto s : PandaSpiHandle::list()) { + if (std::find(serials.begin(), serials.end(), s) == serials.end()) { + serials.push_back(s); + } } } #endif diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index 69df2e2b66..ea93229725 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -57,7 +57,7 @@ public: std::string hw_serial(); // Static functions - static std::vector list(); + static std::vector list(bool usb_only=false); // Panda functionality cereal::PandaState::PandaType get_hw_type(); From c1909df43716d8e40333b2e587dbc5ac97020b05 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Fri, 26 May 2023 01:33:04 -0400 Subject: [PATCH 073/283] Subaru: frequency based messaging (#28066) * frequency based messaging * frequency based messaging * frequency based messaging * frequency based messaging * rename better * use frame in if statement * syntax * remove extra space * put all behind one if statement * update refs --------- Co-authored-by: Shane Smiskol --- selfdrive/car/subaru/carcontroller.py | 20 +++++--------------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index c4246b3806..ae3305fbe4 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -10,10 +10,6 @@ class CarController: self.apply_steer_last = 0 self.frame = 0 - self.es_lkas_state_cnt = -1 - self.es_distance_cnt = -1 - self.es_dashstatus_cnt = -1 - self.infotainmentstatus_cnt = -1 self.cruise_button_prev = 0 self.last_cancel_frame = 0 @@ -29,7 +25,6 @@ class CarController: # *** steering *** if (self.frame % self.p.STEER_STEP) == 0: - apply_steer = int(round(actuators.steer * self.p.STEER_MAX)) # limits due to driver torque @@ -51,7 +46,7 @@ class CarController: # *** alerts and pcm cancel *** if self.CP.carFingerprint in PREGLOBAL_CARS: - if self.es_distance_cnt != CS.es_distance_msg["COUNTER"]: + if self.frame % 5 == 0: # 1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 = resume deep # disengage ACC when OP is disengaged if pcm_cancel_cmd: @@ -68,7 +63,6 @@ class CarController: self.cruise_button_prev = cruise_button can_sends.append(subarucan.create_preglobal_es_distance(self.packer, cruise_button, CS.es_distance_msg)) - self.es_distance_cnt = CS.es_distance_msg["COUNTER"] else: if pcm_cancel_cmd and (self.frame - self.last_cancel_frame) > 0.2: @@ -76,19 +70,15 @@ class CarController: can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, bus, pcm_cancel_cmd)) self.last_cancel_frame = self.frame - if self.es_dashstatus_cnt != CS.es_dashstatus_msg["COUNTER"]: + if self.frame % 10 == 0: can_sends.append(subarucan.create_es_dashstatus(self.packer, CS.es_dashstatus_msg)) - self.es_dashstatus_cnt = CS.es_dashstatus_msg["COUNTER"] - if self.es_lkas_state_cnt != CS.es_lkas_state_msg["COUNTER"]: can_sends.append(subarucan.create_es_lkas_state(self.packer, CS.es_lkas_state_msg, CC.enabled, hud_control.visualAlert, hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart)) - self.es_lkas_state_cnt = CS.es_lkas_state_msg["COUNTER"] - - if self.CP.flags & SubaruFlags.SEND_INFOTAINMENT and self.infotainmentstatus_cnt != CS.es_infotainmentstatus_msg["COUNTER"]: - can_sends.append(subarucan.create_infotainmentstatus(self.packer, CS.es_infotainmentstatus_msg, hud_control.visualAlert)) - self.infotainmentstatus_cnt = CS.es_infotainmentstatus_msg["COUNTER"] + + if self.CP.flags & SubaruFlags.SEND_INFOTAINMENT: + can_sends.append(subarucan.create_infotainmentstatus(self.packer, CS.es_infotainmentstatus_msg, hud_control.visualAlert)) new_actuators = actuators.copy() new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dfb9106b8b..52735b686b 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -02b8c1e21f2bd3551aa4a2b94c73dcac762d3148 +29f846f525a4e14f380afd20ae8fa0804011ab6e \ No newline at end of file From 54e6d4c4028f790a2c38c5ccd3e4a9f012e4cce2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 25 May 2023 22:59:52 -0700 Subject: [PATCH 074/283] Subaru: explicitly copy signals to forward (#28304) * do subaru * add missing checksum * more missing checksums --- selfdrive/car/subaru/subarucan.py | 113 +++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index 3b498d3f70..bc9bf4c0a0 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -1,4 +1,3 @@ -import copy from cereal import car VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -18,7 +17,28 @@ def create_steering_status(packer): def create_es_distance(packer, es_distance_msg, bus, pcm_cancel_cmd): - values = copy.copy(es_distance_msg) + values = {s: es_distance_msg[s] for s in [ + "CHECKSUM", + "COUNTER", + "Signal1", + "Cruise_Fault", + "Cruise_Throttle", + "Signal2", + "Car_Follow", + "Signal3", + "Cruise_Soft_Disable", + "Signal7", + "Cruise_Brake_Active", + "Distance_Swap", + "Cruise_EPB", + "Signal4", + "Close_Distance", + "Signal5", + "Cruise_Cancel", + "Cruise_Set", + "Cruise_Resume", + "Signal6", + ]} values["COUNTER"] = (values["COUNTER"] + 1) % 0x10 if pcm_cancel_cmd: values["Cruise_Cancel"] = 1 @@ -26,7 +46,24 @@ def create_es_distance(packer, es_distance_msg, bus, pcm_cancel_cmd): def create_es_lkas_state(packer, es_lkas_state_msg, enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart): - values = copy.copy(es_lkas_state_msg) + values = {s: es_lkas_state_msg[s] for s in [ + "CHECKSUM", + "COUNTER", + "LKAS_Alert_Msg", + "Signal1", + "LKAS_ACTIVE", + "LKAS_Dash_State", + "Signal2", + "Backward_Speed_Limit_Menu", + "LKAS_Left_Line_Enable", + "LKAS_Left_Line_Light_Blink", + "LKAS_Right_Line_Enable", + "LKAS_Right_Line_Light_Blink", + "LKAS_Left_Line_Visible", + "LKAS_Right_Line_Visible", + "LKAS_Alert", + "Signal3", + ]} # Filter the stock LKAS "Keep hands on wheel" alert if values["LKAS_Alert_Msg"] == 1: @@ -69,7 +106,35 @@ def create_es_lkas_state(packer, es_lkas_state_msg, enabled, visual_alert, left_ def create_es_dashstatus(packer, dashstatus_msg): - values = copy.copy(dashstatus_msg) + values = {s: dashstatus_msg[s] for s in [ + "CHECKSUM", + "COUNTER", + "PCB_Off", + "LDW_Off", + "Signal1", + "Cruise_State_Msg", + "LKAS_State_Msg", + "Signal2", + "Cruise_Soft_Disable", + "Cruise_Status_Msg", + "Signal3", + "Cruise_Distance", + "Signal4", + "Conventional_Cruise", + "Signal5", + "Cruise_Disengaged", + "Cruise_Activated", + "Signal6", + "Cruise_Set_Speed", + "Cruise_Fault", + "Cruise_On", + "Display_Own_Car", + "Brake_Lights", + "Car_Follow", + "Signal7", + "Far_Distance", + "Cruise_State", + ]} # Filter stock LKAS disabled and Keep hands on steering wheel OFF alerts if values["LKAS_State_Msg"] in (2, 3): @@ -80,18 +145,26 @@ def create_es_dashstatus(packer, dashstatus_msg): def create_infotainmentstatus(packer, infotainmentstatus_msg, visual_alert): # Filter stock LKAS disabled and Keep hands on steering wheel OFF alerts - if infotainmentstatus_msg["LKAS_State_Infotainment"] in (3, 4): - infotainmentstatus_msg["LKAS_State_Infotainment"] = 0 + values = {s: infotainmentstatus_msg[s] for s in [ + "CHECKSUM", + "COUNTER", + "LKAS_State_Infotainment", + "LKAS_Blue_Lines", + "Signal1", + "Signal2", + ]} + if values["LKAS_State_Infotainment"] in (3, 4): + values["LKAS_State_Infotainment"] = 0 # Show Keep hands on wheel alert for openpilot steerRequired alert if visual_alert == VisualAlert.steerRequired: - infotainmentstatus_msg["LKAS_State_Infotainment"] = 3 + values["LKAS_State_Infotainment"] = 3 # Show Obstacle Detected for fcw if visual_alert == VisualAlert.fcw: - infotainmentstatus_msg["LKAS_State_Infotainment"] = 2 + values["LKAS_State_Infotainment"] = 2 - return packer.make_can_msg("INFOTAINMENT_STATUS", 0, infotainmentstatus_msg) + return packer.make_can_msg("INFOTAINMENT_STATUS", 0, values) # *** Subaru Pre-global *** @@ -112,9 +185,27 @@ def create_preglobal_steering_control(packer, apply_steer): def create_preglobal_es_distance(packer, cruise_button, es_distance_msg): - values = copy.copy(es_distance_msg) - values["Cruise_Button"] = cruise_button + values = {s: es_distance_msg[s] for s in [ + "Cruise_Throttle", + "Signal1", + "Car_Follow", + "Signal2", + "Brake_On", + "Distance_Swap", + "Standstill", + "Signal3", + "Close_Distance", + "Signal4", + "Standstill_2", + "Cruise_Fault", + "Signal5", + "COUNTER", + "Signal6", + "Cruise_Button", + "Signal7", + ]} + values["Cruise_Button"] = cruise_button values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_Distance") return packer.make_can_msg("ES_Distance", 0, values) From 26baac2ff4a57fa8dc7de46bd1292f2734a4d179 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 25 May 2023 23:12:50 -0700 Subject: [PATCH 075/283] Nissan: explicitly copy signals to forward (#28305) * nissan * missing counter * add comment from carstate --- selfdrive/car/nissan/carcontroller.py | 1 + selfdrive/car/nissan/nissancan.py | 97 +++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 5064e8c457..4e99d24903 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -63,6 +63,7 @@ class CarController: can_sends.append(nissancan.create_steering_control( self.packer, apply_angle, self.frame, CC.latActive, self.lkas_max_torque)) + # Below are the HUD messages. We copy the stock message and modify if self.CP.carFingerprint != CAR.ALTIMA: if self.frame % 2 == 0: can_sends.append(nissancan.create_lkas_hud_msg( diff --git a/selfdrive/car/nissan/nissancan.py b/selfdrive/car/nissan/nissancan.py index 01fb3463a9..89754775b1 100644 --- a/selfdrive/car/nissan/nissancan.py +++ b/selfdrive/car/nissan/nissancan.py @@ -1,4 +1,3 @@ -import copy import crcmod from selfdrive.car.nissan.values import CAR @@ -23,7 +22,23 @@ def create_steering_control(packer, apply_steer, frame, steer_on, lkas_max_torqu def create_acc_cancel_cmd(packer, car_fingerprint, cruise_throttle_msg): - values = copy.copy(cruise_throttle_msg) + values = {s: cruise_throttle_msg[s] for s in [ + "COUNTER", + "PROPILOT_BUTTON", + "CANCEL_BUTTON", + "GAS_PEDAL_INVERTED", + "SET_BUTTON", + "RES_BUTTON", + "FOLLOW_DISTANCE_BUTTON", + "NO_BUTTON_PRESSED", + "GAS_PEDAL", + "USER_BRAKE_PRESSED", + "NEW_SIGNAL_2", + "GAS_PRESSED_INVERTED", + "unsure1", + "unsure2", + "unsure3", + ]} can_bus = 1 if car_fingerprint == CAR.ALTIMA else 2 values["CANCEL_BUTTON"] = 1 @@ -37,7 +52,12 @@ def create_acc_cancel_cmd(packer, car_fingerprint, cruise_throttle_msg): def create_cancel_msg(packer, cancel_msg, cruise_cancel): - values = copy.copy(cancel_msg) + values = {s: cancel_msg[s] for s in [ + "CANCEL_SEATBELT", + "NEW_SIGNAL_1", + "NEW_SIGNAL_2", + "NEW_SIGNAL_3", + ]} if cruise_cancel: values["CANCEL_SEATBELT"] = 1 @@ -46,7 +66,34 @@ def create_cancel_msg(packer, cancel_msg, cruise_cancel): def create_lkas_hud_msg(packer, lkas_hud_msg, enabled, left_line, right_line, left_lane_depart, right_lane_depart): - values = lkas_hud_msg + values = {s: lkas_hud_msg[s] for s in [ + "LARGE_WARNING_FLASHING", + "SIDE_RADAR_ERROR_FLASHING1", + "SIDE_RADAR_ERROR_FLASHING2", + "LEAD_CAR", + "LEAD_CAR_ERROR", + "FRONT_RADAR_ERROR", + "FRONT_RADAR_ERROR_FLASHING", + "SIDE_RADAR_ERROR_FLASHING3", + "LKAS_ERROR_FLASHING", + "SAFETY_SHIELD_ACTIVE", + "RIGHT_LANE_GREEN_FLASH", + "LEFT_LANE_GREEN_FLASH", + "FOLLOW_DISTANCE", + "AUDIBLE_TONE", + "SPEED_SET_ICON", + "SMALL_STEERING_WHEEL_ICON", + "unknown59", + "unknown55", + "unknown26", + "unknown28", + "unknown31", + "SET_SPEED", + "unknown43", + "unknown08", + "unknown05", + "unknown02", + ]} values["RIGHT_LANE_YELLOW_FLASH"] = 1 if right_lane_depart else 0 values["LEFT_LANE_YELLOW_FLASH"] = 1 if left_lane_depart else 0 @@ -59,7 +106,47 @@ def create_lkas_hud_msg(packer, lkas_hud_msg, enabled, left_line, right_line, le def create_lkas_hud_info_msg(packer, lkas_hud_info_msg, steer_hud_alert): - values = lkas_hud_info_msg + values = {s: lkas_hud_info_msg[s] for s in [ + "NA_HIGH_ACCEL_TEMP", + "SIDE_RADAR_NA_HIGH_CABIN_TEMP", + "SIDE_RADAR_MALFUNCTION", + "LKAS_MALFUNCTION", + "FRONT_RADAR_MALFUNCTION", + "SIDE_RADAR_NA_CLEAN_REAR_CAMERA", + "NA_POOR_ROAD_CONDITIONS", + "CURRENTLY_UNAVAILABLE", + "SAFETY_SHIELD_OFF", + "FRONT_COLLISION_NA_FRONT_RADAR_OBSTRUCTION", + "PEDAL_MISSAPPLICATION_SYSTEM_ACTIVATED", + "SIDE_IMPACT_NA_RADAR_OBSTRUCTION", + "WARNING_DO_NOT_ENTER", + "SIDE_IMPACT_SYSTEM_OFF", + "SIDE_IMPACT_MALFUNCTION", + "FRONT_COLLISION_MALFUNCTION", + "SIDE_RADAR_MALFUNCTION2", + "LKAS_MALFUNCTION2", + "FRONT_RADAR_MALFUNCTION2", + "PROPILOT_NA_MSGS", + "BOTTOM_MSG", + "HANDS_ON_WHEEL_WARNING", + "WARNING_STEP_ON_BRAKE_NOW", + "PROPILOT_NA_FRONT_CAMERA_OBSTRUCTED", + "PROPILOT_NA_HIGH_CABIN_TEMP", + "WARNING_PROPILOT_MALFUNCTION", + "ACC_UNAVAILABLE_HIGH_CABIN_TEMP", + "ACC_NA_FRONT_CAMERA_IMPARED", + "unknown07", + "unknown10", + "unknown15", + "unknown23", + "unknown19", + "unknown31", + "unknown32", + "unknown46", + "unknown61", + "unknown55", + "unknown50", + ]} if steer_hud_alert: values["HANDS_ON_WHEEL_WARNING"] = 1 From 303c62119d6e41f13a59e12a41495e4950d6acf3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 25 May 2023 23:35:32 -0700 Subject: [PATCH 076/283] Tesla: explicitly copy signals to forward (#28306) * tesla * cmt --- selfdrive/car/tesla/teslacan.py | 36 +++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/tesla/teslacan.py b/selfdrive/car/tesla/teslacan.py index e5d904f80e..c84f2c45be 100644 --- a/selfdrive/car/tesla/teslacan.py +++ b/selfdrive/car/tesla/teslacan.py @@ -1,4 +1,3 @@ -import copy import crcmod from common.conversions import Conversions as CV @@ -31,7 +30,40 @@ class TeslaCAN: return self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values) def create_action_request(self, msg_stw_actn_req, cancel, bus, counter): - values = copy.copy(msg_stw_actn_req) + # We copy this whole message when spamming cancel + values = {s: msg_stw_actn_req[s] for s in [ + "SpdCtrlLvr_Stat", + "VSL_Enbl_Rq", + "SpdCtrlLvrStat_Inv", + "DTR_Dist_Rq", + "TurnIndLvr_Stat", + "HiBmLvr_Stat", + "WprWashSw_Psd", + "WprWash_R_Sw_Posn_V2", + "StW_Lvr_Stat", + "StW_Cond_Flt", + "StW_Cond_Psd", + "HrnSw_Psd", + "StW_Sw00_Psd", + "StW_Sw01_Psd", + "StW_Sw02_Psd", + "StW_Sw03_Psd", + "StW_Sw04_Psd", + "StW_Sw05_Psd", + "StW_Sw06_Psd", + "StW_Sw07_Psd", + "StW_Sw08_Psd", + "StW_Sw09_Psd", + "StW_Sw10_Psd", + "StW_Sw11_Psd", + "StW_Sw12_Psd", + "StW_Sw13_Psd", + "StW_Sw14_Psd", + "StW_Sw15_Psd", + "WprSw6Posn", + "MC_STW_ACTN_RQ", + "CRC_STW_ACTN_RQ", + ]} if cancel: values["SpdCtrlLvr_Stat"] = 1 From f494abf0d2db769a0a55ac29a3914962c3db902b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 26 May 2023 00:00:18 -0700 Subject: [PATCH 077/283] Hyundai: explicitly copy signals to forward (#28020) * define signals in brandcan.py * seems so * fix and reorder * lkas11 for hyundai * clu11 * honda: we only use this one signal for BRAKE_COMMAND * Revert "honda: we only use this one signal for BRAKE_COMMAND" This reverts commit f5f3aaed7e2fa1cdf35c3608b259fab11164644e. * do cam and cruise info * add todo * do nissan * s for signal * do nissan * mazda * toyota * gm * ford * ES_DISTANCE_SIGNALS is used twice * for s * volks * tesla * no copy * oh there's mqbcan * same with mqb lka message * all s's * these actually are different (pre vs. global) * this is not in the DBC... * fix * check len * rm import * need to copy counter! * fix other proc replay diff (TODO: the rest) * missing cs/cnt --- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/car/hyundai/hyundaican.py | 33 +++++++++++++++++++++-- selfdrive/car/hyundai/hyundaicanfd.py | 36 +++++++++++++++++++++----- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index ac74d2cc5b..11ff2fb6e4 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -141,7 +141,7 @@ class CarController: # cruise cancel if CC.cruiseControl.cancel: if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS: - can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CAN, CS.cruise_info)) + 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): diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index 858f3d0876..f23d9d5328 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -7,7 +7,23 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, torque_fault, lkas11, sys_warning, sys_state, enabled, left_lane, right_lane, left_lane_depart, right_lane_depart): - values = lkas11 + values = {s: lkas11[s] for s in [ + "CF_Lkas_LdwsActivemode", + "CF_Lkas_LdwsSysState", + "CF_Lkas_SysWarning", + "CF_Lkas_LdwsLHWarning", + "CF_Lkas_LdwsRHWarning", + "CF_Lkas_HbaLamp", + "CF_Lkas_FcwBasReq", + "CF_Lkas_HbaSysState", + "CF_Lkas_FcwOpt", + "CF_Lkas_HbaOpt", + "CF_Lkas_FcwSysState", + "CF_Lkas_FcwCollisionWarning", + "CF_Lkas_FusionState", + "CF_Lkas_FcwOpt_USM", + "CF_Lkas_LdwsOpt_USM", + ]} values["CF_Lkas_LdwsSysState"] = sys_state values["CF_Lkas_SysWarning"] = 3 if sys_warning else 0 values["CF_Lkas_LdwsLHWarning"] = left_lane_depart @@ -79,7 +95,20 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, def create_clu11(packer, frame, clu11, button, car_fingerprint): - values = clu11 + values = {s: clu11[s] for s in [ + "CF_Clu_CruiseSwState", + "CF_Clu_CruiseSwMain", + "CF_Clu_SldMainSW", + "CF_Clu_ParityBit1", + "CF_Clu_VanzDecimal", + "CF_Clu_Vanz", + "CF_Clu_SPEED_UNIT", + "CF_Clu_DetentOut", + "CF_Clu_RheostatLevel", + "CF_Clu_CluInfo", + "CF_Clu_AmpInfo", + "CF_Clu_AliveCnt1", + ]} values["CF_Clu_CruiseSwState"] = button values["CF_Clu_AliveCnt1"] = frame % 0x10 # send buttons to camera on camera-scc based cars diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index 3717a45909..da9cff8225 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -63,11 +63,11 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer): return ret -def create_cam_0x2a4(packer, CAN, camera_values): - camera_values.update({ - "BYTE7": 0, - }) - return packer.make_can_msg("CAM_0x2a4", CAN.ACAN, camera_values) +def create_cam_0x2a4(packer, CAN, cam_0x2a4): + values = {f"BYTE{i}": cam_0x2a4[f"BYTE{i}"] for i in range(3, 24)} + values['COUNTER'] = cam_0x2a4['COUNTER'] + values["BYTE7"] = 0 + return packer.make_can_msg("CAM_0x2a4", CAN.ACAN, values) def create_buttons(packer, CP, CAN, cnt, btn): values = { @@ -79,8 +79,30 @@ def create_buttons(packer, CP, CAN, cnt, btn): bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM return packer.make_can_msg("CRUISE_BUTTONS", bus, values) -def create_acc_cancel(packer, CAN, cruise_info_copy): - values = cruise_info_copy +def create_acc_cancel(packer, CP, CAN, cruise_info_copy): + # 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", + "CHECKSUM", + "NEW_SIGNAL_1", + "MainMode_ACC", + "ACCMode", + "CRUISE_INACTIVE", + "ZEROS_9", + "CRUISE_STANDSTILL", + "ZEROS_5", + "DISTANCE_SETTING", + "VSetDis", + ]} + else: + values = {s: cruise_info_copy[s] for s in [ + "COUNTER", + "CHECKSUM", + "ACCMode", + "VSetDis", + "CRUISE_STANDSTILL", + ]} values.update({ "ACCMode": 4, }) From f678ff0f2282d9374a13fa9513f5f8f43f5dac11 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 26 May 2023 00:19:46 -0700 Subject: [PATCH 078/283] car docs: sort parts by shown name (#28293) * sort by shown name * fix --- docs/CARS.md | 502 +++++++++++++++--------------- selfdrive/car/docs_definitions.py | 3 +- 2 files changed, 253 insertions(+), 252 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 37064537a1..6ee21f3517 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -8,258 +8,258 @@ A supported vehicle is one that just works when you install a comma three. All s |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| +|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| -|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 angled mount
- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 angled mount
- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai J connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|GV70 (2.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|GV70 (3.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai M connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Genesis|GV80 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai M connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 long OBD-C cable
- 1 mount
- 1 OBD-II connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 GM connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Honda Nidec connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai B connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai J connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai Q connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai Q connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai B connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai G connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai O connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai I connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai D connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Tucson Hybrid 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 FCA connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai P connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai P connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai L connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai G connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro EV 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai F connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai D connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai B connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai G connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai E connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai A connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai N connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai C connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai K connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Hyundai H connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 Ford Q3 connector
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Mazda connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 Mazda connector
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan B connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| -|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan A connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| -|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan A connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| -|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 Nissan A connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
Buy Here
|| -|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 Ram connector
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
Buy Here
|| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
Buy Here
|| -|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
Buy Here
|| -|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
Buy Here
|| -|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 RJ45 cable (7 ft)
- 1 Toyota connector
Buy Here
|| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
[10](#footnotes)|| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| -|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 harness box
- 1 J533 connector
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
- 1 USB-C coupler
Buy Here
|| +|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV70 (2.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV70 (3.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV80 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai O connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai I connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson Hybrid 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Ram connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| ### Footnotes 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 619d32e8eb..2088cc63b3 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -251,7 +251,8 @@ class CarInfo: if self.car_parts.parts: model_years = self.model + (' ' + self.years if self.years else '') buy_link = f'Buy Here' - parts = '
'.join([f"- {self.car_parts.parts.count(part)} {part.value.name}" for part in sorted(set(self.car_parts.parts), key=lambda part: part.name)]) + parts = '
'.join([f"- {self.car_parts.parts.count(part)} {part.value.name}" for part in + sorted(set(self.car_parts.parts), key=lambda part: str(part.value.name))]) hardware_col = f'
View{parts}
{buy_link}
' self.row: Dict[Enum, Union[str, Star]] = { From b35d525cc90f4ad5b4213872eacf7429a517c0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 26 May 2023 17:24:09 +0200 Subject: [PATCH 079/283] Assisted GPS qcom (#28278) * Assisted GPS works * cleanup * add error handling * use pycurl instead with timeout * Add file size check * More cleanup * more cleanup * Dont crash on large file --- system/sensord/rawgps/rawgpsd.py | 43 +++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/system/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py index 8f243af9a5..539a6308a7 100755 --- a/system/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -5,7 +5,9 @@ import signal import itertools import math import time +import pycurl import subprocess +from datetime import datetime from typing import NoReturn from struct import unpack_from, calcsize, pack @@ -107,6 +109,38 @@ def gps_enabled() -> bool: except subprocess.CalledProcessError as exc: raise Exception("failed to execute QGPS mmcli command") from exc +def download_and_inject_assistance(): + assist_data_file = '/tmp/xtra3grc.bin' + assistance_url = 'http://xtrapath3.izatcloud.net/xtra3grc.bin' + try: + c = pycurl.Curl() + c.setopt(c.URL, assistance_url) + c.setopt(c.NOBODY, 1) + c.setopt(pycurl.CONNECTTIMEOUT, 2) + c.perform() + c.close() + bytes_n = c.getinfo(c.CONTENT_LENGTH_DOWNLOAD) + if bytes_n > 1e5: + cloudlog.exception("Qcom assistance data larger than expected") + return + with open(assist_data_file, "wb") as fp: + c = pycurl.Curl() + c.setopt(pycurl.URL, assistance_url) + c.setopt(pycurl.CONNECTTIMEOUT, 5) + + c.setopt(pycurl.WRITEDATA, fp) + c.perform() + c.close() + except pycurl.error as e: + cloudlog.exception(f'Failed to download assistance file with error: {e}') + if os.path.isfile(assist_data_file): + try: + subprocess.check_call(f"mmcli -m any --timeout 30 --location-inject-assistance-data={assist_data_file}", shell=True) + except subprocess.CalledProcessError: + cloudlog.exception("rawgps.mmcli_command_failed") + if os.path.isfile(assist_data_file): + os.remove(assist_data_file) + def setup_quectel(diag: ModemDiag): # enable OEMDRE in the NV # TODO: it has to reboot for this to take effect @@ -120,13 +154,20 @@ def setup_quectel(diag: ModemDiag): if gps_enabled(): at_cmd("AT+QGPSEND") + #at_cmd("AT+QGPSDEL=0") # disable DPO power savings for more accuracy at_cmd("AT+QGPSCFG=\"dpoenable\",0") # don't automatically turn on GNSS on powerup at_cmd("AT+QGPSCFG=\"autogps\",0") - at_cmd("AT+QGPSSUPLURL=\"supl.google.com:7275\"") + # Do internet assistance + at_cmd("AT+QGPSXTRA=1") + download_and_inject_assistance() + #at_cmd("AT+QGPSXTRADATA?") + time_str = datetime.utcnow().strftime("%Y/%m/%d,%H:%M:%S") + at_cmd(f"AT+QGPSXTRATIME=0,\"{time_str}\",1,1,1000") + at_cmd("AT+QGPSCFG=\"outport\",\"usbnmea\"") at_cmd("AT+QGPS=1") From 79872db74137a4d3ae8c4b85609d15fa9556bfd6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 26 May 2023 11:07:22 -0700 Subject: [PATCH 080/283] offroad alerts: change email reference to support page (#28311) --- selfdrive/controls/lib/alerts_offroad.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/alerts_offroad.json b/selfdrive/controls/lib/alerts_offroad.json index 42d2512e51..9226c94d85 100644 --- a/selfdrive/controls/lib/alerts_offroad.json +++ b/selfdrive/controls/lib/alerts_offroad.json @@ -30,7 +30,7 @@ "severity": 0 }, "Offroad_UnofficialHardware": { - "text": "Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, contact support@comma.ai.", + "text": "Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support.", "severity": 1 }, "Offroad_StorageMissing": { From 9a3897831cebe7ee98858a3820f05b1985a0f40f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 27 May 2023 02:07:46 +0800 Subject: [PATCH 081/283] cabana: auto stretch last column (#28310) --- tools/cabana/messageswidget.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 2b591a26d7..657743901e 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -46,6 +46,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { restoreHeaderState(settings.message_header_state); view->header()->setSectionsMovable(true); view->header()->setSectionResizeMode(MessageListModel::Column::DATA, QHeaderView::Fixed); + view->header()->setStretchLastSection(true); // Header context menu view->header()->setContextMenuPolicy(Qt::CustomContextMenu); @@ -404,8 +405,8 @@ void MessageView::updateBytesSectionSize() { } } int width = delegate->widthForBytes(max_bytes); - if (header()->sectionSize(5) != width) { - header()->resizeSection(5, width); + if (header()->sectionSize(MessageListModel::Column::DATA) != width) { + header()->resizeSection(MessageListModel::Column::DATA, width); } } From 005ec28e72a60d643749b697098aa054a77935f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Fri, 26 May 2023 21:36:08 +0200 Subject: [PATCH 082/283] poetry: update lock (#28314) Update lock file --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index e2d894d3c3..91eb7e42e0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4804,7 +4804,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "0f8861fe679c2ba9a2a6365498a02ee353023e1a3ef882b117516fb7ea28fb58" +content-hash = "454ab16c681fa1754b26156f767ca0701eac357b66c146d71d61b39cbed42f5a" [metadata.files] adal = [ From 715f44ff455e1d5cf03ed6e0b0a2dae526229f84 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 26 May 2023 13:07:35 -0700 Subject: [PATCH 083/283] controls: write recalibrating offroad alert once (#28312) * only write once * rm read --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/controls/controlsd.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index a1620194bd..a584a44cb9 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -178,6 +178,7 @@ class Controls: self.desired_curvature_rate = 0.0 self.experimental_mode = False self.v_cruise_helper = VCruiseHelper(self.CP) + self.recalibrating_seen = False # TODO: no longer necessary, aside from process replay self.sm['liveParameters'].valid = True @@ -286,7 +287,9 @@ class Controls: if cal_status == log.LiveCalibrationData.Status.uncalibrated: self.events.add(EventName.calibrationIncomplete) elif cal_status == log.LiveCalibrationData.Status.recalibrating: - set_offroad_alert("Offroad_Recalibration", True) + if not self.recalibrating_seen: + set_offroad_alert("Offroad_Recalibration", True) + self.recalibrating_seen = True self.events.add(EventName.calibrationRecalibrating) else: self.events.add(EventName.calibrationInvalid) From 9a1d7d5fc2e8b5f1ab95e56ba3ecf38914350126 Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Sat, 27 May 2023 07:56:02 +0800 Subject: [PATCH 084/283] VW MQB: Add FW for 2017 Volkswagen Passat (#28280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit route name : 40443218782e5709|2023-05-22--13-05-38--0 --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index e64135d086..7fe29674a4 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -633,6 +633,7 @@ FW_VERSIONS = { b'\xf1\x870DD300045T \xf1\x891601', b'\xf1\x870DL300011H \xf1\x895201', b'\xf1\x870CW300042H \xf1\x891601', + b'\xf1\x870CW300042H \xf1\x891607', b'\xf1\x870GC300042H \xf1\x891404', b'\xf1\x870D9300018C \xf1\x895297', b'\xf1\x870GC300043 \xf1\x892301', @@ -640,6 +641,7 @@ FW_VERSIONS = { (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AE\xf1\x890195\xf1\x82\r56140056130012416612124111', b'\xf1\x873Q0959655AF\xf1\x890195\xf1\x82\r56140056130012026612120211', + b'\xf1\x873Q0959655AN\xf1\x890305\xf1\x82\r58160058140013036914110311', b'\xf1\x873Q0959655AN\xf1\x890306\xf1\x82\r58160058140013036914110311', b'\xf1\x873Q0959655BA\xf1\x890195\xf1\x82\r56140056130012516612125111', b'\xf1\x873Q0959655BB\xf1\x890195\xf1\x82\r56140056130012026612120211', @@ -656,6 +658,7 @@ FW_VERSIONS = { b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820514B0060703', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0060803', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803', + b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820526B0060905', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521B00606A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\00516B00501A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521B00703A1', @@ -668,6 +671,7 @@ FW_VERSIONS = { b'\xf1\x873Q0907572B \xf1\x890192', b'\xf1\x873Q0907572C \xf1\x890195', b'\xf1\x873Q0907572C \xf1\x890196', + b'\xf1\x875Q0907572P \xf1\x890682', b'\xf1\x875Q0907572R \xf1\x890771', ], }, From a075905c4ab04b0e159416ed5068fa2c0069928c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Sat, 27 May 2023 02:10:10 +0200 Subject: [PATCH 085/283] process_replay: fix crash on segments without carParams (#28286) * Fix crash on segments without carParams * Add assertion for carParams --- .../test/process_replay/process_replay.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index f271335611..8f2f3e1bd6 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -152,7 +152,7 @@ def get_car_params_callback(rc, pm, msgs, fingerprint): Params().put("CarParams", CP.to_bytes()) -def controlsd_rcv_callback(msg, CP, cfg, frame): +def controlsd_rcv_callback(msg, cfg, frame): # no sendcan until controlsd is initialized if msg.which() != "can": return False @@ -166,17 +166,17 @@ def controlsd_rcv_callback(msg, CP, cfg, frame): return len(socks) > 0 -def radar_rcv_callback(msg, CP, cfg, frame): +def radar_rcv_callback(msg, cfg, frame): return msg.which() == "can" -def calibration_rcv_callback(msg, CP, cfg, frame): +def calibration_rcv_callback(msg, cfg, frame): # calibrationd publishes 1 calibrationData every 5 cameraOdometry packets. # should_recv always true to increment frame return (frame - 1) == 0 or msg.which() == 'cameraOdometry' -def torqued_rcv_callback(msg, CP, cfg, frame): +def torqued_rcv_callback(msg, cfg, frame): # should_recv always true to increment frame return (frame - 1) == 0 or msg.which() == 'liveLocationKalman' @@ -185,7 +185,7 @@ class FrequencyBasedRcvCallback: def __init__(self, trigger_msg_type): self.trigger_msg_type = trigger_msg_type - def __call__(self, msg, CP, cfg, frame): + def __call__(self, msg, cfg, frame): if msg.which() != self.trigger_msg_type: return False @@ -338,19 +338,20 @@ def replay_process(cfg, lr, fingerprint=None): initialized = False if cfg.proc_name == "controlsd": for msg in lr: - if msg.which() == 'controlsState': + if msg.which() == "controlsState": controlsState = msg.controlsState if initialized: break - elif msg.which() == 'carEvents': + elif msg.which() == "carEvents": initialized = car.CarEvent.EventName.controlsInitializing not in [e.name for e in msg.carEvents] assert controlsState is not None and initialized, "controlsState never initialized" - CP = [m for m in lr if m.which() == 'carParams'][0].carParams if fingerprint is not None: setup_env(cfg=cfg, controlsState=controlsState, lr=lr, fingerprint=fingerprint) else: + CP = next((m.carParams for m in lr if m.which() == "carParams"), None) + assert CP is not None or "carParams" not in cfg.pubs, "carParams are missing and process needs it" setup_env(CP=CP, cfg=cfg, controlsState=controlsState, lr=lr) if cfg.config_callback is not None: @@ -369,7 +370,6 @@ def replay_process(cfg, lr, fingerprint=None): if cfg.init_callback is not None: cfg.init_callback(rc, pm, all_msgs, fingerprint) - CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) log_msgs, msg_queue = [], [] try: @@ -384,7 +384,7 @@ def replay_process(cfg, lr, fingerprint=None): with Timeout(cfg.timeout, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): resp_sockets, end_of_cycle = cfg.subs, True if cfg.should_recv_callback is not None: - end_of_cycle = cfg.should_recv_callback(msg, CP, cfg, cnt) + end_of_cycle = cfg.should_recv_callback(msg, cfg, cnt) msg_queue.append(msg) if end_of_cycle: From 23de5f1bace7bae9bb89fc426df9f162ef598667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Sat, 27 May 2023 04:21:34 +0200 Subject: [PATCH 086/283] pre-commit: validate poetry lock (#28313) * Add CI step to validate lock file * Fix run script * Build docker image before running the check * Fix * Use setup instead of docker build * Add pre-commit check * Update hooks * Add files to lock validation hook * Add pyproject.toml and poetry.lock to release files * Cleanup --- .github/workflows/selfdrive_tests.yaml | 2 ++ .pre-commit-config.yaml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 0f782107ec..9d92392b3a 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -59,6 +59,8 @@ jobs: cp .pre-commit-config.yaml $STRIPPED_DIR cp .pylintrc $STRIPPED_DIR cp mypy.ini $STRIPPED_DIR + cp pyproject.toml $STRIPPED_DIR + cp poetry.lock $STRIPPED_DIR cd $STRIPPED_DIR ${{ env.RUN }} "pre-commit run --all" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5e5c468f41..43d861667d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -83,3 +83,7 @@ repos: rev: '1.5.0' hooks: - id: poetry-check + - id: poetry-lock + name: validate poetry lock + args: + - --check From b0120e30a491bad0284f860e81064d142519e647 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 28 May 2023 05:04:43 +0800 Subject: [PATCH 087/283] cabana: fix broken message filtering (#28319) fix message filtering --- tools/cabana/messageswidget.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 657743901e..e24e8ab291 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -254,9 +254,13 @@ static bool parseRange(const QString &filter, uint32_t value, int base = 10) { unsigned int min = std::numeric_limits::min(); unsigned int max = std::numeric_limits::max(); auto s = filter.split('-'); - bool ok = s.size() <= 2; + bool ok = s.size() >= 1 && s.size() <= 2; if (ok && !s[0].isEmpty()) min = s[0].toUInt(&ok, base); - if (ok && s.size() == 2 && !s[1].isEmpty()) max = s[1].toUInt(&ok, base); + if (ok && s.size() == 1) { + max = min; + } else if (ok && s.size() == 2 && !s[1].isEmpty()) { + max = s[1].toUInt(&ok, base); + } return ok && value >= min && value <= max; } From 376faefec26f30cf457178cb02cdaff111bdfabe Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 27 May 2023 15:41:55 -0700 Subject: [PATCH 088/283] CI: enable FW query (#28316) --- selfdrive/test/helpers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py index 9fc80d8d72..f7dab576f3 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -12,7 +12,6 @@ from system.version import training_version, terms_version def set_params_enabled(): os.environ['PASSIVE'] = "0" os.environ['REPLAY'] = "1" - os.environ['SKIP_FW_QUERY'] = "1" os.environ['FINGERPRINT'] = "TOYOTA COROLLA TSS2 2019" os.environ['LOGPRINT'] = "debug" From 2a6458b44ed4189ec110036de956598e39fe8151 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 28 May 2023 06:43:42 +0800 Subject: [PATCH 089/283] cabana: improve dbc parsing (#28321) --- tools/cabana/dbc/dbc.cc | 2 +- tools/cabana/dbc/dbc.h | 2 +- tools/cabana/dbc/dbcfile.cc | 64 +++++++++++++++++--------------- tools/cabana/historylog.cc | 2 +- tools/cabana/signalview.cc | 14 +++---- tools/cabana/tools/findsignal.cc | 4 +- tools/cabana/util.cc | 8 ++++ tools/cabana/util.h | 8 +++- 8 files changed, 59 insertions(+), 45 deletions(-) diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index ac91922e01..cb5ebff602 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -40,7 +40,7 @@ void cabana::Signal::updatePrecision() { QString cabana::Signal::formatValue(double value) const { // Show enum string for (auto &[val, desc] : val_desc) { - if (std::abs(value - val.toInt()) < 1e-6) { + if (std::abs(value - val) < 1e-6) { return desc; } } diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index b43d9cdecc..ad5f33a260 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -42,7 +42,7 @@ struct std::hash { std::size_t operator()(const MessageId &k) const noexcept { return qHash(k); } }; -typedef QList> ValueDescription; +typedef QList> ValueDescription; namespace cabana { struct Signal { diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index 4679831ddc..e1b31489b9 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -196,7 +196,13 @@ void DBCFile::parseExtraInfo(const QString &content) { static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"(.*)\";)"); static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"(.*)\";)"); - static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (.*);)"); + static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))"); + + int line_num = 0; + QString line; + auto dbc_assert = [&line_num, &line, this](bool condition) { + if (!condition) throw std::runtime_error(QString("[%1:%2]: %3").arg(filename).arg(line_num).arg(line).toStdString()); + }; auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * { auto m = (cabana::Msg *)msg(address); return m ? (cabana::Signal *)m->sig(name) : nullptr; @@ -205,11 +211,12 @@ void DBCFile::parseExtraInfo(const QString &content) { QTextStream stream((QString *)&content); uint32_t address = 0; while (!stream.atEnd()) { - QString line = stream.readLine().trimmed(); + ++line_num; + line = stream.readLine().trimmed(); if (line.startsWith("BO_ ")) { - if (auto match = bo_regexp.match(line); match.hasMatch()) { - address = match.captured(1).toUInt(); - } + auto match = bo_regexp.match(line); + dbc_assert(match.hasMatch()); + address = match.captured(1).toUInt(); } else if (line.startsWith("SG_ ")) { int offset = 0; auto match = sg_regexp.match(line); @@ -217,37 +224,36 @@ void DBCFile::parseExtraInfo(const QString &content) { match = sgm_regexp.match(line); offset = 1; } - if (match.hasMatch()) { - if (auto s = get_sig(address, match.captured(1))) { - s->min = match.captured(8 + offset).toDouble(); - s->max = match.captured(9 + offset).toDouble(); - s->unit = match.captured(10 + offset); - } + dbc_assert(match.hasMatch()); + if (auto s = get_sig(address, match.captured(1))) { + s->min = match.captured(8 + offset).toDouble(); + s->max = match.captured(9 + offset).toDouble(); + s->unit = match.captured(10 + offset); } } else if (line.startsWith("VAL_ ")) { - if (auto match = val_regexp.match(line); match.hasMatch()) { - if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { - QStringList desc_list = match.captured(3).trimmed().split('"'); - for (int i = 0; i < desc_list.size(); i += 2) { - auto val = desc_list[i].trimmed(); - if (!val.isEmpty() && (i + 1) < desc_list.size()) { - auto desc = desc_list[i+1].trimmed(); - s->val_desc.push_back({val, desc}); - } + auto match = val_regexp.match(line); + dbc_assert(match.hasMatch()); + if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { + QStringList desc_list = match.captured(3).trimmed().split('"'); + for (int i = 0; i < desc_list.size(); i += 2) { + auto val = desc_list[i].trimmed(); + if (!val.isEmpty() && (i + 1) < desc_list.size()) { + auto desc = desc_list[i + 1].trimmed(); + s->val_desc.push_back({val.toDouble(), desc}); } } } } else if (line.startsWith("CM_ BO_")) { - if (auto match = msg_comment_regexp.match(line); match.hasMatch()) { - if (auto m = (cabana::Msg *)msg(match.captured(1).toUInt())) { - m->comment = match.captured(2).trimmed(); - } + auto match = msg_comment_regexp.match(line); + dbc_assert(match.hasMatch()); + if (auto m = (cabana::Msg *)msg(match.captured(1).toUInt())) { + m->comment = match.captured(2).trimmed(); } } else if (line.startsWith("CM_ SG_ ")) { - if (auto match = sg_comment_regexp.match(line); match.hasMatch()) { - if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { - s->comment = match.captured(3).trimmed(); - } + auto match = sg_comment_regexp.match(line); + dbc_assert(match.hasMatch()); + if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { + s->comment = match.captured(3).trimmed(); } } } @@ -278,7 +284,7 @@ QString DBCFile::generateDBC() { if (!sig->val_desc.isEmpty()) { QStringList text; for (auto &[val, desc] : sig->val_desc) { - text << QString("%1 \"%2\"").arg(val, desc); + text << QString("%1 \"%2\"").arg(val).arg(desc); } val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig->name).arg(text.join(" ")); } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 13e8f70a8f..51abc3d50f 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -224,7 +224,7 @@ LogsWidget::LogsWidget(QWidget *parent) : QFrame(parent) { display_type_cb->setToolTip(tr("Display signal value or raw hex value")); comp_box->addItems({">", "=", "!=", "<"}); value_edit->setClearButtonEnabled(true); - value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); + value_edit->setValidator(new DoubleValidator(this)); dynamic_mode->setChecked(true); dynamic_mode->setEnabled(!can->liveStreaming()); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index b501f14a7c..762b494f35 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -133,7 +133,7 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { case Item::Desc: { QStringList val_desc; for (auto &[val, desc] : item->sig->val_desc) { - val_desc << QString("%1 \"%2\"").arg(val, desc); + val_desc << QString("%1 \"%2\"").arg(val).arg(desc); } return val_desc.join(" "); } @@ -284,11 +284,7 @@ void SignalModel::handleSignalRemoved(const cabana::Signal *sig) { SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { name_validator = new NameValidator(this); - - QLocale locale(QLocale::C); - locale.setNumberOptions(QLocale::RejectGroupSeparator); - double_validator = new QDoubleValidator(this); - double_validator->setLocale(locale); // Match locale of QString::toDouble() instead of system + double_validator = new DoubleValidator(this); label_font.setPointSize(8); minmax_font.setPixelSize(10); @@ -666,7 +662,7 @@ ValueDescriptionDlg::ValueDescriptionDlg(const ValueDescription &descriptions, Q int row = 0; for (auto &[val, desc] : descriptions) { - table->setItem(row, 0, new QTableWidgetItem(val)); + table->setItem(row, 0, new QTableWidgetItem(QString::number(val))); table->setItem(row, 1, new QTableWidgetItem(desc)); ++row; } @@ -696,7 +692,7 @@ void ValueDescriptionDlg::save() { QString val = table->item(i, 0)->text().trimmed(); QString desc = table->item(i, 1)->text().trimmed(); if (!val.isEmpty() && !desc.isEmpty()) { - val_desc.push_back({val, desc}); + val_desc.push_back({val.toDouble(), desc}); } } QDialog::accept(); @@ -706,7 +702,7 @@ QWidget *ValueDescriptionDlg::Delegate::createEditor(QWidget *parent, const QSty QLineEdit *edit = new QLineEdit(parent); edit->setFrame(false); if (index.column() == 0) { - edit->setValidator(new QIntValidator(edit)); + edit->setValidator(new DoubleValidator(parent)); } return edit; } diff --git a/tools/cabana/tools/findsignal.cc b/tools/cabana/tools/findsignal.cc index 7b4a5633f6..b7d2f4c015 100644 --- a/tools/cabana/tools/findsignal.cc +++ b/tools/cabana/tools/findsignal.cc @@ -1,6 +1,5 @@ #include "tools/cabana/tools/findsignal.h" -#include #include #include #include @@ -138,8 +137,7 @@ FindSignalDlg::FindSignalDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags( undo_btn->setEnabled(false); reset_btn->setEnabled(false); - auto double_validator = new QDoubleValidator(this); - double_validator->setLocale(QLocale::C); + auto double_validator = new DoubleValidator(this); for (auto edit : {value1, value2, factor_edit, offset_edit, first_time_edit, last_time_edit}) { edit->setValidator(double_validator); } diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index a75d10139d..2660ae6837 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -161,6 +162,13 @@ QValidator::State NameValidator::validate(QString &input, int &pos) const { return QRegExpValidator::validate(input, pos); } +DoubleValidator::DoubleValidator(QObject *parent) : QDoubleValidator(parent) { + // Match locale of QString::toDouble() instead of system + QLocale locale(QLocale::C); + locale.setNumberOptions(QLocale::RejectGroupSeparator); + setLocale(locale); +} + namespace utils { QPixmap icon(const QString &id) { bool dark_theme = settings.theme == DARK_THEME; diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 3955ab82c5..fed8ba94c3 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -84,12 +85,17 @@ QColor getColor(const cabana::Signal *sig); class NameValidator : public QRegExpValidator { Q_OBJECT - public: NameValidator(QObject *parent=nullptr); QValidator::State validate(QString &input, int &pos) const override; }; +class DoubleValidator : public QDoubleValidator { + Q_OBJECT +public: + DoubleValidator(QObject *parent = nullptr); +}; + namespace utils { QPixmap icon(const QString &id); void setTheme(int theme); From 3f61537d1b7b33ee0a1104ca6a47bf323bf31c4b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 27 May 2023 16:50:34 -0700 Subject: [PATCH 090/283] Hyundai CAN FD DBC update (#28322) --- opendbc | 2 +- selfdrive/car/hyundai/carstate.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opendbc b/opendbc index 8faada0494..2db0483993 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 8faada0494c4498a57c2196e80c6da94f508d009 +Subproject commit 2db04839931562b7088276e14de846e90c7e2396 diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index cec2c3e69e..bb84dcde1d 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -173,8 +173,8 @@ class CarState(CarStateBase): ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1 - ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1 - ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0 + ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1 + ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0 gear = cp.vl[self.gear_msg_canfd]["GEAR"] ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear)) @@ -457,8 +457,8 @@ class CarState(CarStateBase): ("LEFT_LAMP", "BLINKERS"), ("RIGHT_LAMP", "BLINKERS"), - ("DRIVER_DOOR_OPEN", "DOORS_SEATBELTS"), - ("DRIVER_SEATBELT_LATCHED", "DOORS_SEATBELTS"), + ("DRIVER_DOOR", "DOORS_SEATBELTS"), + ("DRIVER_SEATBELT", "DOORS_SEATBELTS"), ] checks = [ From 897b9c117abb9777b7d41e2efd3de04e3df482ce Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 27 May 2023 18:49:03 -0700 Subject: [PATCH 091/283] HKG: add missing FW for 2020 G70 (#28323) missing g70 --- selfdrive/car/hyundai/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index bbfeca9b0e..8dbd7a65f0 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1105,12 +1105,14 @@ FW_VERSIONS = { b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9220 4I2VL107', b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9420 4I4VL107', b'\xf1\x00IK MDPS R 1.00 1.08 57700-G9420 4I4VL108', + b'\xf1\x00IK MDPS R 1.00 1.08 57700-G9200 4I2CL108', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x87VCJLP18407832DN3\x88vXfvUVT\x97eFU\x87d7v\x88eVeveFU\x89\x98\x7f\xff\xb2\xb0\xf1\x81E25\x00\x00\x00', b'\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL', b'\xf1\x87VDKLT18912362DN4wfVfwefeveVUwfvw\x88vWfvUFU\x89\xa9\x8f\xff\x87w\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL', b'\xf1\x87VDJLC18480772DK9\x88eHfwfff\x87eFUeDEU\x98eFe\x86T5DVyo\xff\x87s\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33KB5\x9f\xa5&\x81', + b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T20KB3Wuvz', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ', @@ -1124,6 +1126,7 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x81606G2051\x00\x00\x00\x00\x00\x00\x00\x00', ], }, CAR.GENESIS_G80: { From aa3490ac3058832fc7da0e5e824714cb5f95b469 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 27 May 2023 19:25:38 -0700 Subject: [PATCH 092/283] IsoTpParallelQuery: fixup comment and simpler response check (#28326) * startswith works with bytes * this comment only explained an exception, was confusing --- selfdrive/car/isotp_parallel_query.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index 965d2e1836..d6b3538840 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -90,7 +90,8 @@ class IsoTpParallelQuery: for addr in self.functional_addrs: self._create_isotp_msg(addr, None, -1).send(self.request[0]) - # If querying functional addrs, set up physical IsoTpMessages to send consecutive frames + # Send first frame (single or first) to all addresses and receive asynchronously in the loop below. + # If querying functional addrs, only set up physical IsoTpMessages to send consecutive frames for msg in msgs.values(): msg.send(self.request[0], setup_only=len(self.functional_addrs) > 0) @@ -117,7 +118,7 @@ class IsoTpParallelQuery: counter = request_counter[tx_addr] expected_response = self.response[counter] - response_valid = dat[:len(expected_response)] == expected_response + response_valid = dat.startswith(expected_response) if response_valid: if counter + 1 < len(self.request): From de5e0d0c714ce8820c5bbd9dc7e981cc8f58bb03 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 27 May 2023 21:54:37 -0700 Subject: [PATCH 093/283] Ford: fix counter in LateralMotionControl2 message (#28328) --- selfdrive/car/ford/carcontroller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index d9a9ae6bc0..5bdafa58b5 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -70,7 +70,7 @@ class CarController: if self.CP.carFingerprint in CANFD_CARS: # TODO: extended mode mode = 1 if CC.latActive else 0 - counter = self.frame // CarControllerParams.STEER_STEP + counter = (self.frame // CarControllerParams.STEER_STEP) % 0xF can_sends.append(create_lat_ctl2_msg(self.packer, mode, 0., 0., -apply_curvature, 0., counter)) else: can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.)) From 026c093d05dfc05a9a04ff341942e5b9858a12f7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 27 May 2023 22:14:50 -0700 Subject: [PATCH 094/283] IsoTpParallelQuery: log all timeouts (#28325) * log * self explan * clean up * revert * need a better name * move * bvack --- selfdrive/car/isotp_parallel_query.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index d6b3538840..5f8b0561a0 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -97,6 +97,7 @@ class IsoTpParallelQuery: results = {} start_time = time.monotonic() + addrs_responded = set() # track addresses that have ever sent a valid iso-tp frame for timeout logging response_timeouts = {tx_addr: start_time + timeout for tx_addr in self.msg_addrs} while True: self.rx() @@ -111,6 +112,7 @@ class IsoTpParallelQuery: # Extend timeout for each consecutive ISO-TP frame to avoid timing out on long responses if rx_in_progress: + addrs_responded.add(tx_addr) response_timeouts[tx_addr] = time.monotonic() + timeout if not dat: @@ -141,8 +143,13 @@ class IsoTpParallelQuery: cur_time = time.monotonic() for tx_addr in response_timeouts: if cur_time - response_timeouts[tx_addr] > 0: - if request_counter[tx_addr] > 0 and not request_done[tx_addr]: - cloudlog.error(f"iso-tp query timeout after receiving response: {tx_addr}") + if not request_done[tx_addr]: + if request_counter[tx_addr] > 0: + cloudlog.error(f"iso-tp query timeout after receiving partial response: {tx_addr}") + elif tx_addr in addrs_responded: + cloudlog.error(f"iso-tp query timeout while receiving response: {tx_addr}") + else: + cloudlog.error(f"iso-tp query timeout with no response: {tx_addr}") request_done[tx_addr] = True # Break if all requests are done (finished or timed out) From 43b0e51906f0054fe4ba0dddf27ce90df443d8bd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 28 May 2023 11:59:01 -0700 Subject: [PATCH 095/283] show ign off time in count events debug script --- selfdrive/debug/count_events.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/selfdrive/debug/count_events.py b/selfdrive/debug/count_events.py index 42b671e5e3..a81d797b89 100755 --- a/selfdrive/debug/count_events.py +++ b/selfdrive/debug/count_events.py @@ -23,6 +23,7 @@ if __name__ == "__main__": alerts: List[Tuple[float, str]] = [] start_time = math.inf end_time = -math.inf + ignition_off = None for q in tqdm(r.qlog_paths()): if q is None: continue @@ -38,6 +39,11 @@ if __name__ == "__main__": if len(alerts) == 0 or alerts[-1][1] != msg.controlsState.alertType: t = (msg.logMonoTime - start_time) / 1e9 alerts.append((t, msg.controlsState.alertType)) + elif msg.which() == 'pandaStates': + if ignition_off is None: + ign = any(ps.ignitionLine or ps.ignitionCan for ps in msg.pandaStates) + if not ign: + ignition_off = msg.logMonoTime elif msg.which() in cams: cnt_cameras[msg.which()] += 1 @@ -64,6 +70,9 @@ if __name__ == "__main__": print("Alerts") for t, a in alerts: print(f"{t:8.2f} {a}") + if ignition_off is not None: + ignition_off = round((ignition_off - start_time) / 1e9, 2) + print("Ignition off at", ignition_off) print("\n") print("Route duration", datetime.timedelta(seconds=duration)) From 7e141f25f9454d245e09bbdc8d7cc826e4095592 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 29 May 2023 14:46:15 -0700 Subject: [PATCH 096/283] athena: raise log level for call method (#28334) --- selfdrive/athena/athenad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 8e335c2b58..842c649672 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -171,7 +171,7 @@ def jsonrpc_handler(end_event: threading.Event) -> None: try: data = recv_queue.get(timeout=1) if "method" in data: - cloudlog.debug(f"athena.jsonrpc_handler.call_method {data}") + cloudlog.event("athena.jsonrpc_handler.call_method", data=data) response = JSONRPCResponseManager.handle(data, dispatcher) send_queue.put_nowait(response.json) elif "id" in data and ("result" in data or "error" in data): From 90e0c61664d5620c82dccd058c67757426649435 Mon Sep 17 00:00:00 2001 From: vanillagorillaa <31773928+vanillagorillaa@users.noreply.github.com> Date: Mon, 29 May 2023 23:01:30 -0700 Subject: [PATCH 097/283] Nissan: use generated DBCs (#28307) * nissan dbc update * bump * for release build --------- Co-authored-by: Shane Smiskol --- opendbc | 2 +- release/files_common | 4 ++-- selfdrive/car/nissan/values.py | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/opendbc b/opendbc index 2db0483993..49b31858a3 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 2db04839931562b7088276e14de846e90c7e2396 +Subproject commit 49b31858a36275dc16f768781297e443e57d16ab diff --git a/release/files_common b/release/files_common index 0280d14b63..781600ac8f 100644 --- a/release/files_common +++ b/release/files_common @@ -565,8 +565,8 @@ opendbc/hyundai_kia_mando_front_radar_generated.dbc opendbc/mazda_2017.dbc -opendbc/nissan_x_trail_2017.dbc -opendbc/nissan_leaf_2018.dbc +opendbc/nissan_x_trail_2017_generated.dbc +opendbc/nissan_leaf_2018_generated.dbc opendbc/subaru_global_2017_generated.dbc opendbc/subaru_outback_2015_generated.dbc diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 1669151025..0194a71aa1 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -171,9 +171,9 @@ FW_VERSIONS = { } DBC = { - CAR.XTRAIL: dbc_dict('nissan_x_trail_2017', None), - CAR.LEAF: dbc_dict('nissan_leaf_2018', None), - CAR.LEAF_IC: dbc_dict('nissan_leaf_2018', None), - CAR.ROGUE: dbc_dict('nissan_x_trail_2017', None), - CAR.ALTIMA: dbc_dict('nissan_x_trail_2017', None), + CAR.XTRAIL: dbc_dict('nissan_x_trail_2017_generated', None), + CAR.LEAF: dbc_dict('nissan_leaf_2018_generated', None), + CAR.LEAF_IC: dbc_dict('nissan_leaf_2018_generated', None), + CAR.ROGUE: dbc_dict('nissan_x_trail_2017_generated', None), + CAR.ALTIMA: dbc_dict('nissan_x_trail_2017_generated', None), } From 80e84a2158df7e4cacf1a21aee71206293ff7f5d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 May 2023 15:05:57 -0700 Subject: [PATCH 098/283] Honda: use CS accFaulted field (#28339) * log accFaulted * bool * also bool --- selfdrive/car/honda/carstate.py | 5 ++--- selfdrive/car/honda/interface.py | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index bcc239c2df..57a2f4a846 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -148,7 +148,6 @@ class CarState(CarStateBase): self.shifter_values = can_define.dv[self.gearbox_msg]["GEAR_SHIFTER"] self.steer_status_values = defaultdict(lambda: "UNKNOWN", can_define.dv["STEER_STATUS"]["STEER_STATUS"]) - self.brake_error = False self.brake_switch_prev = False self.brake_switch_active = False self.cruise_setting = 0 @@ -195,9 +194,9 @@ class CarState(CarStateBase): ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2") if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS: - self.brake_error = cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"] + ret.accFaulted = bool(cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"]) elif self.CP.openpilotLongitudinalControl: - self.brake_error = cp.vl["STANDSTILL"]["BRAKE_ERROR_1"] or cp.vl["STANDSTILL"]["BRAKE_ERROR_2"] + ret.accFaulted = bool(cp.vl["STANDSTILL"]["BRAKE_ERROR_1"] or cp.vl["STANDSTILL"]["BRAKE_ERROR_2"]) ret.espDisabled = cp.vl["VSA_STATUS"]["ESP_DISABLED"] != 0 ret.wheelSpeeds = self.get_wheel_speeds( diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 65deab7401..2c936cf3b6 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -326,9 +326,6 @@ class CarInterface(CarInterfaceBase): # events events = self.create_common_events(ret, pcm_enable=False) - if self.CS.brake_error: - events.add(EventName.brakeUnavailable) - if self.CP.pcmCruise and ret.vEgo < self.CP.minEnableSpeed: events.add(EventName.belowEngageSpeed) From 4b4b31450ccf0d4b63bb2cc4fa77c7f476374bde Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 May 2023 15:10:17 -0700 Subject: [PATCH 099/283] Nissan: add counter signal to forwarded message (#28336) Update carstate.py --- selfdrive/car/nissan/carstate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py index bbba92ddeb..7fbc807665 100644 --- a/selfdrive/car/nissan/carstate.py +++ b/selfdrive/car/nissan/carstate.py @@ -171,6 +171,7 @@ class CarState(CarStateBase): ("USER_BRAKE_PRESSED", "CRUISE_THROTTLE"), ("NEW_SIGNAL_2", "CRUISE_THROTTLE"), ("GAS_PRESSED_INVERTED", "CRUISE_THROTTLE"), + ("COUNTER", "CRUISE_THROTTLE"), ("unsure1", "CRUISE_THROTTLE"), ("unsure2", "CRUISE_THROTTLE"), ("unsure3", "CRUISE_THROTTLE"), From 439a30aae4c0495bb27aed4b5cd2d0e684fe0f1b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 May 2023 15:33:02 -0700 Subject: [PATCH 100/283] cars: explicitly add counter/checksum messages (#28341) * hkg canfd: add counter/checksum * add explicitly to subaru * same for ES_LKAS_State * and ES_DashStatus * aaand INFOTAINMENT_STATUS * and preglobal ES_Distance * Revert "and preglobal ES_Distance" This reverts commit 68d98307703a24296ff7aafd99503ea6af4b231b. --- selfdrive/car/hyundai/carstate.py | 3 +++ selfdrive/car/subaru/carstate.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index bb84dcde1d..9bf2e0d4c1 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -486,6 +486,8 @@ class CarState(CarStateBase): if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl: signals += [ + ("COUNTER", "SCC_CONTROL"), + ("CHECKSUM", "SCC_CONTROL"), ("ACCMode", "SCC_CONTROL"), ("VSetDis", "SCC_CONTROL"), ("CRUISE_STANDSTILL", "SCC_CONTROL"), @@ -528,6 +530,7 @@ class CarState(CarStateBase): elif CP.flags & HyundaiFlags.CANFD_CAMERA_SCC: signals += [ ("COUNTER", "SCC_CONTROL"), + ("CHECKSUM", "SCC_CONTROL"), ("NEW_SIGNAL_1", "SCC_CONTROL"), ("MainMode_ACC", "SCC_CONTROL"), ("ACCMode", "SCC_CONTROL"), diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index 9d7b0a65cc..8ce31b1842 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -110,6 +110,7 @@ class CarState(CarStateBase): def get_global_es_distance_signals(): signals = [ ("COUNTER", "ES_Distance"), + ("CHECKSUM", "ES_Distance"), ("Signal1", "ES_Distance"), ("Cruise_Fault", "ES_Distance"), ("Cruise_Throttle", "ES_Distance"), @@ -251,6 +252,7 @@ class CarState(CarStateBase): else: signals = [ ("COUNTER", "ES_DashStatus"), + ("CHECKSUM", "ES_DashStatus"), ("PCB_Off", "ES_DashStatus"), ("LDW_Off", "ES_DashStatus"), ("Signal1", "ES_DashStatus"), @@ -278,6 +280,7 @@ class CarState(CarStateBase): ("Cruise_State", "ES_DashStatus"), ("COUNTER", "ES_LKAS_State"), + ("CHECKSUM", "ES_LKAS_State"), ("LKAS_Alert_Msg", "ES_LKAS_State"), ("Signal1", "ES_LKAS_State"), ("LKAS_ACTIVE", "ES_LKAS_State"), @@ -305,6 +308,8 @@ class CarState(CarStateBase): if CP.flags & SubaruFlags.SEND_INFOTAINMENT: signals += [ + ("COUNTER", "INFOTAINMENT_STATUS"), + ("CHECKSUM", "INFOTAINMENT_STATUS"), ("LKAS_State_Infotainment", "INFOTAINMENT_STATUS"), ("LKAS_Blue_Lines", "INFOTAINMENT_STATUS"), ("Signal1", "INFOTAINMENT_STATUS"), From 2e4e41a7d3e533fb1c74d68ea9078e45b26bb1d9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 May 2023 15:40:54 -0700 Subject: [PATCH 101/283] Mazda: set default steering control values (#28342) don't crash when porting new car --- selfdrive/car/mazda/mazdacan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/mazda/mazdacan.py b/selfdrive/car/mazda/mazdacan.py index 3b29a25621..58a505f917 100644 --- a/selfdrive/car/mazda/mazdacan.py +++ b/selfdrive/car/mazda/mazdacan.py @@ -44,6 +44,7 @@ def create_steering_control(packer, car_fingerprint, frame, apply_steer, lkas): csum = csum % 256 + values = {} if car_fingerprint in GEN1: values = { "LKAS_REQUEST": apply_steer, From e875bcfaeec9a4bfab2d8e4e4bb5b7ee978eb047 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Tue, 30 May 2023 18:18:47 -0700 Subject: [PATCH 102/283] UI: remove comma points (#28303) * UI: remove comma points * remove param --- common/params.cc | 1 - selfdrive/ui/qt/widgets/prime.cc | 33 ------------------------ selfdrive/ui/qt/widgets/prime.h | 6 ----- selfdrive/ui/translations/main_de.ts | 4 --- selfdrive/ui/translations/main_ja.ts | 4 --- selfdrive/ui/translations/main_ko.ts | 4 --- selfdrive/ui/translations/main_pt-BR.ts | 4 --- selfdrive/ui/translations/main_zh-CHS.ts | 4 --- selfdrive/ui/translations/main_zh-CHT.ts | 4 --- 9 files changed, 64 deletions(-) diff --git a/common/params.cc b/common/params.cc index bc1e414faa..530ffe3051 100644 --- a/common/params.cc +++ b/common/params.cc @@ -189,7 +189,6 @@ std::unordered_map keys = { {"ApiCache_Device", PERSISTENT}, {"ApiCache_DriveStats", PERSISTENT}, {"ApiCache_NavDestinations", PERSISTENT}, - {"ApiCache_Owner", PERSISTENT}, {"Offroad_BadNvme", CLEAR_ON_MANAGER_START}, {"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc index 2fa84a232f..fb4aea2b1c 100644 --- a/selfdrive/ui/qt/widgets/prime.cc +++ b/selfdrive/ui/qt/widgets/prime.cc @@ -143,42 +143,9 @@ PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QFrame(parent) { mainLayout->addWidget(primeWidget); - // comma points layout - QWidget *pointsWidget = new QWidget; - pointsWidget->setObjectName("primeWidget"); - QVBoxLayout *pointsLayout = new QVBoxLayout(pointsWidget); - pointsLayout->setContentsMargins(60, 50, 60, 50); - - QLabel *commaPoints = new QLabel(tr("COMMA POINTS")); - commaPoints->setStyleSheet("font-size: 41px; font-family: Inter SemiBold;"); - pointsLayout->addWidget(commaPoints, 0, Qt::AlignTop); - - points = new QLabel("0"); - points->setStyleSheet("font-size: 91px; font-weight: bold;"); - pointsLayout->addWidget(points, 0, Qt::AlignTop); - - mainLayout->addWidget(pointsWidget); - mainLayout->addStretch(); - - // set up API requests - if (auto dongleId = getDongleId()) { - QString url = CommaApi::BASE_URL + "/v1/devices/" + *dongleId + "/owner"; - RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_Owner", 6); - QObject::connect(repeater, &RequestRepeater::requestDone, this, &PrimeUserWidget::replyFinished); - } } -void PrimeUserWidget::replyFinished(const QString &response) { - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting points"; - return; - } - - QJsonObject json = doc.object(); - points->setText(QString::number(json["points"].toInt())); -} PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QFrame(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); diff --git a/selfdrive/ui/qt/widgets/prime.h b/selfdrive/ui/qt/widgets/prime.h index c5732799b8..9c7b4460fc 100644 --- a/selfdrive/ui/qt/widgets/prime.h +++ b/selfdrive/ui/qt/widgets/prime.h @@ -51,12 +51,6 @@ class PrimeUserWidget : public QFrame { public: explicit PrimeUserWidget(QWidget* parent = 0); - -private: - QLabel *points; - -private slots: - void replyFinished(const QString &response); }; diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 2e4e833e07..5bec3f674a 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -521,10 +521,6 @@ location set CONNECT.COMMA.AI CONNECT.COMMA.AI - - COMMA POINTS - COMMA PUNKTE -
QObject diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 06435d3b41..43e4974784 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -522,10 +522,6 @@ location set CONNECT.COMMA.AI CONNECT.COMMA.AI - - COMMA POINTS - COMMA POINTS - QObject diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index b55a56a061..c985fae0e9 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -522,10 +522,6 @@ location set CONNECT.COMMA.AI CONNECT.COMMA.AI - - COMMA POINTS - COMMA POINTS - QObject diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 34fbc8abf0..9eeedea29c 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -523,10 +523,6 @@ trabalho definido CONNECT.COMMA.AI CONNECT.COMMA.AI - - COMMA POINTS - PONTOS COMMA - QObject diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 7cacc72f1c..9302047ab0 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -520,10 +520,6 @@ location set CONNECT.COMMA.AI CONNECT.COMMA.AI - - COMMA POINTS - COMMA POINTS点数 - QObject diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index e559ca88a6..5d17a7b86a 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -522,10 +522,6 @@ location set CONNECT.COMMA.AI CONNECT.COMMA.AI - - COMMA POINTS - COMMA 積分 - QObject From 2d34083cd8a507ed06f0139f496930cfe4bde820 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Tue, 30 May 2023 20:33:01 -0700 Subject: [PATCH 103/283] Test navmodel (#28272) * Test navmodel * removed comment * Updated model_replay ref * read tiles from azure bucket * updated ref commit --- Jenkinsfile | 2 +- selfdrive/test/openpilotci.py | 20 +++++++++----- selfdrive/test/process_replay/model_replay.py | 27 ++++++++++++++++++- .../process_replay/model_replay_ref_commit | 2 +- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e0e8511251..c7ef88811f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -220,7 +220,7 @@ pipeline { steps { phone_steps("tici-common", [ ["build", "cd selfdrive/manager && ./build.py"], - ["model replay", "cd selfdrive/test/process_replay && NO_NAV=1 ./model_replay.py"], + ["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], ]) } } diff --git a/selfdrive/test/openpilotci.py b/selfdrive/test/openpilotci.py index 1d1b6ec423..5f4b9f1f35 100755 --- a/selfdrive/test/openpilotci.py +++ b/selfdrive/test/openpilotci.py @@ -11,10 +11,7 @@ def get_url(route_name, segment_num, log_type="rlog"): ext = "hevc" if log_type.endswith('camera') else "bz2" return BASE_URL + f"{route_name.replace('|', '/')}/{segment_num}/{log_type}.{ext}" - -def upload_file(path, name): - from azure.storage.blob import BlockBlobService # pylint: disable=import-error - +def get_sas_token(): sas_token = os.environ.get("AZURE_TOKEN", None) if os.path.isfile(TOKEN_PATH): sas_token = open(TOKEN_PATH).read().strip() @@ -22,9 +19,20 @@ def upload_file(path, name): if sas_token is None: sas_token = subprocess.check_output("az storage container generate-sas --account-name commadataci --name openpilotci --https-only --permissions lrw \ --expiry $(date -u '+%Y-%m-%dT%H:%M:%SZ' -d '+1 hour') --auth-mode login --as-user --output tsv", shell=True).decode().strip("\n") - service = BlockBlobService(account_name="commadataci", sas_token=sas_token) + + return sas_token + +def upload_bytes(data, name): + from azure.storage.blob import BlockBlobService # pylint: disable=import-error + service = BlockBlobService(account_name="commadataci", sas_token=get_sas_token()) + service.create_blob_from_bytes("openpilotci", name, data) + return BASE_URL + name + +def upload_file(path, name): + from azure.storage.blob import BlockBlobService # pylint: disable=import-error + service = BlockBlobService(account_name="commadataci", sas_token=get_sas_token()) service.create_blob_from_path("openpilotci", name, path) - return "https://commadataci.blob.core.windows.net/openpilotci/" + name + return BASE_URL + name if __name__ == "__main__": diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index 68cbb28aaf..9c1ec4e931 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -25,7 +25,7 @@ SEGMENT = 6 MAX_FRAMES = 100 if PC else 600 NAV_FRAMES = 50 -NO_NAV = "NO_NAV" in os.environ # TODO: make map renderer work in CI +NO_NAV = "NO_NAV" in os.environ SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0")) VIPC_STREAM = {"roadCameraState": VisionStreamType.VISION_STREAM_ROAD, "driverCameraState": VisionStreamType.VISION_STREAM_DRIVER, @@ -209,6 +209,31 @@ if __name__ == "__main__": 'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True) } + # Update tile refs + if update: + import urllib + import requests + import threading + import http.server + from selfdrive.test.openpilotci import upload_bytes + os.environ['MAPS_HOST'] = 'http://localhost:5000' + + class HTTPRequestHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + assert len(self.path) > 10 # Sanity check on path length + r = requests.get(f'https://api.mapbox.com{self.path}', timeout=30) + upload_bytes(r.content, urllib.parse.urlparse(self.path).path.lstrip('/')) + self.send_response(r.status_code) + self.send_header('Content-type','text/html') + self.end_headers() + self.wfile.write(r.content) + + server = http.server.HTTPServer(("127.0.0.1", 5000), HTTPRequestHandler) + thread = threading.Thread(None, server.serve_forever, daemon=True) + thread.start() + else: + os.environ['MAPS_HOST'] = BASE_URL.rstrip('/') + # run replays log_msgs = model_replay(lr, frs) if not NO_NAV: diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 448c7b4291..e458f817d3 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -e3cf1856830902bede2d1c9ca3d0d60e5504ae20 +91bdaeae5a7141ff6bb6fd80672521c8d63f644c From 2ff1eadb1153a26a177a55f1f29426ebf328b655 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 30 May 2023 20:46:44 -0700 Subject: [PATCH 104/283] cars: log non-critical car faults (#28338) * log non-noEntry acc faults non * adasFaulted * bump * bump again * bump agaiiinn * remove event * bump to master * add fixme comment and fix * whoops * switch --- cereal | 2 +- selfdrive/car/honda/carstate.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 9b6b53396f..3f950792d8 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 9b6b53396fff6ec7541a5415901d892e57756b91 +Subproject commit 3f950792d896b9c6e1846e522757abb3eae3087d diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 57a2f4a846..35d6279902 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -195,8 +195,16 @@ class CarState(CarStateBase): if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS: ret.accFaulted = bool(cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"]) - elif self.CP.openpilotLongitudinalControl: - ret.accFaulted = bool(cp.vl["STANDSTILL"]["BRAKE_ERROR_1"] or cp.vl["STANDSTILL"]["BRAKE_ERROR_2"]) + else: + # On some cars, these two signals are always 1, this flag is masking a bug in release + # FIXME: find and set the ACC faulted signals on more platforms + if self.CP.openpilotLongitudinalControl: + ret.accFaulted = bool(cp.vl["STANDSTILL"]["BRAKE_ERROR_1"] or cp.vl["STANDSTILL"]["BRAKE_ERROR_2"]) + + # Log non-critical stock ACC/LKAS faults if Nidec (camera) + if self.CP.carFingerprint not in HONDA_BOSCH: + ret.carFaultedNonCritical = bool(cp_cam.vl["ACC_HUD"]["ACC_PROBLEM"] or cp_cam.vl["LKAS_HUD"]["LKAS_PROBLEM"]) + ret.espDisabled = cp.vl["VSA_STATUS"]["ESP_DISABLED"] != 0 ret.wheelSpeeds = self.get_wheel_speeds( @@ -331,12 +339,15 @@ class CarState(CarStateBase): ("AEB_REQ_1", "BRAKE_COMMAND"), ("FCW", "BRAKE_COMMAND"), ("CHIME", "BRAKE_COMMAND"), + ("LKAS_PROBLEM", "LKAS_HUD"), ("FCM_OFF", "ACC_HUD"), ("FCM_OFF_2", "ACC_HUD"), ("FCM_PROBLEM", "ACC_HUD"), + ("ACC_PROBLEM", "ACC_HUD"), ("ICONS", "ACC_HUD")] checks += [ ("ACC_HUD", 10), + ("LKAS_HUD", 10), ("BRAKE_COMMAND", 50), ] From e853af2ca6c84352b9cd7a17f9dae9a77f5cb3c1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 1 Jun 2023 02:22:47 +0800 Subject: [PATCH 105/283] cabana: fix seeking issue (#28346) * fix seekto * rename loadThumbnail to parseQLog --- tools/cabana/videowidget.cc | 25 +++++++++++++++---------- tools/cabana/videowidget.h | 6 +++--- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index ed0704a676..2af1db4635 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -157,26 +157,31 @@ Slider::Slider(QWidget *parent) : thumbnail_label(parent), QSlider(Qt::Horizonta update(); }); timer->start(2000); - thumnail_future = QtConcurrent::run(this, &Slider::loadThumbnails); + QObject::connect(can, &AbstractStream::eventsMerged, [this]() { + if (!qlog_future) { + qlog_future = std::make_unique>(QtConcurrent::run(this, &Slider::parseQLog)); + } + }); } Slider::~Slider() { - abort_load_thumbnail = true; - thumnail_future.waitForFinished(); + abort_parse_qlog = true; + if (qlog_future) { + qlog_future->waitForFinished(); + } } -void Slider::loadThumbnails() { +void Slider::parseQLog() { const auto &segments = can->route()->segments(); - double max_time = 0; - for (auto it = segments.rbegin(); it != segments.rend() && !abort_load_thumbnail; ++it) { + for (auto it = segments.rbegin(); it != segments.rend() && !abort_parse_qlog; ++it) { LogReader log; std::string qlog = it->second.qlog.toStdString(); - if (!qlog.empty() && log.load(qlog, &abort_load_thumbnail, {cereal::Event::Which::THUMBNAIL, cereal::Event::Which::CONTROLS_STATE}, true, 0, 3)) { - if (max_time == 0 && !log.events.empty()) { - max_time = (*(log.events.rbegin()))->mono_time / 1e9 - can->routeStartTime(); + if (!qlog.empty() && log.load(qlog, &abort_parse_qlog, {cereal::Event::Which::THUMBNAIL, cereal::Event::Which::CONTROLS_STATE}, true, 0, 3)) { + if (it == segments.rbegin() && !log.events.empty()) { + double max_time = (*(log.events.rbegin()))->mono_time / 1e9 - can->routeStartTime(); emit updateMaximumTime(max_time); } - for (auto ev = log.events.cbegin(); ev != log.events.cend() && !abort_load_thumbnail; ++ev) { + for (auto ev = log.events.cbegin(); ev != log.events.cend() && !abort_parse_qlog; ++ev) { if ((*ev)->which == cereal::Event::Which::THUMBNAIL) { auto thumb = (*ev)->event.getThumbnail(); auto data = thumb.getThumbnail(); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 59bc112bd0..56edc83809 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -44,16 +44,16 @@ private: bool event(QEvent *event) override; void sliderChange(QAbstractSlider::SliderChange change) override; void paintEvent(QPaintEvent *ev) override; - void loadThumbnails(); + void parseQLog(); double max_sec = 0; int slider_x = -1; std::vector> timeline; std::mutex thumbnail_lock; - std::atomic abort_load_thumbnail = false; + std::atomic abort_parse_qlog = false; QMap thumbnails; std::map alerts; - QFuture thumnail_future; + std::unique_ptr> qlog_future; InfoLabel thumbnail_label; friend class VideoWidget; }; From 9abe95c949747e87f059ea0810c03b01305110c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 1 Jun 2023 00:01:12 +0200 Subject: [PATCH 106/283] locationd: add filterState (#28340) * Add filterState to published messages * Hide it behind DEBUG flag * Update cereal * Update cereal --- cereal | 2 +- selfdrive/locationd/locationd.cc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index 3f950792d8..172b9b7dc0 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 3f950792d896b9c6e1846e522757abb3eae3087d +Subproject commit 172b9b7dc07fc5e8609a0e7160e525f1eb4b1b68 diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 9ee9e33fb4..af31218499 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -35,6 +35,8 @@ const float GPS_VEL_STD_RESET_THRESHOLD = 0.5; const float GPS_ORIENTATION_ERROR_RESET_THRESHOLD = 1.0; const int GPS_ORIENTATION_ERROR_RESET_CNT = 3; +const bool DEBUG = getenv("DEBUG") != nullptr && std::string(getenv("DEBUG")) != "0"; + static VectorXd floatlist2vector(const capnp::List::Reader& floatlist) { VectorXd res(floatlist.size()); for (int i = 0; i < floatlist.size(); i++) { @@ -161,6 +163,9 @@ void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { init_measurement(fix.initVelocityCalibrated(), vel_calib, vel_calib_std, this->calibrated); init_measurement(fix.initAngularVelocityCalibrated(), ang_vel_calib, ang_vel_calib_std, this->calibrated); init_measurement(fix.initAccelerationCalibrated(), acc_calib, acc_calib_std, this->calibrated); + if (DEBUG) { + init_measurement(fix.initFilterState(), predicted_state, predicted_std, true); + } double old_mean = 0.0, new_mean = 0.0; int i = 0; From fc2bd16e72a89feb270f99468cfd8d14ccbab4fd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 May 2023 16:29:11 -0700 Subject: [PATCH 107/283] Deprecate brakeUnavailable event (#28351) * bump cereal * deprecate * Update selfdrive/controls/lib/events.py --- cereal | 2 +- selfdrive/controls/lib/events.py | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/cereal b/cereal index 172b9b7dc0..7e1d67d415 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 172b9b7dc07fc5e8609a0e7160e525f1eb4b1b68 +Subproject commit 7e1d67d4155651c6288e4b65fb7788871742e752 diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index b935e24615..da358127c7 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -885,12 +885,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { ET.NO_ENTRY: NoEntryAlert("LKAS Fault: Restart the Car"), }, - EventName.brakeUnavailable: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Fault: Restart the Car"), - ET.PERMANENT: NormalPermanentAlert("Cruise Fault: Restart the car to engage"), - ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), - }, - EventName.reverseGear: { ET.PERMANENT: Alert( "Reverse\nGear", From cbd3e5b94685220f78297786e6a121e1165946b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 31 May 2023 16:33:07 -0700 Subject: [PATCH 108/283] Plannerd: higher upper bound cost for lateral planner (#28352) 20k not good upper bound for 10s --- selfdrive/controls/lib/lateral_planner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index fc29aeb087..0593becba5 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -112,7 +112,7 @@ class LateralPlanner: self.last_cloudlog_t = t cloudlog.warning("Lateral mpc - nan: True") - if self.lat_mpc.cost > 20000. or mpc_nans: + if self.lat_mpc.cost > 1e6 or mpc_nans: self.solution_invalid_cnt += 1 else: self.solution_invalid_cnt = 0 From c67759c7f0d5ae977bfd71744ea50974c292b800 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 31 May 2023 20:00:20 -0700 Subject: [PATCH 109/283] boardd: less spam msgs on PC (#28353) --- selfdrive/boardd/spi.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index fe237d5f27..e10fd744d5 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -68,6 +68,10 @@ PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { // revs of the comma three may not support this speed uint32_t spi_speed = 50000000; + if (!util::file_exists(SPI_DEVICE)) { + goto fail; + } + spi_fd = open(SPI_DEVICE.c_str(), O_RDWR); if (spi_fd < 0) { LOGE("failed opening SPI device %d", spi_fd); From 024abe6455d44c7616ca7c694643c5324d0d371c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 31 May 2023 21:30:50 -0700 Subject: [PATCH 110/283] car docs: document parts of parts (#28292) * more stuff * even more * all parts func * start to use it * include self in parts * use car_parts_new * not used * more usages * remove get_parts * remove more commented stuff * remove iter * clean up some more stuff * more more * ford * optional optional * nissan * use new classes * fix tests * fix * order * no more required * connector * CARS.md --------- Co-authored-by: Maxime Desroches --- docs/CARS.md | 502 ++++++++++++++--------------- selfdrive/car/chrysler/values.py | 10 +- selfdrive/car/docs.py | 8 +- selfdrive/car/docs_definitions.py | 199 ++++++------ selfdrive/car/ford/values.py | 6 +- selfdrive/car/gm/values.py | 6 +- selfdrive/car/honda/values.py | 6 +- selfdrive/car/hyundai/values.py | 148 ++++----- selfdrive/car/mazda/values.py | 4 +- selfdrive/car/nissan/values.py | 9 +- selfdrive/car/subaru/values.py | 8 +- selfdrive/car/tests/test_docs.py | 9 +- selfdrive/car/toyota/values.py | 4 +- selfdrive/car/volkswagen/values.py | 4 +- 14 files changed, 466 insertions(+), 457 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 6ee21f3517..136101e97b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -8,258 +8,258 @@ A supported vehicle is one that just works when you install a comma three. All s |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| -|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|GV70 (2.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|GV70 (3.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Genesis|GV80 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 USB-C coupler
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai O connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai I connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Tucson Hybrid 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro EV 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Ram connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV70 (2.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV70 (3.5T Trim) 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Genesis|GV80 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai O connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai I connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson Hybrid 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro EV 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai D connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Ram connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| ### Footnotes 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index b5ee26cee8..24f3f92a92 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -5,7 +5,7 @@ from typing import Dict, List, Optional, Union from cereal import car from panda.python import uds from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts +from selfdrive.car.docs_definitions import CarHarness, CarInfo, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -60,7 +60,7 @@ RAM_CARS = RAM_DT | RAM_HD @dataclass class ChryslerCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC)" - car_parts: CarParts = CarParts.common([CarPart.fca]) + car_parts: CarParts = CarParts.common([CarHarness.fca]) CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { @@ -74,10 +74,10 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { ], CAR.JEEP_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"), CAR.JEEP_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"), - CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", car_parts=CarParts.common([CarPart.ram])), + CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", car_parts=CarParts.common([CarHarness.ram])), CAR.RAM_HD: [ - ChryslerCarInfo("Ram 2500 2020-22", car_parts=CarParts.common([CarPart.ram])), - ChryslerCarInfo("Ram 3500 2019-22", car_parts=CarParts.common([CarPart.ram])), + ChryslerCarInfo("Ram 2500 2020-22", car_parts=CarParts.common([CarHarness.ram])), + ChryslerCarInfo("Ram 3500 2019-22", car_parts=CarParts.common([CarHarness.ram])), ], } diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index afeb457544..143d64bd52 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -10,7 +10,7 @@ from typing import Dict, List from cereal import car from common.basedir import BASEDIR from selfdrive.car import gen_empty_fingerprint -from selfdrive.car.docs_definitions import CarInfo, CarPart, Column, CommonFootnote, PartType +from selfdrive.car.docs_definitions import CarInfo, Column, CommonFootnote, PartType from selfdrive.car.car_helpers import interfaces, get_interface_attr @@ -61,9 +61,9 @@ def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str: template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) footnotes = [fn.value.text for fn in get_all_footnotes()] - cars_md: str = template.render(all_car_info=all_car_info, CarPart=CarPart, - PartType=PartType, group_by_make=group_by_make, - footnotes=footnotes, Column=Column) + cars_md: str = template.render(all_car_info=all_car_info, PartType=PartType, + group_by_make=group_by_make, footnotes=footnotes, + Column=Column) return cars_md diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 2088cc63b3..c1ebc35cab 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -30,120 +30,131 @@ class Star(Enum): EMPTY = "empty" -class PartType(Enum): - connector = "Connector" - device = "Device" - cable = "Cable" - accessory = "Accessory" - mount = "Mount" +# A part + its comprised parts +@dataclass +class BasePart: + name: str + parts: List[Enum] = field(default_factory=list) + + def all_parts(self): + # Recursively get all parts + _parts = 'parts' + parts = [] + parts.extend(getattr(self, _parts)) + for part in getattr(self, _parts): + parts.extend(part.value.all_parts()) + + return parts + + +class EnumBase(Enum): + @property + def type(self): + return PartType(self.__class__) + + +class Mount(EnumBase): + mount = BasePart("mount") + angled_mount = BasePart("angled mount") + + +class Cable(EnumBase): + rj45_cable_7ft = BasePart("RJ45 cable (7 ft)") + long_obdc_cable = BasePart("long OBD-C cable") + usb_a_2_a_cable = BasePart("USB A-A cable") + usbc_otg_cable = BasePart("USB C OTG cable") + usbc_coupler = BasePart("USB-C coupler") + obd_c_cable_1_5ft = BasePart("OBD-C cable (1.5 ft)") + right_angle_obd_c_cable_1_5ft = BasePart("right angle OBD-C cable (1.5 ft)") + + +class Accessory(EnumBase): + harness_box = BasePart("harness box") + comma_power_v2 = BasePart("comma power v2") @dataclass -class Part: - name: str - - @property - def type(self) -> PartType: - raise NotImplementedError +class BaseCarHarness(BasePart): + parts: List[Enum] = field(default_factory=lambda: [Accessory.harness_box, Accessory.comma_power_v2, Cable.rj45_cable_7ft]) + has_connector: bool = True # without are hidden on the harness connector page -class Connector(Part): - @property - def type(self) -> PartType: - return PartType.connector +class CarHarness(EnumBase): + nidec = BaseCarHarness("Honda Nidec connector") + bosch_a = BaseCarHarness("Honda Bosch A connector") + bosch_b = BaseCarHarness("Honda Bosch B connector") + toyota = BaseCarHarness("Toyota connector") + subaru_a = BaseCarHarness("Subaru A connector") + subaru_b = BaseCarHarness("Subaru B connector") + fca = BaseCarHarness("FCA connector") + ram = BaseCarHarness("Ram connector") + vw = BaseCarHarness("VW connector") + j533 = BaseCarHarness("J533 connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler]) + hyundai_a = BaseCarHarness("Hyundai A connector") + hyundai_b = BaseCarHarness("Hyundai B connector") + hyundai_c = BaseCarHarness("Hyundai C connector") + hyundai_d = BaseCarHarness("Hyundai D connector") + hyundai_e = BaseCarHarness("Hyundai E connector") + hyundai_f = BaseCarHarness("Hyundai F connector") + hyundai_g = BaseCarHarness("Hyundai G connector") + hyundai_h = BaseCarHarness("Hyundai H connector") + hyundai_i = BaseCarHarness("Hyundai I connector") + hyundai_j = BaseCarHarness("Hyundai J connector") + hyundai_k = BaseCarHarness("Hyundai K connector") + hyundai_l = BaseCarHarness("Hyundai L connector") + hyundai_m = BaseCarHarness("Hyundai M connector") + hyundai_n = BaseCarHarness("Hyundai N connector") + hyundai_o = BaseCarHarness("Hyundai O connector") + hyundai_p = BaseCarHarness("Hyundai P connector") + hyundai_q = BaseCarHarness("Hyundai Q connector") + custom = BaseCarHarness("Developer connector") + obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable, Cable.long_obdc_cable], has_connector=False) + gm = BaseCarHarness("GM connector") + nissan_a = BaseCarHarness("Nissan A connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable, Cable.usbc_coupler]) + nissan_b = BaseCarHarness("Nissan B connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable, Cable.usbc_coupler]) + mazda = BaseCarHarness("Mazda connector") + ford_q3 = BaseCarHarness("Ford Q3 connector") + ford_q4 = BaseCarHarness("Ford Q4 connector") -class Accessory(Part): - @property - def type(self) -> PartType: - return PartType.accessory +class Device(EnumBase): + three = BasePart("comma three", parts=[Mount.mount, Cable.right_angle_obd_c_cable_1_5ft]) + # variant of comma three with angled mounts + three_angled_mount = BasePart("comma three", parts=[Mount.angled_mount, Cable.right_angle_obd_c_cable_1_5ft]) + red_panda = BasePart("red panda") -class Mount(Part): - @property - def type(self) -> PartType: - return PartType.mount +class Kit(EnumBase): + red_panda_kit = BasePart("CAN FD panda kit", parts=[Device.red_panda, Accessory.harness_box, Cable.usb_a_2_a_cable, Cable.usbc_otg_cable, Cable.obd_c_cable_1_5ft]) -class Cable(Part): - @property - def type(self) -> PartType: - return PartType.cable +class PartType(Enum): + accessory = Accessory + cable = Cable + connector = CarHarness + device = Device + kit = Kit + mount = Mount -class Device(Part): - @property - def type(self) -> PartType: - return PartType.device - - -class CarPart(Enum): - nidec = Connector("Honda Nidec connector") - bosch_a = Connector("Honda Bosch A connector") - bosch_b = Connector("Honda Bosch B connector") - toyota = Connector("Toyota connector") - subaru_a = Connector("Subaru A connector") - subaru_b = Connector("Subaru B connector") - fca = Connector("FCA connector") - ram = Connector("Ram connector") - vw = Connector("VW connector") - j533 = Connector("J533 connector") - hyundai_a = Connector("Hyundai A connector") - hyundai_b = Connector("Hyundai B connector") - hyundai_c = Connector("Hyundai C connector") - hyundai_d = Connector("Hyundai D connector") - hyundai_e = Connector("Hyundai E connector") - hyundai_f = Connector("Hyundai F connector") - hyundai_g = Connector("Hyundai G connector") - hyundai_h = Connector("Hyundai H connector") - hyundai_i = Connector("Hyundai I connector") - hyundai_j = Connector("Hyundai J connector") - hyundai_k = Connector("Hyundai K connector") - hyundai_l = Connector("Hyundai L connector") - hyundai_m = Connector("Hyundai M connector") - hyundai_n = Connector("Hyundai N connector") - hyundai_o = Connector("Hyundai O connector") - hyundai_p = Connector("Hyundai P connector") - hyundai_q = Connector("Hyundai Q connector") - custom = Connector("Developer connector") - obd_ii = Connector("OBD-II connector") - gm = Connector("GM connector") - nissan_a = Connector("Nissan A connector") - nissan_b = Connector("Nissan B connector") - mazda = Connector("Mazda connector") - ford_q3 = Connector("Ford Q3 connector") - ford_q4 = Connector("Ford Q4 connector") - - comma_3 = Device("comma 3") - red_panda = Device("red panda") - - harness_box = Accessory("harness box") - comma_power_v2 = Accessory("comma power v2") - - mount = Mount("mount") - angled_mount = Mount("angled mount") - - rj45_cable_7ft = Cable("RJ45 cable (7 ft)") - long_obdc_cable = Cable("long OBD-C cable") - usb_a_2_a_cable = Cable("USB A-A cable") - usbc_otg_cable = Cable("USB C OTG cable") - usbc_coupler = Cable("USB-C coupler") - obd_c_cable_1_5ft = Cable("OBD-C cable (1.5 ft)") - right_angle_obd_c_cable_1_5ft = Cable("right angle OBD-C cable (1.5 ft)") - - -DEFAULT_CAR_PARTS: List[CarPart] = [CarPart.harness_box, CarPart.comma_power_v2, CarPart.rj45_cable_7ft, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft] +DEFAULT_CAR_PARTS: List[EnumBase] = [Device.three] @dataclass class CarParts: - parts: List[CarPart] = field(default_factory=list) + parts: List[EnumBase] = field(default_factory=list) @classmethod - def common(cls, add: List[CarPart] = None, remove: List[CarPart] = None): + def common(cls, add: List[EnumBase] = None, remove: List[EnumBase] = None): p = [part for part in (add or []) + DEFAULT_CAR_PARTS if part not in (remove or [])] return cls(p) + def all_parts(self): + parts = [] + for part in self.parts: + parts.extend(part.value.all_parts()) + return self.parts + parts + CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only", "shop_footnote"], defaults=(False, False)) @@ -251,8 +262,8 @@ class CarInfo: if self.car_parts.parts: model_years = self.model + (' ' + self.years if self.years else '') buy_link = f'Buy Here' - parts = '
'.join([f"- {self.car_parts.parts.count(part)} {part.value.name}" for part in - sorted(set(self.car_parts.parts), key=lambda part: str(part.value.name))]) + car_parts_docs = self.car_parts.all_parts() + parts = '
'.join([f"- {car_parts_docs.count(part)} {part.value.name}" for part in sorted(set(car_parts_docs), key=lambda part: str(part.value.name))]) hardware_col = f'
View{parts}
{buy_link}
' self.row: Dict[Enum, Union[str, Star]] = { diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 41fa8f3475..fbb6917b34 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -4,7 +4,7 @@ from typing import Dict, List, Set, Union from cereal import car from selfdrive.car import AngleRateLimit, dbc_dict -from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts +from selfdrive.car.docs_definitions import CarInfo, CarParts, CarHarness, Device from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -66,11 +66,11 @@ DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base @dataclass class FordCarInfo(CarInfo): package: str = "Co-Pilot360 Assist+" - car_parts: CarParts = CarParts.common([CarPart.ford_q3]) + car_parts: CarParts = CarParts.common([CarHarness.ford_q3]) def init_make(self, CP: car.CarParams): if CP.carFingerprint in (CAR.BRONCO_SPORT_MK1, CAR.MAVERICK_MK1): - self.car_parts = CarParts.common([CarPart.ford_q3, CarPart.angled_mount], remove=[CarPart.mount]) + self.car_parts = CarParts([Device.three_angled_mount, CarHarness.ford_q3]) CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 60c76f135b..b21c303d85 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -5,7 +5,7 @@ from typing import Dict, List, Union from cereal import car from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column +from selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column Ecu = car.CarParams.Ecu @@ -89,9 +89,9 @@ class GMCarInfo(CarInfo): def init_make(self, CP: car.CarParams): if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera: - self.car_parts = CarParts.common([CarPart.gm]) + self.car_parts = CarParts.common([CarHarness.gm]) else: - self.car_parts = CarParts([CarPart.obd_ii, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft]) + self.car_parts = CarParts.common([CarHarness.obd_ii]) self.footnotes.append(Footnote.OBD_II) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index d19281fce7..7c1c5f0920 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -6,7 +6,7 @@ from cereal import car from common.conversions import Conversions as CV from panda.python import uds from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column +from selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = car.CarParams.Ecu @@ -110,9 +110,9 @@ class HondaCarInfo(CarInfo): def init_make(self, CP: car.CarParams): if CP.carFingerprint in HONDA_BOSCH: - self.car_parts = CarParts.common([CarPart.bosch_b]) if CP.carFingerprint in HONDA_BOSCH_RADARLESS else CarParts.common([CarPart.bosch_a]) + self.car_parts = CarParts.common([CarHarness.bosch_b]) if CP.carFingerprint in HONDA_BOSCH_RADARLESS else CarParts.common([CarHarness.bosch_a]) else: - self.car_parts = CarParts.common([CarPart.nidec]) + self.car_parts = CarParts.common([CarHarness.nidec]) CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 8dbd7a65f0..20b7bacaff 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -6,7 +6,7 @@ from cereal import car from panda.python import uds from common.conversions import Conversions as CV from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column +from selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -147,114 +147,114 @@ class HyundaiCarInfo(CarInfo): CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.ELANTRA: [ - HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_b])), - HyundaiCarInfo("Hyundai Elantra GT 2017-19", car_parts=CarParts.common([CarPart.hyundai_e])), - HyundaiCarInfo("Hyundai i30 2017-19", car_parts=CarParts.common([CarPart.hyundai_e])), + HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_b])), + HyundaiCarInfo("Hyundai Elantra GT 2017-19", car_parts=CarParts.common([CarHarness.hyundai_e])), + HyundaiCarInfo("Hyundai i30 2017-19", car_parts=CarParts.common([CarHarness.hyundai_e])), ], - CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarPart.hyundai_k])), - CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarPart.hyundai_k])), + CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarHarness.hyundai_k])), + CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarHarness.hyundai_k])), CAR.HYUNDAI_GENESIS: [ - HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_j])), # TODO: check 2015 packages - HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_j])), + HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_j])), # TODO: check 2015 packages + HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_j])), ], - CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", car_parts=CarParts.common([CarPart.hyundai_c])), - CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", car_parts=CarParts.common([CarPart.hyundai_h])), # TODO: confirm 2020-21 harness - CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", car_parts=CarParts.common([CarPart.hyundai_c])), - CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", car_parts=CarParts.common([CarPart.hyundai_h])), - CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", car_parts=CarParts.common([CarPart.hyundai_c])), - CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2020-22", "All", car_parts=CarParts.common([CarPart.hyundai_h])), - CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020", car_parts=CarParts.common([CarPart.hyundai_b])), - CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarPart.hyundai_g])), - CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", car_parts=CarParts.common([CarPart.hyundai_o])), - CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", car_parts=CarParts.common([CarPart.hyundai_i])), # TODO: check packages - CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", car_parts=CarParts.common([CarPart.hyundai_d])), - CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="https://youtu.be/VnHzSTygTS4", car_parts=CarParts.common([CarPart.hyundai_l])), - CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_l])), - CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarPart.hyundai_l])), - CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", car_parts=CarParts.common([CarPart.hyundai_a])), - CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarPart.hyundai_e])), + CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", car_parts=CarParts.common([CarHarness.hyundai_c])), + CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", car_parts=CarParts.common([CarHarness.hyundai_h])), # TODO: confirm 2020-21 harness + CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", car_parts=CarParts.common([CarHarness.hyundai_c])), + CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_h])), + CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", car_parts=CarParts.common([CarHarness.hyundai_c])), + CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_h])), + CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020", car_parts=CarParts.common([CarHarness.hyundai_b])), + CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarHarness.hyundai_g])), + CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", car_parts=CarParts.common([CarHarness.hyundai_o])), + CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", car_parts=CarParts.common([CarHarness.hyundai_i])), # TODO: check packages + CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", car_parts=CarParts.common([CarHarness.hyundai_d])), + CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="https://youtu.be/VnHzSTygTS4", car_parts=CarParts.common([CarHarness.hyundai_l])), + CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])), + CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_l])), + CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", car_parts=CarParts.common([CarHarness.hyundai_a])), + CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarHarness.hyundai_e])), CAR.TUCSON: [ - HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_l])), - HyundaiCarInfo("Hyundai Tucson Diesel 2019", car_parts=CarParts.common([CarPart.hyundai_l])), + HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_l])), + HyundaiCarInfo("Hyundai Tucson Diesel 2019", car_parts=CarParts.common([CarHarness.hyundai_l])), ], CAR.PALISADE: [ - HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", car_parts=CarParts.common([CarPart.hyundai_h])), - HyundaiCarInfo("Kia Telluride 2020-22", "All", car_parts=CarParts.common([CarPart.hyundai_h])), + HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", car_parts=CarParts.common([CarHarness.hyundai_h])), + HyundaiCarInfo("Kia Telluride 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_h])), ], - CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_e])), - CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_e])), + CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_a])), CAR.IONIQ_5: [ - HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_q])), - HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarPart.hyundai_k])), - HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarPart.hyundai_q])), + HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_q])), + HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_k])), + HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])), ], CAR.TUCSON_4TH_GEN: [ - HyundaiCarInfo("Hyundai Tucson 2022", car_parts=CarParts.common([CarPart.hyundai_n])), - HyundaiCarInfo("Hyundai Tucson 2023", "All", car_parts=CarParts.common([CarPart.hyundai_n])), + HyundaiCarInfo("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])), + HyundaiCarInfo("Hyundai Tucson 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), ], - CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_n])), - CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", car_parts=CarParts.common([CarPart.hyundai_n])), + CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), + CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", car_parts=CarParts.common([CarHarness.hyundai_n])), # Kia CAR.KIA_FORTE: [ - HyundaiCarInfo("Kia Forte 2019-21", car_parts=CarParts.common([CarPart.hyundai_g])), - HyundaiCarInfo("Kia Forte 2023", car_parts=CarParts.common([CarPart.hyundai_e])), + HyundaiCarInfo("Kia Forte 2019-21", car_parts=CarParts.common([CarHarness.hyundai_g])), + HyundaiCarInfo("Kia Forte 2023", car_parts=CarParts.common([CarHarness.hyundai_e])), ], - CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", car_parts=CarParts.common([CarPart.hyundai_a])), - CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", car_parts=CarParts.common([CarHarness.hyundai_a])), + CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020", car_parts=CarParts.common([CarHarness.hyundai_a])), CAR.KIA_NIRO_EV: [ - HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_h])), - HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_f])), - HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_c])), - HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarPart.hyundai_h])), + HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])), + HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_f])), + HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_c])), + HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])), ], - CAR.KIA_NIRO_EV_2ND_GEN: HyundaiCarInfo("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarPart.hyundai_a])), + CAR.KIA_NIRO_EV_2ND_GEN: HyundaiCarInfo("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a])), CAR.KIA_NIRO_PHEV: [ - HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarPart.hyundai_c])), - HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", car_parts=CarParts.common([CarPart.hyundai_d])), + HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])), + HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_d])), ], CAR.KIA_NIRO_HEV_2021: [ - HyundaiCarInfo("Kia Niro Hybrid 2021-22", car_parts=CarParts.common([CarPart.hyundai_f])), # TODO: 2021 could be hyundai_d, verify + HyundaiCarInfo("Kia Niro Hybrid 2021-22", car_parts=CarParts.common([CarHarness.hyundai_f])), # TODO: 2021 could be hyundai_d, verify ], - CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarPart.hyundai_a])), - CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarPart.hyundai_b])), # TODO: may support 2016, 2018 - CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarPart.hyundai_g])), + CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_a])), + CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarHarness.hyundai_b])), # TODO: may support 2016, 2018 + CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarHarness.hyundai_g])), CAR.KIA_OPTIMA_H: [ HyundaiCarInfo("Kia Optima Hybrid 2017", "Advanced Smart Cruise Control"), # TODO: may support adjacent years HyundaiCarInfo("Kia Optima Hybrid 2019"), ], - CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", car_parts=CarParts.common([CarPart.hyundai_a])), - CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", car_parts=CarParts.common([CarPart.hyundai_n])), + CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", car_parts=CarParts.common([CarHarness.hyundai_a])), + CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", car_parts=CarParts.common([CarHarness.hyundai_n])), CAR.KIA_SORENTO: [ - HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarPart.hyundai_c])), - HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarPart.hyundai_e])), + HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarHarness.hyundai_c])), + HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarHarness.hyundai_e])), ], - CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", car_parts=CarParts.common([CarPart.hyundai_k])), - CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", car_parts=CarParts.common([CarPart.hyundai_a])), - CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", car_parts=CarParts.common([CarPart.hyundai_n])), - CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", car_parts=CarParts.common([CarPart.hyundai_c])), - CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", car_parts=CarParts.common([CarPart.hyundai_k])), - CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", car_parts=CarParts.common([CarPart.hyundai_e])), + CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", car_parts=CarParts.common([CarHarness.hyundai_k])), + CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", car_parts=CarParts.common([CarHarness.hyundai_a])), + CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_n])), + CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", car_parts=CarParts.common([CarHarness.hyundai_c])), + CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k])), + CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", car_parts=CarParts.common([CarHarness.hyundai_e])), CAR.KIA_EV6: [ - HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_p])), - HyundaiCarInfo("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarPart.hyundai_l])), - HyundaiCarInfo("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarPart.hyundai_p])) + HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_p])), + HyundaiCarInfo("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])), + HyundaiCarInfo("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p])) ], # Genesis CAR.GENESIS_GV60_EV_1ST_GEN: [ - HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", car_parts=CarParts.common([CarPart.hyundai_a])), - HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", car_parts=CarParts.common([CarPart.hyundai_k])), + HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a])), + HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])), ], - CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", car_parts=CarParts.common([CarPart.hyundai_f])), - CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", car_parts=CarParts.common([CarPart.hyundai_f])), + CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_f])), + CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_f])), CAR.GENESIS_GV70_1ST_GEN: [ - HyundaiCarInfo("Genesis GV70 (2.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_l])), - HyundaiCarInfo("Genesis GV70 (3.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarPart.hyundai_m])), + HyundaiCarInfo("Genesis GV70 (2.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])), + HyundaiCarInfo("Genesis GV70 (3.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_m])), ], - CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarPart.hyundai_h])), - CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", car_parts=CarParts.common([CarPart.hyundai_c])), - CAR.GENESIS_GV80: HyundaiCarInfo("Genesis GV80 2023", "All", car_parts=CarParts.common([CarPart.hyundai_m])), + CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h])), + CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", car_parts=CarParts.common([CarHarness.hyundai_c])), + CAR.GENESIS_GV80: HyundaiCarInfo("Genesis GV80 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_m])), } class Buttons: diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 864462186e..3fbf34e5fe 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -3,7 +3,7 @@ from typing import Dict, List, Union from cereal import car from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts +from selfdrive.car.docs_definitions import CarHarness, CarInfo, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -37,7 +37,7 @@ class CAR: @dataclass class MazdaCarInfo(CarInfo): package: str = "All" - car_parts: CarParts = CarParts.common([CarPart.mazda]) + car_parts: CarParts = CarParts.common([CarHarness.mazda]) CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = { diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 0194a71aa1..568c33630b 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -4,7 +4,7 @@ from typing import Dict, List, Optional, Union from cereal import car from panda.python import uds from selfdrive.car import AngleRateLimit, dbc_dict -from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts +from selfdrive.car.docs_definitions import CarInfo, CarHarness, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -30,13 +30,10 @@ class CAR: ALTIMA = "NISSAN ALTIMA 2020" -NISSAN_PARTS: List[CarPart] = [CarPart.harness_box, CarPart.rj45_cable_7ft, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft] - - @dataclass class NissanCarInfo(CarInfo): package: str = "ProPILOT Assist" - car_parts: CarParts = CarParts([CarPart.nissan_a] + NISSAN_PARTS) + car_parts: CarParts = CarParts.common([CarHarness.nissan_a]) CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = { @@ -44,7 +41,7 @@ CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = { CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-23", video_link="https://youtu.be/vaMbtAh_0cY"), CAR.LEAF_IC: None, # same platforms CAR.ROGUE: NissanCarInfo("Nissan Rogue 2018-20"), - CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", car_parts=CarParts([CarPart.nissan_b] + NISSAN_PARTS)), + CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", car_parts=CarParts.common([CarHarness.nissan_b])), } FINGERPRINTS = { diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 660bdcaaab..12367d9b5a 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -5,7 +5,7 @@ from typing import Dict, List, Union from cereal import car from panda.python import uds from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts +from selfdrive.car.docs_definitions import CarHarness, CarInfo, CarParts from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = car.CarParams.Ecu @@ -53,13 +53,13 @@ class CAR: @dataclass class SubaruCarInfo(CarInfo): package: str = "EyeSight Driver Assistance" - car_parts: CarParts = CarParts.common([CarPart.subaru_a]) + car_parts: CarParts = CarParts.common([CarHarness.subaru_a]) CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = { CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-21", "All"), - CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All", car_parts=CarParts.common([CarPart.subaru_b])), - CAR.LEGACY: SubaruCarInfo("Subaru Legacy 2020-22", "All", car_parts=CarParts.common([CarPart.subaru_b])), + CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All", car_parts=CarParts.common([CarHarness.subaru_b])), + CAR.LEGACY: SubaruCarInfo("Subaru Legacy 2020-22", "All", car_parts=CarParts.common([CarHarness.subaru_b])), CAR.IMPREZA: [ SubaruCarInfo("Subaru Impreza 2017-19"), SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"), diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py index 4b53489b73..f42c094856 100755 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -5,7 +5,7 @@ import unittest from selfdrive.car.car_helpers import interfaces, get_interface_attr from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info -from selfdrive.car.docs_definitions import CarPart, Column, PartType, Star +from selfdrive.car.docs_definitions import Cable, Column, PartType, Star from selfdrive.car.honda.values import CAR as HONDA @@ -74,11 +74,12 @@ class TestCarDocs(unittest.TestCase): if car.name == "comma body": raise unittest.SkipTest - car_part_type = [p.value.type for p in car.car_parts.parts] - self.assertTrue(len(car.car_parts.parts) > 0, f"Need to specify car parts: {car.name}") + car_part_type = [p.type for p in car.car_parts.all_parts()] + car_parts = [p for p in car.car_parts.all_parts()] + self.assertTrue(len(car_parts) > 0, f"Need to specify car parts: {car.name}") self.assertTrue(car_part_type.count(PartType.connector) == 1, f"Need to specify one harness connector: {car.name}") self.assertTrue(car_part_type.count(PartType.mount) == 1, f"Need to specify one mount: {car.name}") - self.assertTrue(CarPart.right_angle_obd_c_cable_1_5ft in car.car_parts.parts, f"Need to specify a right angle OBD-C cable (1.5ft): {car.name}") + self.assertTrue(Cable.right_angle_obd_c_cable_1_5ft in car_parts, f"Need to specify a right angle OBD-C cable (1.5ft): {car.name}") if __name__ == "__main__": diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 5738ba30f5..ab1a05a926 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -6,7 +6,7 @@ from typing import Dict, List, Union from cereal import car from common.conversions import Conversions as CV from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, CarPart, CarParts +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, CarParts, CarHarness from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -102,7 +102,7 @@ class Footnote(Enum): @dataclass class ToyotaCarInfo(CarInfo): package: str = "All" - car_parts: CarParts = CarParts.common([CarPart.toyota]) + car_parts: CarParts = CarParts.common([CarHarness.toyota]) CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 7fe29674a4..02c579b0c1 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -7,7 +7,7 @@ from cereal import car from panda.python import uds from opendbc.can.can_define import CANDefine from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarParts, CarHarness, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -166,7 +166,7 @@ class Footnote(Enum): @dataclass class VWCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC) & Lane Assist" - car_parts: CarParts = CarParts([CarPart.j533, CarPart.harness_box, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft]) + car_parts: CarParts = CarParts.common([CarHarness.j533]) def init_make(self, CP: car.CarParams): self.footnotes.insert(0, Footnote.VW_EXP_LONG) From 15ac8c041b638e8989e1391387530c7195ef7403 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 31 May 2023 23:04:30 -0700 Subject: [PATCH 111/283] UI snapshot tool (#28356) * UI: snapshot testing tool * gitignore * cleanup * remove prime type arg * rename * add script * commit snapshots * use base setup * updates * always run base * echo * use imagemagick * test_snapshots * fixes * update * set language * revert * default arg * just remove translations * formatting * output arg * improved help * fix assets * change dir back before saving snapshot * unused imports * simpler * add default to description * use uiUpdate signal --- selfdrive/ui/SConscript | 1 + selfdrive/ui/tests/.gitignore | 1 + selfdrive/ui/tests/ui_snapshot.cc | 66 +++++++++++++++++++++++++++++++ selfdrive/ui/tests/ui_snapshot.h | 5 +++ 4 files changed, 73 insertions(+) create mode 100644 selfdrive/ui/tests/ui_snapshot.cc create mode 100644 selfdrive/ui/tests/ui_snapshot.h diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index a8c8463bd7..f54d72ae31 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -64,6 +64,7 @@ qt_env.Program("_ui", qt_src + [asset_obj], LIBS=qt_libs) if GetOption('test'): qt_src.remove("main.cc") # replaced by test_runner qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs) + qt_env.Program('tests/ui_snapshot', [asset_obj, "tests/ui_snapshot.cc"] + qt_src, LIBS=qt_libs) # build translation files diff --git a/selfdrive/ui/tests/.gitignore b/selfdrive/ui/tests/.gitignore index 26335744f3..94ba9a3a97 100644 --- a/selfdrive/ui/tests/.gitignore +++ b/selfdrive/ui/tests/.gitignore @@ -2,3 +2,4 @@ test playsound test_sound test_translations +ui_snapshot diff --git a/selfdrive/ui/tests/ui_snapshot.cc b/selfdrive/ui/tests/ui_snapshot.cc new file mode 100644 index 0000000000..14e0fab835 --- /dev/null +++ b/selfdrive/ui/tests/ui_snapshot.cc @@ -0,0 +1,66 @@ +#include "selfdrive/ui/tests/ui_snapshot.h" + +#include +#include +#include +#include +#include + +#include "selfdrive/ui/qt/home.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/window.h" +#include "selfdrive/ui/ui.h" + +void saveWidgetAsImage(QWidget *widget, const QString &fileName) { + QImage image(widget->size(), QImage::Format_ARGB32); + QPainter painter(&image); + widget->render(&painter); + image.save(fileName); +} + +int main(int argc, char *argv[]) { + initApp(argc, argv); + + QApplication app(argc, argv); + + QCommandLineParser parser; + parser.setApplicationDescription("Take a snapshot of the UI."); + parser.addHelpOption(); + parser.addOption(QCommandLineOption(QStringList() << "o" + << "output", + "Output image file path. The file's suffix is used to " + "determine the format. Supports PNG and JPEG formats. " + "Defaults to \"snapshot.png\".", + "file", "snapshot.png")); + parser.process(app); + + const QString output = parser.value("output"); + if (output.isEmpty()) { + qCritical() << "No output file specified"; + return 1; + } + + auto current = QDir::current(); + + // change working directory to find assets + if (!QDir::setCurrent(QCoreApplication::applicationDirPath() + QDir::separator() + "..")) { + qCritical() << "Failed to set current directory"; + return 1; + } + + MainWindow w; + w.setFixedSize(2160, 1080); + w.show(); + app.installEventFilter(&w); + + // restore working directory + QDir::setCurrent(current.absolutePath()); + + // wait for the UI to update + QObject::connect(uiState(), &UIState::uiUpdate, [&](const UIState &s) { + saveWidgetAsImage(&w, output); + app.quit(); + }); + + return app.exec(); +} diff --git a/selfdrive/ui/tests/ui_snapshot.h b/selfdrive/ui/tests/ui_snapshot.h new file mode 100644 index 0000000000..b4699f6af5 --- /dev/null +++ b/selfdrive/ui/tests/ui_snapshot.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void saveWidgetAsImage(QWidget *widget, const QString &fileName); From a971affeb051b1b6a16ba7cf7f22c63e1947e2fe Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 1 Jun 2023 00:04:07 -0700 Subject: [PATCH 112/283] Kia Ceed: display lane lines in HUD (#28357) ceed uses the new format --- selfdrive/car/hyundai/hyundaican.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index f23d9d5328..dc5a5b6286 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -37,7 +37,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, - CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020): + CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED): values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsOpt_USM"] = 2 From a19799cbe968a4f0633b591ff9ed27a9a3f35b61 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 1 Jun 2023 15:04:46 +0800 Subject: [PATCH 113/283] cabana: fix multiple dialog popups (#28358) fix multiple popups --- tools/cabana/mainwin.cc | 11 ++++++----- tools/cabana/mainwin.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d3da4a1500..fd24c3f6db 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -351,12 +351,13 @@ void MainWindow::streamStarted() { } void MainWindow::eventsMerged() { - if (!can->liveStreaming()) { - auto fingerprint = can->carFingerprint(); - video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPRINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); + if (!can->liveStreaming() && std::exchange(car_fingerprint, can->carFingerprint()) != car_fingerprint) { + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPRINT: %2") + .arg(can->routeName()) + .arg(car_fingerprint.isEmpty() ? tr("Unknown Car") : car_fingerprint)); // Don't overwrite already loaded DBC - if (!dbc()->msgCount() && !fingerprint.isEmpty()) { - auto dbc_name = fingerprint_to_dbc[fingerprint]; + if (!dbc()->msgCount() && !car_fingerprint.isEmpty()) { + auto dbc_name = fingerprint_to_dbc[car_fingerprint]; if (dbc_name != QJsonValue::Undefined) { loadDBCFromOpendbc(dbc_name.toString()); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index f56d37a252..72ed0ae5cc 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -95,6 +95,7 @@ protected: QAction *save_dbc = nullptr; QAction *save_dbc_as = nullptr; QAction *copy_dbc_to_clipboard = nullptr; + QString car_fingerprint; int prev_undostack_index = 0; int prev_undostack_count = 0; friend class OnlineHelp; From cd57b340c1974c52146015b0211bd6ec50388c7e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Jun 2023 10:26:08 -0700 Subject: [PATCH 114/283] test_onroad: ignore vehicleModelInvalid (#28335) * test_onroad: ignore vehicleModelInvalid * not for all ci --- selfdrive/controls/controlsd.py | 3 ++- selfdrive/test/test_onroad.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index a584a44cb9..6d653091d2 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -34,6 +34,7 @@ LANE_DEPARTURE_THRESHOLD = 0.1 REPLAY = "REPLAY" in os.environ SIMULATION = "SIMULATION" in os.environ +TESTING_CLOSET = "TESTING_CLOSET" in os.environ NOSENSOR = "NOSENSOR" in os.environ IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd"} @@ -373,7 +374,7 @@ class Controls: else: self.logged_comm_issue = None - if not self.sm['liveParameters'].valid: + if not self.sm['liveParameters'].valid and not TESTING_CLOSET: self.events.add(EventName.vehicleModelInvalid) if not self.sm['lateralPlan'].mpcSolutionValid: self.events.add(EventName.plannerError) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index acc98c85d6..793530b964 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -98,6 +98,7 @@ class TestOnroad(unittest.TestCase): params = Params() params.clear_all() set_params_enabled() + os.environ['TESTING_CLOSET'] = '1' if os.path.exists(ROOT): shutil.rmtree(ROOT) From 702e4120e6b5a02f1d25089c198f1a0e9a813ac1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Jun 2023 10:36:06 -0700 Subject: [PATCH 115/283] boardd: smaller spi chunk size (#28360) Co-authored-by: Comma Device --- selfdrive/boardd/spi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index e10fd744d5..924f416ead 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -163,7 +163,7 @@ int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int l } int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len, unsigned int timeout) { - const int xfer_size = 0x40 * 15; + const int xfer_size = 0x40 * 5; int ret = 0; uint16_t length = (tx_data != NULL) ? tx_len : rx_len; From 2373f785560be95aa9a64e949466cf0929f7e6f9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 2 Jun 2023 01:36:40 +0800 Subject: [PATCH 116/283] cabana: support displaying&editing overlapping signals in the binary view (#28359) --- tools/cabana/binaryview.cc | 93 +++++++++++++++++++++----------------- tools/cabana/binaryview.h | 6 +-- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 3a03ee0b70..50f66e5182 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -277,8 +277,12 @@ void BinaryViewModel::refresh() { } if (j == start) sig->is_little_endian ? items[idx].is_lsb = true : items[idx].is_msb = true; if (j == end) sig->is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; - items[idx].bg_color = getColor(sig); - items[idx].sigs.push_back(sig); + + auto &sigs = items[idx].sigs; + sigs.push_back(sig); + if (sigs.size() > 1) { + std::sort(sigs.begin(), sigs.end(), [](auto l, auto r) { return l->size > r->size; }); + } } } } else { @@ -353,15 +357,11 @@ BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(pa hex_font.setBold(true); } -bool BinaryItemDelegate::isSameColor(const QModelIndex &index, int dx, int dy) const { - QModelIndex index2 = index.sibling(index.row() + dy, index.column() + dx); - if (!index2.isValid()) { - return false; - } - auto color1 = ((const BinaryViewModel::Item *)index.internalPointer())->bg_color; - auto color2 = ((const BinaryViewModel::Item *)index2.internalPointer())->bg_color; - // Ignore alpha - return (color1.red() == color2.red()) && (color2.green() == color2.green()) && (color1.blue() == color2.blue()); +bool BinaryItemDelegate::hasSignal(const QModelIndex &index, int dx, int dy, const cabana::Signal *sig) const { + if (!index.isValid()) return false; + auto model = (const BinaryViewModel*)(index.model()); + int idx = (index.row() + dy) * model->columnCount() + index.column() + dx; + return (idx >=0 && idx < model->items.size()) ? model->items[idx].sigs.contains(sig) : false; } void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -370,28 +370,32 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->save(); if (index.column() == 8) { - painter->setFont(hex_font); - painter->fillRect(option.rect, item->bg_color); + if (item->valid) { + painter->setFont(hex_font); + painter->fillRect(option.rect, item->bg_color); + } } else if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, selection_color); painter->setPen(option.palette.color(QPalette::BrightText)); - } else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) { // not resizing - QColor bg = item->bg_color; - if (bin_view->hovered_sig && item->sigs.contains(bin_view->hovered_sig)) { - bg.setAlpha(255); - painter->fillRect(option.rect, bg.darker(125)); // 4/5x brightness - painter->setPen(option.palette.color(QPalette::BrightText)); - } else { - if (item->sigs.size() > 0) { - drawBorder(painter, option, index); - bg.setAlpha(std::max(50, bg.alpha())); + } else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) { // not resizing + if (item->sigs.size() > 0) { + for (auto &s : item->sigs) { + if (s == bin_view->hovered_sig) { + painter->fillRect(option.rect, getColor(bin_view->hovered_sig).darker(125)); // 4/5x brightness + } else { + drawSignalCell(painter, option, index, s); + } } - painter->fillRect(option.rect, bg); - painter->setPen(option.palette.color(QPalette::Text)); + } else if (item->valid) { + painter->fillRect(option.rect, item->bg_color); } + auto color_role = item->sigs.contains(bin_view->hovered_sig) ? QPalette::BrightText : QPalette::Text; + painter->setPen(option.palette.color(color_role)); } - if (!item->valid) { + if (item->sigs.size() > 1) { + painter->fillRect(option.rect, QBrush(Qt::darkGray, Qt::Dense7Pattern)); + } else if (!item->valid) { painter->fillRect(option.rect, QBrush(Qt::darkGray, Qt::BDiagPattern)); } painter->drawText(option.rect, Qt::AlignCenter, item->val); @@ -403,44 +407,49 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } // Draw border on edge of signal -void BinaryItemDelegate::drawBorder(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - auto item = (const BinaryViewModel::Item *)index.internalPointer(); - QColor border_color = item->bg_color; - border_color.setAlphaF(1.0); - - bool draw_left = !isSameColor(index, -1, 0); - bool draw_top = !isSameColor(index, 0, -1); - bool draw_right = !isSameColor(index, 1, 0); - bool draw_bottom = !isSameColor(index, 0, 1); +void BinaryItemDelegate::drawSignalCell(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index, const cabana::Signal *sig) const { + bool draw_left = !hasSignal(index, -1, 0, sig); + bool draw_top = !hasSignal(index, 0, -1, sig); + bool draw_right = !hasSignal(index, 1, 0, sig); + bool draw_bottom = !hasSignal(index, 0, 1, sig); const int spacing = 2; QRect rc = option.rect.adjusted(draw_left * 3, draw_top * spacing, draw_right * -3, draw_bottom * -spacing); QRegion subtract; if (!draw_top) { - if (!draw_left && !isSameColor(index, -1, -1)) { + if (!draw_left && !hasSignal(index, -1, -1, sig)) { subtract += QRect{rc.left(), rc.top(), 3, spacing}; - } else if (!draw_right && !isSameColor(index, 1, -1)) { + } else if (!draw_right && !hasSignal(index, 1, -1, sig)) { subtract += QRect{rc.right() - 2, rc.top(), 3, spacing}; } } if (!draw_bottom) { - if (!draw_left && !isSameColor(index, -1, 1)) { + if (!draw_left && !hasSignal(index, -1, 1, sig)) { subtract += QRect{rc.left(), rc.bottom() - (spacing - 1), 3, spacing}; - } else if (!draw_right && !isSameColor(index, 1, 1)) { + } else if (!draw_right && !hasSignal(index, 1, 1, sig)) { subtract += QRect{rc.right() - 2, rc.bottom() - (spacing - 1), 3, spacing}; } } + painter->setClipRegion(QRegion(rc).subtracted(subtract)); - painter->setPen(QPen(border_color, 1)); + auto item = (const BinaryViewModel::Item *)index.internalPointer(); + auto sig_color = getColor(sig); + QColor color = sig_color; + color.setAlpha(item->bg_color.alpha()); + painter->fillRect(rc, Qt::white); + painter->fillRect(rc, color); + + color = sig_color.darker(125); + painter->setPen(QPen(color, 1)); if (draw_left) painter->drawLine(rc.topLeft(), rc.bottomLeft()); if (draw_right) painter->drawLine(rc.topRight(), rc.bottomRight()); if (draw_bottom) painter->drawLine(rc.bottomLeft(), rc.bottomRight()); if (draw_top) painter->drawLine(rc.topLeft(), rc.topRight()); - painter->setClipRegion(QRegion(rc).subtracted(subtract)); if (!subtract.isEmpty()) { // fill gaps inside corners. - painter->setPen(QPen(border_color, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); + painter->setPen(QPen(color, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); for (auto &r : subtract) { painter->drawRect(r); } diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index f80b4520ed..baeb79cba7 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -14,8 +14,8 @@ public: BinaryItemDelegate(QObject *parent); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setSelectionColor(const QColor &color) { selection_color = color; } - bool isSameColor(const QModelIndex &index, int dx, int dy) const; - void drawBorder(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + bool hasSignal(const QModelIndex &index, int dx, int dy, const cabana::Signal *sig) const; + void drawSignalCell(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index, const cabana::Signal *sig) const; QFont small_font, hex_font; QColor selection_color; @@ -40,7 +40,7 @@ public: } struct Item { - QColor bg_color = QColor(102, 86, 169, 0); + QColor bg_color = QColor(102, 86, 169, 255); bool is_msb = false; bool is_lsb = false; QString val; From ede75c9e9b849505f2ea91d00abe9073ad0b3cd4 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Thu, 1 Jun 2023 21:37:10 +0200 Subject: [PATCH 117/283] fix typos --- selfdrive/boardd/panda.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 72c3ea36ca..625e4218f7 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -13,11 +13,11 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { // try USB first, then SPI try { handle = std::make_unique(serial); - LOGW("conntected to %s over USB", serial.c_str()); + LOGW("connected to %s over USB", serial.c_str()); } catch (std::exception &e) { #ifndef __APPLE__ handle = std::make_unique(serial); - LOGW("conntected to %s over SPI", serial.c_str()); + LOGW("connected to %s over SPI", serial.c_str()); #endif } From 7ab9569a0815022ef5abadc6a3641bd93e4a8f6d Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Thu, 1 Jun 2023 23:25:55 +0200 Subject: [PATCH 118/283] Tesla: half the DAS_steeringControl message rate (#27503) * half the freq, double the limit * fix bug * bump submodule --- panda | 2 +- selfdrive/car/tesla/carcontroller.py | 21 +++++++++++---------- selfdrive/car/tesla/teslacan.py | 4 ++-- selfdrive/car/tesla/values.py | 4 ++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/panda b/panda index 00c2689487..5847d7dbc0 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 00c26894876484d2c5a5b63a1c33c28f0f9b15dd +Subproject commit 5847d7dbc05df3bc76243b6704b9d98544eb53df diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py index 1f18c3d0ea..aeaaba88e7 100644 --- a/selfdrive/car/tesla/carcontroller.py +++ b/selfdrive/car/tesla/carcontroller.py @@ -24,17 +24,18 @@ class CarController: hands_on_fault = CS.steer_warning == "EAC_ERROR_HANDS_ON" and CS.hands_on_level >= 3 lkas_enabled = CC.latActive and not hands_on_fault - if lkas_enabled: - # Angular rate limit based on speed - apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo, CarControllerParams) + if self.frame % 2 == 0: + if lkas_enabled: + # Angular rate limit based on speed + apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo, CarControllerParams) - # To not fault the EPS - apply_angle = clip(apply_angle, CS.out.steeringAngleDeg - 20, CS.out.steeringAngleDeg + 20) - else: - apply_angle = CS.out.steeringAngleDeg + # To not fault the EPS + apply_angle = clip(apply_angle, CS.out.steeringAngleDeg - 20, CS.out.steeringAngleDeg + 20) + else: + apply_angle = CS.out.steeringAngleDeg - self.apply_angle_last = apply_angle - can_sends.append(self.tesla_can.create_steering_control(apply_angle, lkas_enabled, self.frame)) + self.apply_angle_last = apply_angle + can_sends.append(self.tesla_can.create_steering_control(apply_angle, lkas_enabled, (self.frame // 2) % 16)) # Longitudinal control (in sync with stock message, about 40Hz) if self.CP.openpilotLongitudinalControl: @@ -59,7 +60,7 @@ class CarController: # TODO: HUD control new_actuators = actuators.copy() - new_actuators.steeringAngleDeg = apply_angle + new_actuators.steeringAngleDeg = self.apply_angle_last self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/car/tesla/teslacan.py b/selfdrive/car/tesla/teslacan.py index c84f2c45be..a491c030f8 100644 --- a/selfdrive/car/tesla/teslacan.py +++ b/selfdrive/car/tesla/teslacan.py @@ -17,12 +17,12 @@ class TeslaCAN: ret += sum(dat) return ret & 0xFF - def create_steering_control(self, angle, enabled, frame): + def create_steering_control(self, angle, enabled, counter): values = { "DAS_steeringAngleRequest": -angle, "DAS_steeringHapticRequest": 0, "DAS_steeringControlType": 1 if enabled else 0, - "DAS_steeringControlCounter": (frame % 16), + "DAS_steeringControlCounter": counter, } data = self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values)[2] diff --git a/selfdrive/car/tesla/values.py b/selfdrive/car/tesla/values.py index bac025a9c5..f79e5f0097 100644 --- a/selfdrive/car/tesla/values.py +++ b/selfdrive/car/tesla/values.py @@ -103,8 +103,8 @@ BUTTONS = [ ] class CarControllerParams: - ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., .8, .15]) - ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., 3.5, 0.4]) + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[10., 1.6, .3]) + ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[10., 7.0, 0.8]) JERK_LIMIT_MAX = 8 JERK_LIMIT_MIN = -8 ACCEL_TO_SPEED_MULTIPLIER = 3 From bcdecfa084e682a85d158d6fa44a92fad9588b5f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 1 Jun 2023 15:45:33 -0700 Subject: [PATCH 119/283] Toyota: remove incorrect FW version (#28362) Update values.py --- selfdrive/car/toyota/values.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index ab1a05a926..422c7560fe 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1131,7 +1131,6 @@ FW_VERSIONS = { b'\x01896630EF8000\x00\x00\x00\x00', b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630E66100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', - b'\x01896630EA1000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630EB3000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630EB3100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', ], From 9f616982ed8bd3b493b791dd42b19415f4c6b7a9 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 1 Jun 2023 19:42:46 -0700 Subject: [PATCH 120/283] Ford: fix minor typos --- selfdrive/car/ford/values.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index fbb6917b34..edc40f629c 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -4,7 +4,7 @@ from typing import Dict, List, Set, Union from cereal import car from selfdrive.car import AngleRateLimit, dbc_dict -from selfdrive.car.docs_definitions import CarInfo, CarParts, CarHarness, Device +from selfdrive.car.docs_definitions import CarHarness, CarInfo, CarParts, Device from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu @@ -29,8 +29,8 @@ class CarControllerParams: ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 25], angle_v=[0.000225, 0.00015]) CURVATURE_ERROR = 0.002 # ~6 degrees at 10 m/s, ~10 degrees at 35 m/s - ACCEL_MAX = 2.0 # m/s^s max acceleration - ACCEL_MIN = -3.5 # m/s^s max deceleration + ACCEL_MAX = 2.0 # m/s^2 max acceleration + ACCEL_MIN = -3.5 # m/s^2 max deceleration MIN_GAS = -0.5 INACTIVE_GAS = -5.0 From 342d0e7bd58070eb6c81659e14d8de691ac28e50 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 1 Jun 2023 19:49:42 -0700 Subject: [PATCH 121/283] rename angled mount (#28368) rename mount --- docs/CARS.md | 4 ++-- selfdrive/car/docs_definitions.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 136101e97b..89d282c021 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -31,11 +31,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| -|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount (8 degrees)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 angled mount (8 degrees)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai F connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index c1ebc35cab..23b460147e 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -55,7 +55,7 @@ class EnumBase(Enum): class Mount(EnumBase): mount = BasePart("mount") - angled_mount = BasePart("angled mount") + angled_mount_8_degrees = BasePart("angled mount (8 degrees)") class Cable(EnumBase): @@ -120,7 +120,7 @@ class CarHarness(EnumBase): class Device(EnumBase): three = BasePart("comma three", parts=[Mount.mount, Cable.right_angle_obd_c_cable_1_5ft]) # variant of comma three with angled mounts - three_angled_mount = BasePart("comma three", parts=[Mount.angled_mount, Cable.right_angle_obd_c_cable_1_5ft]) + three_angled_mount = BasePart("comma three", parts=[Mount.angled_mount_8_degrees, Cable.right_angle_obd_c_cable_1_5ft]) red_panda = BasePart("red panda") From 99398176dfe707c84d591400b90838fdfceda5a3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 2 Jun 2023 11:52:08 +0800 Subject: [PATCH 122/283] cabana: Support parsing of multi-line comments (#28345) --- tools/cabana/dbc/dbcfile.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index e1b31489b9..d9938b0fbc 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -194,8 +194,8 @@ void DBCFile::parseExtraInfo(const QString &content) { static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); - static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"(.*)\";)"); - static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"(.*)\";)"); + static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"([^"]*)\";)"); + static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"([^"]*)\";)"); static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))"); int line_num = 0; @@ -212,7 +212,7 @@ void DBCFile::parseExtraInfo(const QString &content) { uint32_t address = 0; while (!stream.atEnd()) { ++line_num; - line = stream.readLine().trimmed(); + line = stream.readLine(); if (line.startsWith("BO_ ")) { auto match = bo_regexp.match(line); dbc_assert(match.hasMatch()); @@ -244,12 +244,20 @@ void DBCFile::parseExtraInfo(const QString &content) { } } } else if (line.startsWith("CM_ BO_")) { + if (!line.endsWith("\";")) { + int pos = stream.pos() - line.length() - 1; + line = content.mid(pos, content.indexOf("\";", pos)); + } auto match = msg_comment_regexp.match(line); dbc_assert(match.hasMatch()); if (auto m = (cabana::Msg *)msg(match.captured(1).toUInt())) { m->comment = match.captured(2).trimmed(); } } else if (line.startsWith("CM_ SG_ ")) { + if (!line.endsWith("\";")) { + int pos = stream.pos() - line.length() - 1; + line = content.mid(pos, content.indexOf("\";", pos)); + } auto match = sg_comment_regexp.match(line); dbc_assert(match.hasMatch()); if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { From dba437bc8d9219287e90bc3903cd5eed72b3218d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 1 Jun 2023 21:05:49 -0700 Subject: [PATCH 123/283] Remove INDI controller (#28366) --- release/files_common | 1 - selfdrive/controls/controlsd.py | 3 - selfdrive/controls/lib/latcontrol_indi.py | 120 ------------------ .../controls/lib/tests/test_latcontrol.py | 3 +- 4 files changed, 1 insertion(+), 126 deletions(-) delete mode 100644 selfdrive/controls/lib/latcontrol_indi.py diff --git a/release/files_common b/release/files_common index 781600ac8f..af1fca176f 100644 --- a/release/files_common +++ b/release/files_common @@ -181,7 +181,6 @@ selfdrive/controls/lib/desire_helper.py selfdrive/controls/lib/drive_helpers.py selfdrive/controls/lib/events.py selfdrive/controls/lib/latcontrol_angle.py -selfdrive/controls/lib/latcontrol_indi.py selfdrive/controls/lib/latcontrol_torque.py selfdrive/controls/lib/latcontrol_pid.py selfdrive/controls/lib/latcontrol.py diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 6d653091d2..3903340c8d 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -20,7 +20,6 @@ from selfdrive.controls.lib.drive_helpers import VCruiseHelper, get_lag_adjusted from selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED from selfdrive.controls.lib.longcontrol import LongControl from selfdrive.controls.lib.latcontrol_pid import LatControlPID -from selfdrive.controls.lib.latcontrol_indi import LatControlINDI from selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD from selfdrive.controls.lib.latcontrol_torque import LatControlTorque from selfdrive.controls.lib.events import Events, ET @@ -152,8 +151,6 @@ class Controls: self.LaC = LatControlAngle(self.CP, self.CI) elif self.CP.lateralTuning.which() == 'pid': self.LaC = LatControlPID(self.CP, self.CI) - elif self.CP.lateralTuning.which() == 'indi': - self.LaC = LatControlINDI(self.CP, self.CI) elif self.CP.lateralTuning.which() == 'torque': self.LaC = LatControlTorque(self.CP, self.CI) diff --git a/selfdrive/controls/lib/latcontrol_indi.py b/selfdrive/controls/lib/latcontrol_indi.py deleted file mode 100644 index dca82c6729..0000000000 --- a/selfdrive/controls/lib/latcontrol_indi.py +++ /dev/null @@ -1,120 +0,0 @@ -import math -import numpy as np - -from cereal import log -from common.filter_simple import FirstOrderFilter -from common.numpy_fast import clip, interp -from common.realtime import DT_CTRL -from selfdrive.controls.lib.latcontrol import LatControl - - -class LatControlINDI(LatControl): - def __init__(self, CP, CI): - super().__init__(CP, CI) - self.angle_steers_des = 0. - - A = np.array([[1.0, DT_CTRL, 0.0], - [0.0, 1.0, DT_CTRL], - [0.0, 0.0, 1.0]]) - C = np.array([[1.0, 0.0, 0.0], - [0.0, 1.0, 0.0]]) - - # Q = np.matrix([[1e-2, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 10.0]]) - # R = np.matrix([[1e-2, 0.0], [0.0, 1e3]]) - - # (x, l, K) = control.dare(np.transpose(A), np.transpose(C), Q, R) - # K = np.transpose(K) - K = np.array([[7.30262179e-01, 2.07003658e-04], - [7.29394177e+00, 1.39159419e-02], - [1.71022442e+01, 3.38495381e-02]]) - - self.speed = 0. - - self.K = K - self.A_K = A - np.dot(K, C) - self.x = np.array([[0.], [0.], [0.]]) - - self._RC = (CP.lateralTuning.indi.timeConstantBP, CP.lateralTuning.indi.timeConstantV) - self._G = (CP.lateralTuning.indi.actuatorEffectivenessBP, CP.lateralTuning.indi.actuatorEffectivenessV) - self._outer_loop_gain = (CP.lateralTuning.indi.outerLoopGainBP, CP.lateralTuning.indi.outerLoopGainV) - self._inner_loop_gain = (CP.lateralTuning.indi.innerLoopGainBP, CP.lateralTuning.indi.innerLoopGainV) - - self.steer_filter = FirstOrderFilter(0., self.RC, DT_CTRL) - self.reset() - - @property - def RC(self): - return interp(self.speed, self._RC[0], self._RC[1]) - - @property - def G(self): - return interp(self.speed, self._G[0], self._G[1]) - - @property - def outer_loop_gain(self): - return interp(self.speed, self._outer_loop_gain[0], self._outer_loop_gain[1]) - - @property - def inner_loop_gain(self): - return interp(self.speed, self._inner_loop_gain[0], self._inner_loop_gain[1]) - - def reset(self): - super().reset() - self.steer_filter.x = 0. - self.speed = 0. - - def update(self, active, CS, VM, params, last_actuators, steer_limited, desired_curvature, desired_curvature_rate, llk): - self.speed = CS.vEgo - # Update Kalman filter - y = np.array([[math.radians(CS.steeringAngleDeg)], [math.radians(CS.steeringRateDeg)]]) - self.x = np.dot(self.A_K, self.x) + np.dot(self.K, y) - - indi_log = log.ControlsState.LateralINDIState.new_message() - indi_log.steeringAngleDeg = math.degrees(self.x[0]) - indi_log.steeringRateDeg = math.degrees(self.x[1]) - indi_log.steeringAccelDeg = math.degrees(self.x[2]) - - steers_des = VM.get_steer_from_curvature(-desired_curvature, CS.vEgo, params.roll) - steers_des += math.radians(params.angleOffsetDeg) - indi_log.steeringAngleDesiredDeg = math.degrees(steers_des) - - # desired rate is the desired rate of change in the setpoint, not the absolute desired curvature - rate_des = VM.get_steer_from_curvature(-desired_curvature_rate, CS.vEgo, 0) - indi_log.steeringRateDesiredDeg = math.degrees(rate_des) - - if not active: - indi_log.active = False - self.steer_filter.x = 0.0 - output_steer = 0 - else: - # Expected actuator value - self.steer_filter.update_alpha(self.RC) - self.steer_filter.update(last_actuators.steer) - - # Compute acceleration error - rate_sp = self.outer_loop_gain * (steers_des - self.x[0]) + rate_des - accel_sp = self.inner_loop_gain * (rate_sp - self.x[1]) - accel_error = accel_sp - self.x[2] - - # Compute change in actuator - g_inv = 1. / self.G - delta_u = g_inv * accel_error - - # If steering pressed, only allow wind down - if CS.steeringPressed and (delta_u * last_actuators.steer > 0): - delta_u = 0 - - output_steer = self.steer_filter.x + delta_u - - output_steer = clip(output_steer, -self.steer_max, self.steer_max) - - indi_log.active = True - indi_log.rateSetPoint = float(rate_sp) - indi_log.accelSetPoint = float(accel_sp) - indi_log.accelError = float(accel_error) - indi_log.delayedOutput = float(self.steer_filter.x) - indi_log.delta = float(delta_u) - indi_log.output = float(output_steer) - indi_log.saturated = self._check_saturation(self.steer_max - abs(output_steer) < 1e-3, CS, steer_limited) - - return float(output_steer), float(steers_des), indi_log diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py index 993774f719..b504b3d125 100755 --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -10,14 +10,13 @@ from selfdrive.car.toyota.values import CAR as TOYOTA from selfdrive.car.nissan.values import CAR as NISSAN from selfdrive.controls.lib.latcontrol_pid import LatControlPID from selfdrive.controls.lib.latcontrol_torque import LatControlTorque -from selfdrive.controls.lib.latcontrol_indi import LatControlINDI from selfdrive.controls.lib.latcontrol_angle import LatControlAngle from selfdrive.controls.lib.vehicle_model import VehicleModel class TestLatControl(unittest.TestCase): - @parameterized.expand([(HONDA.CIVIC, LatControlPID), (TOYOTA.RAV4, LatControlTorque), (TOYOTA.PRIUS, LatControlINDI), (NISSAN.LEAF, LatControlAngle)]) + @parameterized.expand([(HONDA.CIVIC, LatControlPID), (TOYOTA.RAV4, LatControlTorque), (NISSAN.LEAF, LatControlAngle)]) def test_saturation(self, car_name, controller): CarInterface, CarController, CarState = interfaces[car_name] CP = CarInterface.get_non_essential_params(car_name) From e0c95f7ad9a693e04824d193901cd1e2fdb17e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 1 Jun 2023 21:39:30 -0700 Subject: [PATCH 124/283] Toggles: Reorganize in descending importance for driving (#28364) Reorganize toggles in descending importance for driving --- selfdrive/ui/qt/offroad/settings.cc | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index b9fec9d62d..0c8132343c 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -35,12 +35,6 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), "../assets/offroad/icon_openpilot.png", }, - { - "ExperimentalMode", - tr("Experimental Mode"), - "", - "../assets/img_experimental_white.svg", - }, { "ExperimentalLongitudinalEnabled", tr("openpilot Longitudinal Control (Alpha)"), @@ -49,18 +43,24 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { .arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")), "../assets/offroad/icon_speed_limit.png", }, + { + "ExperimentalMode", + tr("Experimental Mode"), + "", + "../assets/img_experimental_white.svg", + }, + { + "DisengageOnAccelerator", + tr("Disengage on Accelerator Pedal"), + tr("When enabled, pressing the accelerator pedal will disengage openpilot."), + "../assets/offroad/icon_disengage_on_accelerator.svg", + }, { "IsLdwEnabled", tr("Enable Lane Departure Warnings"), tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), "../assets/offroad/icon_warning.png", }, - { - "IsMetric", - tr("Use Metric System"), - tr("Display speed in km/h instead of mph."), - "../assets/offroad/icon_metric.png", - }, { "RecordFront", tr("Record and Upload Driver Camera"), @@ -68,10 +68,10 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "../assets/offroad/icon_monitoring.png", }, { - "DisengageOnAccelerator", - tr("Disengage on Accelerator Pedal"), - tr("When enabled, pressing the accelerator pedal will disengage openpilot."), - "../assets/offroad/icon_disengage_on_accelerator.svg", + "IsMetric", + tr("Use Metric System"), + tr("Display speed in km/h instead of mph."), + "../assets/offroad/icon_metric.png", }, #ifdef ENABLE_MAPS { From ad1fec5c12bc00d736c228ea3a6d1de158285ae3 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 2 Jun 2023 01:08:19 -0500 Subject: [PATCH 125/283] VW MQB: Angled mounts for Transporter and Crafter (#28302) * VW MQB: Angled mounts for Transporter and Crafter * whitespace oops --------- Co-authored-by: Cameron Clough --- docs/CARS.md | 14 +++++++------- selfdrive/car/volkswagen/values.py | 6 +++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 89d282c021..353e7bc4f4 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -153,8 +153,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -230,11 +230,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -243,7 +243,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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 02c579b0c1..68df7ea2d4 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -7,7 +7,8 @@ from cereal import car from panda.python import uds from opendbc.can.can_define import CANDefine from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarParts, CarHarness, Column +from selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column, \ + Device from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -171,6 +172,9 @@ class VWCarInfo(CarInfo): def init_make(self, CP: car.CarParams): self.footnotes.insert(0, Footnote.VW_EXP_LONG) + if CP.carFingerprint in (CAR.CRAFTER_MK2, CAR.TRANSPORTER_T61): + self.car_parts = CarParts([Device.three_angled_mount, CarHarness.j533]) + CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.ARTEON_MK1: [ From e2545c5b2479ba95484a3c56c23bb4a9bfc96962 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 1 Jun 2023 23:21:50 -0700 Subject: [PATCH 126/283] VW MQB: Angled mounts for Transporter and Crafter (2) --- docs/CARS.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 353e7bc4f4..6c59442da9 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -153,8 +153,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -230,11 +230,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -243,7 +243,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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| From 23430dd35f545f70a472668c67beaf005165bbfe Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Jun 2023 13:02:04 -0700 Subject: [PATCH 127/283] fw_versions: add some typing (#28369) * typing * sort * brand addrs * don't type match_fw_to_car_fuzzy * or this unfortunately * no space * add back * and this --- selfdrive/car/fw_versions.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 1c0d5003ec..3c18c2e7bd 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 from collections import defaultdict -from typing import Any, Dict, List, Set +from typing import Any, DefaultDict, Dict, List, Optional, Set, Tuple from tqdm import tqdm +import capnp import panda.python.uds as uds from cereal import car @@ -27,7 +28,8 @@ def chunks(l, n=128): yield l[i:i + n] -def build_fw_dict(fw_versions, filter_brand=None): +def build_fw_dict(fw_versions: List[capnp.lib.capnp._DynamicStructBuilder], + filter_brand: Optional[str] = None) -> Dict[Tuple[int, Optional[int]], Set[bytes]]: fw_versions_dict = defaultdict(set) for fw in fw_versions: if (filter_brand is None or fw.brand == filter_brand) and not fw.logging: @@ -36,14 +38,14 @@ def build_fw_dict(fw_versions, filter_brand=None): return dict(fw_versions_dict) -def get_brand_addrs(): - brand_addrs = defaultdict(set) +def get_brand_addrs() -> Dict[str, Set[Tuple[int, Optional[int]]]]: + brand_addrs: DefaultDict[str, Set[Tuple[int, Optional[int]]]] = defaultdict(set) for brand, cars in VERSIONS.items(): # Add ecus in database + extra ecus to match against brand_addrs[brand] |= {(addr, sub_addr) for _, addr, sub_addr in FW_QUERY_CONFIGS[brand].extra_ecus} for fw in cars.values(): brand_addrs[brand] |= {(addr, sub_addr) for _, addr, sub_addr in fw.keys()} - return brand_addrs + return dict(brand_addrs) def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): @@ -214,7 +216,8 @@ def set_obd_multiplexing(params: Params, obd_multiplexing: bool): cloudlog.warning("OBD multiplexing set successfully") -def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False): +def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False) -> \ + List[capnp.lib.capnp._DynamicStructBuilder]: """Queries for FW versions ordering brands by likelihood, breaks when exact match is found""" all_car_fw = [] @@ -235,7 +238,8 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand return all_car_fw -def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False): +def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False) -> \ + List[capnp.lib.capnp._DynamicStructBuilder]: versions = VERSIONS.copy() params = Params() @@ -286,11 +290,11 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, set_obd_multiplexing(params, r.obd_multiplexing) try: - addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and - (len(r.whitelist_ecus) == 0 or ecu_types[(b, a, s)] in r.whitelist_ecus)] + query_addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and + (len(r.whitelist_ecus) == 0 or ecu_types[(b, a, s)] in r.whitelist_ecus)] - if addrs: - query = IsoTpParallelQuery(sendcan, logcan, r.bus, addrs, r.request, r.response, r.rx_offset, debug=debug) + if query_addrs: + query = IsoTpParallelQuery(sendcan, logcan, r.bus, query_addrs, r.request, r.response, r.rx_offset, debug=debug) for (tx_addr, sub_addr), version in query.get_data(timeout).items(): f = car.CarParams.CarFw.new_message() From 96905e52e2c18af03c0ffa43fa75d614df2a6c04 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Jun 2023 14:24:54 -0700 Subject: [PATCH 128/283] IsoTpParallelQuery: remove spammy log (#28372) * remove * just a warning * just comment out for now --- selfdrive/car/isotp_parallel_query.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index 5f8b0561a0..8ab9728e5f 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -148,8 +148,9 @@ class IsoTpParallelQuery: cloudlog.error(f"iso-tp query timeout after receiving partial response: {tx_addr}") elif tx_addr in addrs_responded: cloudlog.error(f"iso-tp query timeout while receiving response: {tx_addr}") - else: - cloudlog.error(f"iso-tp query timeout with no response: {tx_addr}") + # TODO: handle functional addresses + # else: + # cloudlog.error(f"iso-tp query timeout with no response: {tx_addr}") request_done[tx_addr] = True # Break if all requests are done (finished or timed out) From a446c1fa5665086d690a017f453cad3a4c38f00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 2 Jun 2023 14:38:28 -0700 Subject: [PATCH 129/283] Radard: just get relative speed from model (#27493) * refactor radard * Revert "refactor radard" This reverts commit 4b3507ff58e753334969b6ba2c2f6b1b35a200cc. * May work * No radar for test * check length * no accel for now * First accel * Cleaner way * Re-enable radar * update proc replay * This might cause oscillation * Update ref commit --- selfdrive/controls/lib/radar_helpers.py | 13 +++++++------ selfdrive/controls/radard.py | 12 ++++++++---- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/selfdrive/controls/lib/radar_helpers.py b/selfdrive/controls/lib/radar_helpers.py index 4bb0179267..4184340dc5 100644 --- a/selfdrive/controls/lib/radar_helpers.py +++ b/selfdrive/controls/lib/radar_helpers.py @@ -130,15 +130,16 @@ class Cluster(): "aLeadTau": float(self.aLeadTau) } - def get_RadarState_from_vision(self, lead_msg, v_ego): + def get_RadarState_from_vision(self, lead_msg, v_ego, model_v_ego): + lead_v_rel_pred = lead_msg.v[0] - model_v_ego return { "dRel": float(lead_msg.x[0] - RADAR_TO_CAMERA), "yRel": float(-lead_msg.y[0]), - "vRel": float(lead_msg.v[0] - v_ego), - "vLead": float(lead_msg.v[0]), - "vLeadK": float(lead_msg.v[0]), - "aLeadK": float(0), - "aLeadTau": _LEAD_ACCEL_TAU, + "vRel": float(lead_v_rel_pred), + "vLead": float(v_ego + lead_v_rel_pred), + "vLeadK": float(v_ego + lead_v_rel_pred), + "aLeadK": 0.0, + "aLeadTau": 0.3, "fcw": False, "modelProb": float(lead_msg.prob), "radar": False, diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 34f0f274fe..521cea816f 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -64,7 +64,7 @@ def match_vision_to_cluster(v_ego, lead, clusters): return None -def get_lead(v_ego, ready, clusters, lead_msg, low_speed_override=True): +def get_lead(v_ego, ready, clusters, lead_msg, model_v_ego, low_speed_override=True): # Determine leads, this is where the essential logic happens if len(clusters) > 0 and ready and lead_msg.prob > .5: cluster = match_vision_to_cluster(v_ego, lead_msg, clusters) @@ -75,7 +75,7 @@ def get_lead(v_ego, ready, clusters, lead_msg, low_speed_override=True): if cluster is not None: lead_dict = cluster.get_RadarState(lead_msg.prob) elif (cluster is None) and ready and (lead_msg.prob > .5): - lead_dict = Cluster().get_RadarState_from_vision(lead_msg, v_ego) + lead_dict = Cluster().get_RadarState_from_vision(lead_msg, v_ego, model_v_ego) if low_speed_override: low_speed_clusters = [c for c in clusters if c.potential_low_speed_lead(v_ego)] @@ -168,10 +168,14 @@ class RadarD(): radarState.radarErrors = list(rr.errors) radarState.carStateMonoTime = sm.logMonoTime['carState'] + if len(sm['modelV2'].temporalPose.trans): + model_v_ego = sm['modelV2'].temporalPose.trans[0] + else: + model_v_ego = self.v_ego leads_v3 = sm['modelV2'].leadsV3 if len(leads_v3) > 1: - radarState.leadOne = get_lead(self.v_ego, self.ready, clusters, leads_v3[0], low_speed_override=True) - radarState.leadTwo = get_lead(self.v_ego, self.ready, clusters, leads_v3[1], low_speed_override=False) + radarState.leadOne = get_lead(self.v_ego, self.ready, clusters, leads_v3[0], model_v_ego, low_speed_override=True) + radarState.leadTwo = get_lead(self.v_ego, self.ready, clusters, leads_v3[1], model_v_ego, low_speed_override=False) return dat diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 52735b686b..7fa8dd9530 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -29f846f525a4e14f380afd20ae8fa0804011ab6e \ No newline at end of file +73549898edd3d9a428fa6f58e25c2c0300290ef2 From 26ad9b32f35ff2f4723a871125379537071950eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Sat, 3 Jun 2023 00:17:25 +0200 Subject: [PATCH 130/283] replay: lock uiDebug and userFlag messages behind all flag (#28349) * Add ui-debug flag, for replaying ui debug states * Fix flag description * Replace --ui-debug with --all flag * Add base_blacklist for services blacklisted by default --- tools/cabana/streams/replaystream.cc | 2 +- tools/replay/main.cc | 5 ++++- tools/replay/replay.cc | 10 ++++++++-- tools/replay/replay.h | 3 ++- tools/replay/tests/test_replay.cc | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index b5ea44be0c..c7c79c8388 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -32,7 +32,7 @@ void ReplayStream::mergeSegments() { } bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { - replay.reset(new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this)); + replay.reset(new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, {}, nullptr, replay_flags, data_dir, this)); replay->setSegmentCacheLimit(settings.max_cached_minutes); replay->installEventFilter(event_filter, this); QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo); diff --git a/tools/replay/main.cc b/tools/replay/main.cc index 6b624aa1fa..78be2acd0b 100644 --- a/tools/replay/main.cc +++ b/tools/replay/main.cc @@ -8,6 +8,7 @@ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + const QStringList base_blacklist = {"uiDebug", "userFlag"}; const std::tuple flags[] = { {"dcam", REPLAY_FLAG_DCAM, "load driver camera"}, {"ecam", REPLAY_FLAG_ECAM, "load wide road camera"}, @@ -16,6 +17,8 @@ int main(int argc, char *argv[]) { {"qcam", REPLAY_FLAG_QCAMERA, "load qcamera"}, {"no-hw-decoder", REPLAY_FLAG_NO_HW_DECODER, "disable HW video decoding"}, {"no-vipc", REPLAY_FLAG_NO_VIPC, "do not output video"}, + {"all", REPLAY_FLAG_ALL_SERVICES, "do output all messages including " + base_blacklist.join(", ") + + ". this may causes issues when used along with UI"} }; QCommandLineParser parser; @@ -56,7 +59,7 @@ int main(int argc, char *argv[]) { op_prefix.reset(new OpenpilotPrefix(prefix.toStdString())); } - Replay *replay = new Replay(route, allow, block, nullptr, replay_flags, parser.value("data_dir"), &app); + Replay *replay = new Replay(route, allow, block, base_blacklist, nullptr, replay_flags, parser.value("data_dir"), &app); if (!parser.value("c").isEmpty()) { replay->setSegmentCacheLimit(parser.value("c").toInt()); } diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 95315fe71b..ad6ad4a43d 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -10,14 +10,20 @@ #include "system/hardware/hw.h" #include "tools/replay/util.h" -Replay::Replay(QString route, QStringList allow, QStringList block, SubMaster *sm_, uint32_t flags, QString data_dir, QObject *parent) +Replay::Replay(QString route, QStringList allow, QStringList block, QStringList base_blacklist, SubMaster *sm_, uint32_t flags, QString data_dir, QObject *parent) : sm(sm_), flags_(flags), QObject(parent) { std::vector s; auto event_struct = capnp::Schema::from().asStruct(); sockets_.resize(event_struct.getUnionFields().size()); for (const auto &it : services) { + uint16_t which = event_struct.getFieldByName(it.name).getProto().getDiscriminantValue(); + if ((which == cereal::Event::Which::UI_DEBUG || which == cereal::Event::Which::USER_FLAG) && + !(flags & REPLAY_FLAG_ALL_SERVICES) && + !allow.contains(it.name)) { + continue; + } + if ((allow.empty() || allow.contains(it.name)) && !block.contains(it.name)) { - uint16_t which = event_struct.getFieldByName(it.name).getProto().getDiscriminantValue(); sockets_[which] = it.name; if (!allow.empty() || !block.empty()) { allow_list.insert((cereal::Event::Which)which); diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 2bb426361b..bf66b8d8b9 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -22,6 +22,7 @@ enum REPLAY_FLAGS { REPLAY_FLAG_NO_HW_DECODER = 0x0100, REPLAY_FLAG_FULL_SPEED = 0x0200, REPLAY_FLAG_NO_VIPC = 0x0400, + REPLAY_FLAG_ALL_SERVICES = 0x0800, }; enum class FindFlag { @@ -40,7 +41,7 @@ class Replay : public QObject { Q_OBJECT public: - Replay(QString route, QStringList allow, QStringList block, SubMaster *sm = nullptr, + Replay(QString route, QStringList allow, QStringList block, QStringList base_blacklist, SubMaster *sm = nullptr, uint32_t flags = REPLAY_FLAG_NONE, QString data_dir = "", QObject *parent = 0); ~Replay(); bool load(); diff --git a/tools/replay/tests/test_replay.cc b/tools/replay/tests/test_replay.cc index 30e3c811ee..f0b80269dc 100644 --- a/tools/replay/tests/test_replay.cc +++ b/tools/replay/tests/test_replay.cc @@ -154,7 +154,7 @@ TEST_CASE("Route") { // helper class for unit tests class TestReplay : public Replay { public: - TestReplay(const QString &route, uint8_t flags = REPLAY_FLAG_NO_FILE_CACHE) : Replay(route, {}, {}, nullptr, flags) {} + TestReplay(const QString &route, uint8_t flags = REPLAY_FLAG_NO_FILE_CACHE) : Replay(route, {}, {}, {}, nullptr, flags) {} void test_seek(); void testSeekTo(int seek_to); }; From 1a0f482d4d3fee441d5473882bf1356a7d02a3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Sat, 3 Jun 2023 00:39:23 +0200 Subject: [PATCH 131/283] regen: fix params (#28375) Fix environment setup for regen --- selfdrive/test/process_replay/process_replay.py | 8 ++++++-- selfdrive/test/process_replay/regen.py | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 8f2f3e1bd6..d6d5b25bde 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -2,6 +2,7 @@ import os import time import signal +import platform from collections import OrderedDict from dataclasses import dataclass, field from typing import Dict, List, Optional, Callable @@ -417,8 +418,11 @@ def replay_process(cfg, lr, fingerprint=None): return log_msgs -def setup_env(CP=None, cfg=None, controlsState=None, lr=None, fingerprint=None): - os.environ["PARAMS_ROOT"] = "/dev/shm/params" +def setup_env(CP=None, cfg=None, controlsState=None, lr=None, fingerprint=None, log_dir=None): + if platform.system() != "Darwin": + os.environ["PARAMS_ROOT"] = "/dev/shm/params" + if log_dir is not None: + os.environ["LOG_ROOT"] = log_dir params = Params() params.clear_all() diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index fbabc1bd29..63eb37d29d 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -243,15 +243,14 @@ def regen_segment(lr, frs=None, daemons="all", outdir=FAKEDATA, disable_tqdm=Fal if frs is None: frs = dict() - params = Params() - os.environ["LOG_ROOT"] = outdir - # Get and setup initial state CP = [m for m in lr if m.which() == 'carParams'][0].carParams controlsState = [m for m in lr if m.which() == 'controlsState'][0].controlsState liveCalibration = [m for m in lr if m.which() == 'liveCalibration'][0] - setup_env(CP=CP, controlsState=controlsState) + setup_env(CP=CP, controlsState=controlsState, log_dir=outdir) + + params = Params() params.put("CalibrationParams", liveCalibration.as_builder().to_bytes()) vs, cam_procs = replay_cameras(lr, frs, disable_tqdm=disable_tqdm) From d9ebea4bddf5508fea3a66bfe6ea468723e51a96 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Jun 2023 16:01:27 -0700 Subject: [PATCH 132/283] Hyundai: remove some old FW (#28376) * Update values.py * Update values.py --- selfdrive/car/hyundai/values.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 20b7bacaff..b6e97a38a8 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -542,14 +542,11 @@ FW_VERSIONS = { }, CAR.SONATA: { (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\x00DN8 1.00 99110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa ', - b'\xf1\x00DN8 1.00 99110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 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 FHCUP 1.00 1.00 99110-L0000 ', b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ', - b'\xf1\x00DN89110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa ', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100', From 87364b6a812a5781d7e9385078dd2d6f7109c9d4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 2 Jun 2023 16:40:03 -0700 Subject: [PATCH 133/283] Revert "boardd: smaller spi chunk size (#28360)" This reverts commit 702e4120e6b5a02f1d25089c198f1a0e9a813ac1. --- selfdrive/boardd/spi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 924f416ead..e10fd744d5 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -163,7 +163,7 @@ int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int l } int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len, unsigned int timeout) { - const int xfer_size = 0x40 * 5; + const int xfer_size = 0x40 * 15; int ret = 0; uint16_t length = (tx_data != NULL) ? tx_len : rx_len; From deb4b11d110cd0b437c5752d79f3bf0c48c90fe4 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 2 Jun 2023 18:41:48 -0500 Subject: [PATCH 134/283] Honda: Add FW for 2023 Honda Passport (#28343) * Honda: Add FW for 2023 Honda Pilot/Passport * push update --- docs/CARS.md | 2 +- selfdrive/car/honda/values.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 6c59442da9..6da46e79fd 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -66,7 +66,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Passport 2019-22|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 7c1c5f0920..ba7a42d2a1 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -146,7 +146,7 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), CAR.PILOT: [ HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS), - HondaCarInfo("Honda Passport 2019-22", "All", min_steer_speed=12. * CV.MPH_TO_MS), + HondaCarInfo("Honda Passport 2019-23", "All", min_steer_speed=12. * CV.MPH_TO_MS), ], CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-23", min_steer_speed=12. * CV.MPH_TO_MS), CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), @@ -1130,6 +1130,7 @@ FW_VERSIONS = { b'37805-RLV-B210\x00\x00', b'37805-RLV-L160\x00\x00', b'37805-RLV-B420\x00\x00', + b'37805-RLV-F120\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TG7-A030\x00\x00', From 7925232a349388f3435940c90989f957746d918a Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Fri, 2 Jun 2023 20:55:13 -0700 Subject: [PATCH 135/283] hot coffee model (#28296) * 1061b1c7-b944-43e3-a940-b56b64d66f54/700 * bump cereal * bump cereal * make mypy happy * write TODO * read height from written params * fix certain_if_calib logic and unit tests * factor moving_avg_with_linear_decay * remove whitespace * update model ref commit * default value for CI * update process replay ref commit * update process replay ref commit * update process replay ref commit * bump cereal --- cereal | 2 +- selfdrive/locationd/calibrationd.py | 51 +++++++++++++++---- selfdrive/locationd/test/test_calibrationd.py | 50 +++++++++++++++--- selfdrive/modeld/models/driving.cc | 5 +- selfdrive/modeld/models/driving.h | 9 ++++ selfdrive/modeld/models/supercombo.onnx | 4 +- .../process_replay/model_replay_ref_commit | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 8 files changed, 102 insertions(+), 23 deletions(-) diff --git a/cereal b/cereal index 7e1d67d415..8af4582508 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7e1d67d4155651c6288e4b65fb7788871742e752 +Subproject commit 8af4582508dd7acef082c40ede11eb7018415d9a diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 42fa3b7c94..c9d9340a2d 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -24,6 +24,8 @@ MIN_SPEED_FILTER = 15 * CV.MPH_TO_MS MAX_VEL_ANGLE_STD = np.radians(0.25) MAX_YAW_RATE_FILTER = np.radians(2) # per second +MAX_HEIGHT_STD = np.exp(-3.5) + # This is at model frequency, blocks needed for efficiency SMOOTH_CYCLES = 10 BLOCK_SIZE = 100 @@ -32,6 +34,7 @@ INPUTS_WANTED = 50 # We want a little bit more than we need for stability MAX_ALLOWED_SPREAD = np.radians(2) RPY_INIT = np.array([0.0,0.0,0.0]) WIDE_FROM_DEVICE_EULER_INIT = np.array([0.0, 0.0, 0.0]) +HEIGHT_INIT = np.array([1.22]) # These values are needed to accommodate the model frame in the narrow cam of the C3 PITCH_LIMITS = np.array([-0.09074112085129739, 0.17]) @@ -50,6 +53,8 @@ def sanity_clip(rpy: np.ndarray) -> np.ndarray: np.clip(rpy[1], PITCH_LIMITS[0] - .005, PITCH_LIMITS[1] + .005), np.clip(rpy[2], YAW_LIMITS[0] - .005, YAW_LIMITS[1] + .005)]) +def moving_avg_with_linear_decay(prev_mean: np.ndarray, new_val: np.ndarray, idx: int, block_size: float) -> np.ndarray: + return (idx*prev_mean + (block_size - idx) * new_val) / block_size class Calibrator: def __init__(self, param_put: bool = False): @@ -62,6 +67,7 @@ class Calibrator: calibration_params = params.get("CalibrationParams") rpy_init = RPY_INIT wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT + height = HEIGHT_INIT valid_blocks = 0 self.cal_status = log.LiveCalibrationData.Status.uncalibrated @@ -71,21 +77,28 @@ class Calibrator: rpy_init = np.array(msg.liveCalibration.rpyCalib) valid_blocks = msg.liveCalibration.validBlocks wide_from_device_euler = np.array(msg.liveCalibration.wideFromDeviceEuler) + height = np.array(msg.liveCalibration.height) except Exception: cloudlog.exception("Error reading cached CalibrationParams") - self.reset(rpy_init, valid_blocks, wide_from_device_euler) + self.reset(rpy_init, valid_blocks, wide_from_device_euler, height) self.update_status() def reset(self, rpy_init: np.ndarray = RPY_INIT, valid_blocks: int = 0, wide_from_device_euler_init: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT, + height_init: np.ndarray = HEIGHT_INIT, smooth_from: Optional[np.ndarray] = None) -> None: if not np.isfinite(rpy_init).all(): self.rpy = RPY_INIT.copy() else: self.rpy = rpy_init.copy() + if not np.isfinite(height_init).all() or len(height_init) != 1: + self.height = HEIGHT_INIT.copy() + else: + self.height = height_init.copy() + if not np.isfinite(wide_from_device_euler_init).all() or len(wide_from_device_euler_init) != 3: self.wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT.copy() else: @@ -98,6 +111,7 @@ class Calibrator: self.rpys = np.tile(self.rpy, (INPUTS_WANTED, 1)) self.wide_from_device_eulers = np.tile(self.wide_from_device_euler, (INPUTS_WANTED, 1)) + self.heights = np.tile(self.height, (INPUTS_WANTED, 1)) self.idx = 0 self.block_idx = 0 @@ -120,6 +134,7 @@ class Calibrator: valid_idxs = self.get_valid_idxs() if valid_idxs: self.wide_from_device_euler = np.mean(self.wide_from_device_eulers[valid_idxs], axis=0) + self.height = np.mean(self.heights[valid_idxs], axis=0) rpys = self.rpys[valid_idxs] self.rpy = np.mean(rpys, axis=0) max_rpy_calib = np.array(np.max(rpys, axis=0)) @@ -140,6 +155,7 @@ class Calibrator: # If spread is too high, assume mounting was changed and reset to last block. # Make the transition smooth. Abrupt transitions are not good for feedback loop through supercombo model. + # TODO: add height spread check with smooth transition too if max(self.calib_spread) > MAX_ALLOWED_SPREAD and self.cal_status == log.LiveCalibrationData.Status.calibrated: self.reset(self.rpys[self.block_idx - 1], valid_blocks=1, smooth_from=self.rpy) self.cal_status = log.LiveCalibrationData.Status.recalibrating @@ -160,13 +176,21 @@ class Calibrator: def handle_cam_odom(self, trans: List[float], rot: List[float], wide_from_device_euler: List[float], - trans_std: List[float]) -> Optional[np.ndarray]: + trans_std: List[float], + road_transform_trans: List[float], + road_transform_trans_std: List[float]) -> Optional[np.ndarray]: self.old_rpy_weight = max(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) angle_std_threshold = MAX_VEL_ANGLE_STD - certain_if_calib = ((np.arctan2(trans_std[1], trans[0]) < angle_std_threshold) or - (self.valid_blocks < INPUTS_NEEDED)) + height_std_threshold = MAX_HEIGHT_STD + rpy_certain = np.arctan2(trans_std[1], trans[0]) < angle_std_threshold + if len(road_transform_trans_std) == 3: + height_certain = road_transform_trans_std[2] < height_std_threshold + else: + height_certain = True + + certain_if_calib = (rpy_certain and height_certain) or (self.valid_blocks < INPUTS_NEEDED) if not (straight_and_fast and certain_if_calib): return None @@ -180,10 +204,16 @@ class Calibrator: new_wide_from_device_euler = np.array(wide_from_device_euler) else: new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT - self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + - (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) - self.wide_from_device_eulers[self.block_idx] = (self.idx*self.wide_from_device_eulers[self.block_idx] + - (BLOCK_SIZE - self.idx) * new_wide_from_device_euler) / float(BLOCK_SIZE) + + if (len(road_transform_trans) == 3): + new_height = np.array([road_transform_trans[2]]) + else: + new_height = HEIGHT_INIT + + self.rpys[self.block_idx] = moving_avg_with_linear_decay(self.rpys[self.block_idx], new_rpy, self.idx, float(BLOCK_SIZE)) + self.wide_from_device_eulers[self.block_idx] = moving_avg_with_linear_decay(self.wide_from_device_eulers[self.block_idx], new_wide_from_device_euler, self.idx, float(BLOCK_SIZE)) + self.heights[self.block_idx] = moving_avg_with_linear_decay(self.heights[self.block_idx], new_height, self.idx, float(BLOCK_SIZE)) + self.idx = (self.idx + 1) % BLOCK_SIZE if self.idx == 0: self.block_idx += 1 @@ -206,6 +236,7 @@ class Calibrator: liveCalibration.rpyCalib = smooth_rpy.tolist() liveCalibration.rpyCalibSpread = self.calib_spread.tolist() liveCalibration.wideFromDeviceEuler = self.wide_from_device_euler.tolist() + liveCalibration.height = self.height.tolist() if self.not_car: liveCalibration.validBlocks = INPUTS_NEEDED @@ -243,7 +274,9 @@ def calibrationd_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[m new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans, sm['cameraOdometry'].rot, sm['cameraOdometry'].wideFromDeviceEuler, - sm['cameraOdometry'].transStd) + sm['cameraOdometry'].transStd, + sm['cameraOdometry'].roadTransformTrans, + sm['cameraOdometry'].roadTransformTransStd) if DEBUG and new_rpy is not None: print('got new rpy', new_rpy) diff --git a/selfdrive/locationd/test/test_calibrationd.py b/selfdrive/locationd/test/test_calibrationd.py index 18125cc43f..96f996413d 100755 --- a/selfdrive/locationd/test/test_calibrationd.py +++ b/selfdrive/locationd/test/test_calibrationd.py @@ -7,7 +7,7 @@ import numpy as np import cereal.messaging as messaging from cereal import log from common.params import Params -from selfdrive.locationd.calibrationd import Calibrator, INPUTS_NEEDED, INPUTS_WANTED, BLOCK_SIZE, MIN_SPEED_FILTER, MAX_YAW_RATE_FILTER, SMOOTH_CYCLES +from selfdrive.locationd.calibrationd import Calibrator, INPUTS_NEEDED, INPUTS_WANTED, BLOCK_SIZE, MIN_SPEED_FILTER, MAX_YAW_RATE_FILTER, SMOOTH_CYCLES, HEIGHT_INIT class TestCalibrationd(unittest.TestCase): @@ -16,10 +16,12 @@ class TestCalibrationd(unittest.TestCase): msg = messaging.new_message('liveCalibration') msg.liveCalibration.validBlocks = random.randint(1, 10) msg.liveCalibration.rpyCalib = [random.random() for _ in range(3)] + msg.liveCalibration.height = [random.random() for _ in range(1)] Params().put("CalibrationParams", msg.to_bytes()) c = Calibrator(param_put=True) np.testing.assert_allclose(msg.liveCalibration.rpyCalib, c.rpy) + np.testing.assert_allclose(msg.liveCalibration.height, c.height) self.assertEqual(msg.liveCalibration.validBlocks, c.valid_blocks) @@ -27,51 +29,79 @@ class TestCalibrationd(unittest.TestCase): c = Calibrator(param_put=False) for _ in range(BLOCK_SIZE * INPUTS_WANTED): c.handle_v_ego(MIN_SPEED_FILTER + 1) - c. handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], + c.handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e-3, 1e-3, 1e-3]) self.assertEqual(c.valid_blocks, INPUTS_WANTED) np.testing.assert_allclose(c.rpy, np.zeros(3)) + np.testing.assert_allclose(c.height, HEIGHT_INIT) c.reset() + def test_calibration_low_speed_reject(self): c = Calibrator(param_put=False) for _ in range(BLOCK_SIZE * INPUTS_WANTED): c.handle_v_ego(MIN_SPEED_FILTER - 1) - c. handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], + c.handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e-3, 1e-3, 1e-3]) for _ in range(BLOCK_SIZE * INPUTS_WANTED): c.handle_v_ego(MIN_SPEED_FILTER + 1) - c. handle_cam_odom([MIN_SPEED_FILTER - 1, 0.0, 0.0], + c.handle_cam_odom([MIN_SPEED_FILTER - 1, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e-3, 1e-3, 1e-3]) self.assertEqual(c.valid_blocks, 0) np.testing.assert_allclose(c.rpy, np.zeros(3)) + np.testing.assert_allclose(c.height, HEIGHT_INIT) def test_calibration_yaw_rate_reject(self): c = Calibrator(param_put=False) for _ in range(BLOCK_SIZE * INPUTS_WANTED): c.handle_v_ego(MIN_SPEED_FILTER + 1) - c. handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], + c.handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], [0.0, 0.0, MAX_YAW_RATE_FILTER ], [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e-3, 1e-3, 1e-3]) self.assertEqual(c.valid_blocks, 0) np.testing.assert_allclose(c.rpy, np.zeros(3)) + np.testing.assert_allclose(c.height, HEIGHT_INIT) + - def test_calibration_speed_std_reject(self): c = Calibrator(param_put=False) for _ in range(BLOCK_SIZE * INPUTS_WANTED): c.handle_v_ego(MIN_SPEED_FILTER + 1) - c. handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], + c.handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], + [1e3, 1e3, 1e3], + [0.0, 0.0, HEIGHT_INIT.item()], + [1e-3, 1e-3, 1e-3]) + self.assertEqual(c.valid_blocks, INPUTS_NEEDED) + np.testing.assert_allclose(c.rpy, np.zeros(3)) + + + def test_calibration_speed_std_height_reject(self): + c = Calibrator(param_put=False) + for _ in range(BLOCK_SIZE * INPUTS_WANTED): + c.handle_v_ego(MIN_SPEED_FILTER + 1) + c.handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e3, 1e3, 1e3]) self.assertEqual(c.valid_blocks, INPUTS_NEEDED) np.testing.assert_allclose(c.rpy, np.zeros(3)) @@ -81,9 +111,11 @@ class TestCalibrationd(unittest.TestCase): c = Calibrator(param_put=False) for _ in range(BLOCK_SIZE * INPUTS_WANTED): c.handle_v_ego(MIN_SPEED_FILTER + 1) - c. handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], + c.handle_cam_odom([MIN_SPEED_FILTER + 1, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e-3, 1e-3, 1e-3]) self.assertEqual(c.valid_blocks, INPUTS_WANTED) np.testing.assert_allclose(c.rpy, [0.0, 0.0, 0.0]) @@ -95,6 +127,8 @@ class TestCalibrationd(unittest.TestCase): c.handle_cam_odom([MIN_SPEED_FILTER + 1, -0.05 * MIN_SPEED_FILTER, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], + [1e-3, 1e-3, 1e-3], + [0.0, 0.0, HEIGHT_INIT.item()], [1e-3, 1e-3, 1e-3]) self.assertEqual(c.valid_blocks, 1) self.assertEqual(c.cal_status, log.LiveCalibrationData.Status.recalibrating) diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 5538d6ff9b..6b0e626c5c 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -390,15 +390,18 @@ void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_droppe const auto &v_std = net_outputs.pose.velocity_std; const auto &r_std = net_outputs.pose.rotation_std; const auto &t_std = net_outputs.wide_from_device_euler.std; + const auto &road_transform_trans_mean = net_outputs.road_transform.position_mean; + const auto &road_transform_trans_std = net_outputs.road_transform.position_std; auto posenetd = msg.initEvent(valid && (vipc_dropped_frames < 1)).initCameraOdometry(); posenetd.setTrans({v_mean.x, v_mean.y, v_mean.z}); posenetd.setRot({r_mean.x, r_mean.y, r_mean.z}); posenetd.setWideFromDeviceEuler({t_mean.x, t_mean.y, t_mean.z}); + posenetd.setRoadTransformTrans({road_transform_trans_mean.x, road_transform_trans_mean.y, road_transform_trans_mean.z}); posenetd.setTransStd({exp(v_std.x), exp(v_std.y), exp(v_std.z)}); posenetd.setRotStd({exp(r_std.x), exp(r_std.y), exp(r_std.z)}); posenetd.setWideFromDeviceEulerStd({exp(t_std.x), exp(t_std.y), exp(t_std.z)}); - + posenetd.setRoadTransformTransStd({exp(road_transform_trans_std.x), exp(road_transform_trans_std.y), exp(road_transform_trans_std.z)}); posenetd.setTimestampEof(timestamp_eof); posenetd.setFrameId(vipc_frame_id); diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index 2b0902d5cf..1214c30062 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -178,6 +178,14 @@ struct ModelOutputTemporalPose { }; static_assert(sizeof(ModelOutputTemporalPose) == sizeof(ModelOutputXYZ)*4); +struct ModelOutputRoadTransform { + ModelOutputXYZ position_mean; + ModelOutputXYZ rotation_mean; + ModelOutputXYZ position_std; + ModelOutputXYZ rotation_std; +}; +static_assert(sizeof(ModelOutputRoadTransform) == sizeof(ModelOutputXYZ)*4); + struct ModelOutputDisengageProb { float gas_disengage; float brake_disengage; @@ -237,6 +245,7 @@ struct ModelOutput { const ModelOutputPose pose; const ModelOutputWideFromDeviceEuler wide_from_device_euler; const ModelOutputTemporalPose temporal_pose; + const ModelOutputRoadTransform road_transform; }; constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float); diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 493f3285d6..53c1224ae8 100644 --- a/selfdrive/modeld/models/supercombo.onnx +++ b/selfdrive/modeld/models/supercombo.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8bf95f096b19cef1e473fb4f0caf5f727b74bbde23a642aa586036ad9824e55 -size 46076782 +oid sha256:4aa77af40335462062c6eb06632bb84cbc8e5c9e3ad759f66862711620e2a840 +size 46117948 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index e458f817d3..b89468eebb 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -91bdaeae5a7141ff6bb6fd80672521c8d63f644c +69270554b3c3ae574b9f357f2473395edf7db8af diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 7fa8dd9530..c794a0434a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -73549898edd3d9a428fa6f58e25c2c0300290ef2 +dfe1e4a5fd7a464c91c0d2e70592b4b1470fda8d \ No newline at end of file From 80d8dcd22eefb39e44e32127ce3479a50f063e1a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 2 Jun 2023 21:18:51 -0700 Subject: [PATCH 136/283] test_onroad: tizi updates (#28379) * test_onroad: add tizi support * don't clear params on desk device * update * fix mypy --------- Co-authored-by: Comma Device --- selfdrive/test/test_onroad.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 793530b964..8e51e5ec18 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -18,6 +18,7 @@ from common.basedir import BASEDIR from common.timeout import Timeout from common.params import Params from selfdrive.controls.lib.events import EVENTS, ET +from system.hardware import HARDWARE from system.loggerd.config import ROOT from selfdrive.test.helpers import set_params_enabled, release_only from tools.lib.logreader import LogReader @@ -35,7 +36,6 @@ PROCS = { "./_sensord": 12.0, "selfdrive.controls.radard": 4.5, "./_modeld": 4.48, - "./boardd": 3.63, "./_dmonitoringmodeld": 5.0, "selfdrive.thermald.thermald": 3.87, "selfdrive.locationd.calibrationd": 2.0, @@ -45,12 +45,10 @@ PROCS = { "./proclogd": 1.54, "system.logmessaged": 0.2, "./clocksd": 0.02, - "./ubloxd": 0.02, "selfdrive.tombstoned": 0, "./logcatd": 0, "system.micd": 10.0, "system.timezoned": 0, - "system.sensord.pigeond": 6.0, "selfdrive.boardd.pandad": 0, "selfdrive.statsd": 0.4, "selfdrive.navd.navd": 0.4, @@ -59,6 +57,18 @@ PROCS = { "selfdrive.locationd.laikad": None, # TODO: laikad cpu usage is sporadic } +PROCS.update({ + "tici": { + "./boardd": 4.0, + "./ubloxd": 0.02, + "system.sensord.pigeond": 6.0, + }, + "tizi": { + "./boardd": 19.0, + "system.sensord.rawgps.rawgpsd": 1.0, + } +}[HARDWARE.get_device_type()]) + TIMINGS = { # rtols: max/min, rsd "can": [2.5, 0.35], @@ -96,7 +106,9 @@ class TestOnroad(unittest.TestCase): # setup env params = Params() - params.clear_all() + if "CI" in os.environ: + params.clear_all() + params.remove("CurrentRoute") set_params_enabled() os.environ['TESTING_CLOSET'] = '1' if os.path.exists(ROOT): @@ -156,11 +168,11 @@ class TestOnroad(unittest.TestCase): for s, msgs in self.service_msgs.items(): if s in ('initData', 'sentinel'): continue - + # skip gps services for now - if s in ('ubloxGnss', 'ubloxRaw', 'gnssMeasurements', 'gpsLocationExternal'): + if s in ('ubloxGnss', 'ubloxRaw', 'gnssMeasurements', 'gpsLocation', 'gpsLocationExternal', 'qcomGnss'): continue - + with self.subTest(service=s): assert len(msgs) >= math.floor(service_list[s].frequency*55) From a2e11b2f48c9c77b453f418ebcde3c1454e5bce2 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Fri, 2 Jun 2023 21:23:32 -0700 Subject: [PATCH 137/283] ci: test sof diffs in onroad test (#27723) * add diff test * skip --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/test/test_onroad.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 8e51e5ec18..12a3ef48ac 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -270,6 +270,23 @@ class TestOnroad(unittest.TestCase): result += "------------------------------------------------\n" print(result) + @unittest.skip("TODO: enable once timings are fixed") + def test_camera_frame_timings(self): + result = "\n" + result += "------------------------------------------------\n" + result += "----------------- SoF Timing ------------------\n" + result += "------------------------------------------------\n" + for name in ['roadCameraState', 'wideRoadCameraState', 'driverCameraState']: + ts = [getattr(getattr(m, m.which()), "timestampSof") for m in self.lr if name in m.which()] + d_ms = np.diff(ts) / 1e6 + d50 = np.abs(d_ms-50) + self.assertLess(max(d50), 1.0, f"high sof delta vs 50ms: {max(d50)}") + result += f"{name} sof delta vs 50ms: min {min(d50):.5f}s\n" + result += f"{name} sof delta vs 50ms: max {max(d50):.5f}s\n" + result += f"{name} sof delta vs 50ms: mean {d50.mean():.5f}s\n" + result += "------------------------------------------------\n" + print(result) + def test_mpc_execution_timings(self): result = "\n" result += "------------------------------------------------\n" From 4e738e64e4394e9d25373917a2fb7a6c0a9041f8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Jun 2023 13:34:37 +0800 Subject: [PATCH 138/283] cabana: add a test case for dbc parsing (#28383) test case for dbc parsing --- tools/cabana/dbc/dbcfile.cc | 2 +- tools/cabana/tests/test_cabana.cc | 41 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index d9938b0fbc..2a8d3d2d54 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -212,7 +212,7 @@ void DBCFile::parseExtraInfo(const QString &content) { uint32_t address = 0; while (!stream.atEnd()) { ++line_num; - line = stream.readLine(); + line = stream.readLine().trimmed(); if (line.startsWith("BO_ ")) { auto match = bo_regexp.match(line); dbc_assert(match.hasMatch()); diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index a3921d727b..abbb3dbf13 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -69,3 +69,44 @@ TEST_CASE("Parse can messages") { } } } + +TEST_CASE("Parse dbc") { + QString content = R"( +BO_ 160 message_1: 8 XXX + SG_ signal_1 : 0|12@1+ (1,0) [0|4095] "unit" XXX + SG_ signal_2 : 12|1@1+ (1.0,0.0) [0.0|1] "" XXX + +VAL_ 160 signal_1 0 "disabled" 1.2 "initializing" 2 "fault"; + +CM_ BO_ 160 "message comment"; +CM_ SG_ 160 signal_1 "signal comment"; +CM_ SG_ 160 signal_2 "multiple line comment +1 +2 +";)"; + + DBCFile file("", content); + auto msg = file.msg(160); + REQUIRE(msg != nullptr); + REQUIRE(msg->name == "message_1"); + REQUIRE(msg->size == 8); + REQUIRE(msg->comment == "message comment"); + REQUIRE(msg->sigs.size() == 2); + REQUIRE(file.msg("message_1") != nullptr); + + auto &sig_1 = msg->sigs[0]; + REQUIRE(sig_1.name == "signal_1"); + REQUIRE(sig_1.start_bit == 0); + REQUIRE(sig_1.size == 12); + REQUIRE(sig_1.min == 0); + REQUIRE(sig_1.max == 4095); + REQUIRE(sig_1.unit == "unit"); + REQUIRE(sig_1.comment == "signal comment"); + REQUIRE(sig_1.val_desc.size() == 3); + REQUIRE(sig_1.val_desc[0] == std::pair{0, "disabled"}); + REQUIRE(sig_1.val_desc[1] == std::pair{1.2, "initializing"}); + REQUIRE(sig_1.val_desc[2] == std::pair{2, "fault"}); + + auto &sig_2 = msg->sigs[1]; + REQUIRE(sig_2.comment == "multiple line comment\n1\n2"); +} From 04556652dc15460aa51cd3315982106a66526efb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 2 Jun 2023 22:35:05 -0700 Subject: [PATCH 139/283] rawgpsd: fix loading assistance data (#28381) * rawgpsd: fix loading assistance data * needs a specific name * cleanup * more logging --------- Co-authored-by: Comma Device --- system/sensord/rawgps/rawgpsd.py | 70 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/system/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py index 539a6308a7..a5eafb268d 100755 --- a/system/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -110,36 +110,52 @@ def gps_enabled() -> bool: raise Exception("failed to execute QGPS mmcli command") from exc def download_and_inject_assistance(): - assist_data_file = '/tmp/xtra3grc.bin' + assist_data_file = '/tmp/xtra3grc.bin' assistance_url = 'http://xtrapath3.izatcloud.net/xtra3grc.bin' - try: - c = pycurl.Curl() - c.setopt(c.URL, assistance_url) - c.setopt(c.NOBODY, 1) - c.setopt(pycurl.CONNECTTIMEOUT, 2) - c.perform() - c.close() - bytes_n = c.getinfo(c.CONTENT_LENGTH_DOWNLOAD) - if bytes_n > 1e5: - cloudlog.exception("Qcom assistance data larger than expected") - return - with open(assist_data_file, "wb") as fp: - c = pycurl.Curl() - c.setopt(pycurl.URL, assistance_url) - c.setopt(pycurl.CONNECTTIMEOUT, 5) - c.setopt(pycurl.WRITEDATA, fp) - c.perform() - c.close() - except pycurl.error as e: - cloudlog.exception(f'Failed to download assistance file with error: {e}') - if os.path.isfile(assist_data_file): + try: + # download assistance try: - subprocess.check_call(f"mmcli -m any --timeout 30 --location-inject-assistance-data={assist_data_file}", shell=True) - except subprocess.CalledProcessError: - cloudlog.exception("rawgps.mmcli_command_failed") - if os.path.isfile(assist_data_file): - os.remove(assist_data_file) + c = pycurl.Curl() + c.setopt(c.URL, assistance_url) + c.setopt(c.NOBODY, 1) + c.setopt(pycurl.CONNECTTIMEOUT, 2) + c.perform() + bytes_n = c.getinfo(c.CONTENT_LENGTH_DOWNLOAD) + c.close() + if bytes_n > 1e5: + cloudlog.error("Qcom assistance data larger than expected") + return + + with open(assist_data_file, 'wb') as fp: + c = pycurl.Curl() + c.setopt(pycurl.URL, assistance_url) + c.setopt(pycurl.CONNECTTIMEOUT, 5) + + c.setopt(pycurl.WRITEDATA, fp) + c.perform() + c.close() + except pycurl.error: + cloudlog.exception("Failed to download assistance file") + return + + # inject into module + try: + cmd = f"mmcli -m any --timeout 30 --location-inject-assistance-data={assist_data_file}" + subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=True) + cloudlog.info("successfully loaded assistance data") + except subprocess.CalledProcessError as e: + cloudlog.event( + "rawgps.assistance_loading_failed", + error=True, + cmd=e.cmd, + output=e.output, + returncode=e.returncode + ) + finally: + if os.path.exists(assist_data_file): + os.remove(assist_data_file) + def setup_quectel(diag: ModemDiag): # enable OEMDRE in the NV From 4f815db141db8b0257158d6969e78dea1b727912 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 2 Jun 2023 23:24:38 -0700 Subject: [PATCH 140/283] UI: connect to wifi prompt (#28273) * OffroadHome: move experimental mode button to right column * OffroadHome: replace DriveStats with PrimeAd when no prime * SetupWidget: remove PrimeAd * SetupWidget: tweaks to fit smaller space * UI: add WiFiPromptWidget * WiFiPrompt: update using network type * add WiFiPromptWidget to offroad home * reduce spacing to fit vertical space * WiFiPromptWidget: open Wi-Fi settings * no longer necessary * cleanup * shrink PrimeUser widget and increase Setup Wi-Fi font size * correctly resize widget when stack index changes * layout tweaks * debug * spacing * slightly improved style * helps -> help * . --- .../assets/offroad/icon_wifi_uploading.svg | 6 + selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/home.cc | 38 +++++-- selfdrive/ui/qt/widgets/prime.cc | 49 ++++----- selfdrive/ui/qt/widgets/prime.h | 4 +- selfdrive/ui/qt/widgets/wifi.cc | 103 ++++++++++++++++++ selfdrive/ui/qt/widgets/wifi.h | 23 ++++ selfdrive/ui/translations/main_de.ts | 27 ++++- selfdrive/ui/translations/main_ja.ts | 27 ++++- selfdrive/ui/translations/main_ko.ts | 27 ++++- selfdrive/ui/translations/main_pt-BR.ts | 27 ++++- selfdrive/ui/translations/main_zh-CHS.ts | 27 ++++- selfdrive/ui/translations/main_zh-CHT.ts | 27 ++++- 13 files changed, 324 insertions(+), 63 deletions(-) create mode 100644 selfdrive/assets/offroad/icon_wifi_uploading.svg create mode 100644 selfdrive/ui/qt/widgets/wifi.cc create mode 100644 selfdrive/ui/qt/widgets/wifi.h diff --git a/selfdrive/assets/offroad/icon_wifi_uploading.svg b/selfdrive/assets/offroad/icon_wifi_uploading.svg new file mode 100644 index 0000000000..95cb0e283e --- /dev/null +++ b/selfdrive/assets/offroad/icon_wifi_uploading.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index f54d72ae31..f46e3d5873 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -20,7 +20,7 @@ if arch == "Darwin": qt_env['FRAMEWORKS'] += ['OpenCL'] qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs) -widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/drive_stats.cc", +widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/drive_stats.cc", "qt/widgets/wifi.cc", "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 2b8974f73a..587e2f445e 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include "selfdrive/ui/qt/offroad/experimental_mode.h" @@ -136,21 +137,34 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { home_layout->setContentsMargins(0, 0, 0, 0); home_layout->setSpacing(30); - // left: ExperimentalModeButton, DriveStats - QWidget* left_widget = new QWidget(this); - QVBoxLayout* left_column = new QVBoxLayout(left_widget); - left_column->setContentsMargins(0, 0, 0, 0); - left_column->setSpacing(30); + // left: DriveStats/PrimeAdWidget + QStackedWidget *left_widget = new QStackedWidget(this); + left_widget->addWidget(new DriveStats); + left_widget->addWidget(new PrimeAdWidget); - ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); - QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); - left_column->addWidget(experimental_mode, 1); - left_column->addWidget(new DriveStats, 1); + left_widget->setCurrentIndex(uiState()->primeType() ? 0 : 1); + connect(uiState(), &UIState::primeTypeChanged, [=](int prime_type) { + left_widget->setCurrentIndex(prime_type ? 0 : 1); + }); home_layout->addWidget(left_widget, 1); - // right: SetupWidget - home_layout->addWidget(new SetupWidget); + // right: ExperimentalModeButton, SetupWidget + QWidget* right_widget = new QWidget(this); + QVBoxLayout* right_column = new QVBoxLayout(right_widget); + right_column->setContentsMargins(0, 0, 0, 0); + right_widget->setFixedWidth(750); + right_column->setSpacing(30); + + ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); + QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); + right_column->addWidget(experimental_mode, 1); + + SetupWidget *setup_widget = new SetupWidget; + QObject::connect(setup_widget, &SetupWidget::openSettings, this, &OffroadHome::openSettings); + right_column->addWidget(setup_widget, 1); + + home_layout->addWidget(right_widget, 1); } center_layout->addWidget(home_widget); @@ -170,7 +184,7 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { setStyleSheet(R"( * { - color: white; + color: white; } OffroadHome { background-color: black; diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc index fb4aea2b1c..86bd918e0c 100644 --- a/selfdrive/ui/qt/widgets/prime.cc +++ b/selfdrive/ui/qt/widgets/prime.cc @@ -14,6 +14,7 @@ #include "selfdrive/ui/qt/request_repeater.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/ui/qt/widgets/wifi.h" using qrcodegen::QrCode; @@ -123,26 +124,18 @@ PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QFrame(parent) { QWidget *primeWidget = new QWidget; primeWidget->setObjectName("primeWidget"); QVBoxLayout *primeLayout = new QVBoxLayout(primeWidget); - primeLayout->setContentsMargins(60, 50, 60, 50); + primeLayout->setContentsMargins(56, 40, 56, 40); + primeLayout->setSpacing(20); QLabel *subscribed = new QLabel(tr("✓ SUBSCRIBED")); subscribed->setStyleSheet("font-size: 41px; font-weight: bold; color: #86FF4E;"); - primeLayout->addWidget(subscribed, 0, Qt::AlignTop); - - primeLayout->addSpacing(60); + primeLayout->addWidget(subscribed); QLabel *commaPrime = new QLabel(tr("comma prime")); commaPrime->setStyleSheet("font-size: 75px; font-weight: bold;"); - primeLayout->addWidget(commaPrime, 0, Qt::AlignTop); - - primeLayout->addSpacing(20); - - QLabel *connectUrl = new QLabel(tr("CONNECT.COMMA.AI")); - connectUrl->setStyleSheet("font-size: 41px; font-family: Inter SemiBold; color: #A0A0A0;"); - primeLayout->addWidget(connectUrl, 0, Qt::AlignTop); + primeLayout->addWidget(commaPrime); mainLayout->addWidget(primeWidget); - mainLayout->addStretch(); } @@ -195,8 +188,8 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { QFrame* finishRegistration = new QFrame; finishRegistration->setObjectName("primeWidget"); QVBoxLayout* finishRegistationLayout = new QVBoxLayout(finishRegistration); - finishRegistationLayout->setSpacing(40); - finishRegistationLayout->setContentsMargins(64, 64, 64, 64); + finishRegistationLayout->setSpacing(38); + finishRegistationLayout->setContentsMargins(64, 48, 64, 48); QLabel* registrationTitle = new QLabel(tr("Finish Setup")); registrationTitle->setStyleSheet("font-size: 75px; font-weight: bold;"); @@ -204,7 +197,7 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { QLabel* registrationDescription = new QLabel(tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.")); registrationDescription->setWordWrap(true); - registrationDescription->setStyleSheet("font-size: 55px; font-weight: light;"); + registrationDescription->setStyleSheet("font-size: 50px; font-weight: light;"); finishRegistationLayout->addWidget(registrationDescription); finishRegistationLayout->addStretch(); @@ -234,15 +227,24 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { outer_layout->setContentsMargins(0, 0, 0, 0); outer_layout->addWidget(mainLayout); - primeAd = new PrimeAdWidget; - mainLayout->addWidget(primeAd); + QWidget *content = new QWidget; + QVBoxLayout *content_layout = new QVBoxLayout(content); + content_layout->setContentsMargins(0, 0, 0, 0); + content_layout->setSpacing(30); primeUser = new PrimeUserWidget; - mainLayout->addWidget(primeUser); + content_layout->addWidget(primeUser); - mainLayout->setCurrentWidget(uiState()->primeType() ? (QWidget*)primeUser : (QWidget*)primeAd); + WiFiPromptWidget *wifi_prompt = new WiFiPromptWidget; + QObject::connect(wifi_prompt, &WiFiPromptWidget::openSettings, this, &SetupWidget::openSettings); + content_layout->addWidget(wifi_prompt); + content_layout->addStretch(); + + mainLayout->addWidget(content); + + primeUser->setVisible(uiState()->primeType()); + mainLayout->setCurrentIndex(1); - setFixedWidth(750); setStyleSheet(R"( #primeWidget { border-radius: 10px; @@ -282,10 +284,7 @@ void SetupWidget::replyFinished(const QString &response, bool success) { } else { popup->reject(); - if (prime_type) { - mainLayout->setCurrentWidget(primeUser); - } else { - mainLayout->setCurrentWidget(primeAd); - } + primeUser->setVisible(prime_type); + mainLayout->setCurrentIndex(1); } } diff --git a/selfdrive/ui/qt/widgets/prime.h b/selfdrive/ui/qt/widgets/prime.h index 9c7b4460fc..b41bab1695 100644 --- a/selfdrive/ui/qt/widgets/prime.h +++ b/selfdrive/ui/qt/widgets/prime.h @@ -69,10 +69,12 @@ class SetupWidget : public QFrame { public: explicit SetupWidget(QWidget* parent = 0); +signals: + void openSettings(int index = 0, const QString ¶m = ""); + private: PairingPopup *popup; QStackedWidget *mainLayout; - PrimeAdWidget *primeAd; PrimeUserWidget *primeUser; private slots: diff --git a/selfdrive/ui/qt/widgets/wifi.cc b/selfdrive/ui/qt/widgets/wifi.cc new file mode 100644 index 0000000000..b717a00d98 --- /dev/null +++ b/selfdrive/ui/qt/widgets/wifi.cc @@ -0,0 +1,103 @@ +#include "selfdrive/ui/qt/widgets/wifi.h" + +#include +#include +#include +#include + +WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { + stack = new QStackedLayout(this); + + // Setup Wi-Fi + QFrame *setup = new QFrame; + QVBoxLayout *setup_layout = new QVBoxLayout(setup); + setup_layout->setContentsMargins(56, 40, 56, 40); + setup_layout->setSpacing(20); + { + QHBoxLayout *title_layout = new QHBoxLayout; + title_layout->setSpacing(32); + { + QLabel *icon = new QLabel; + QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_strength_full.svg"); + icon->setPixmap(pixmap->scaledToWidth(80, Qt::SmoothTransformation)); + title_layout->addWidget(icon); + + QLabel *title = new QLabel(tr("Setup Wi-Fi")); + title->setStyleSheet("font-size: 64px; font-weight: 600;"); + title_layout->addWidget(title); + title_layout->addStretch(); + } + setup_layout->addLayout(title_layout); + + QLabel *desc = new QLabel(tr("Connect to Wi-Fi to upload driving data and help improve openpilot")); + desc->setStyleSheet("font-size: 40px; font-weight: 400;"); + desc->setWordWrap(true); + setup_layout->addWidget(desc); + + QPushButton *settings_btn = new QPushButton(tr("Open Settings")); + connect(settings_btn, &QPushButton::clicked, [=]() { emit openSettings(1); }); + settings_btn->setStyleSheet(R"( + QPushButton { + font-size: 48px; + font-weight: 500; + border-radius: 10px; + background-color: #465BEA; + padding: 32px; + } + QPushButton:pressed { + background-color: #3049F4; + } + )"); + setup_layout->addWidget(settings_btn); + } + stack->addWidget(setup); + + // Uploading data + QWidget *uploading = new QWidget; + QVBoxLayout *uploading_layout = new QVBoxLayout(uploading); + uploading_layout->setContentsMargins(64, 56, 64, 56); + uploading_layout->setSpacing(36); + { + QHBoxLayout *title_layout = new QHBoxLayout; + { + QLabel *title = new QLabel(tr("Uploading training data")); + title->setStyleSheet("font-size: 64px; font-weight: 600;"); + title->setWordWrap(true); + title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + title_layout->addWidget(title); + title_layout->addStretch(); + + QLabel *icon = new QLabel; + QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_uploading.svg"); + icon->setPixmap(pixmap->scaledToWidth(120, Qt::SmoothTransformation)); + title_layout->addWidget(icon); + } + uploading_layout->addLayout(title_layout); + + QLabel *desc = new QLabel(tr("Your data is used to train driving models and help improve openpilot")); + desc->setStyleSheet("font-size: 48px; font-weight: 400;"); + desc->setWordWrap(true); + uploading_layout->addWidget(desc); + } + stack->addWidget(uploading); + + setStyleSheet(R"( + WiFiPromptWidget { + background-color: #333333; + border-radius: 10px; + } + )"); + + QObject::connect(uiState(), &UIState::uiUpdate, this, &WiFiPromptWidget::updateState); +} + +void WiFiPromptWidget::updateState(const UIState &s) { + if (!isVisible()) return; + + auto &sm = *(s.sm); + + auto network_type = sm["deviceState"].getDeviceState().getNetworkType(); + auto uploading = network_type == cereal::DeviceState::NetworkType::WIFI || + network_type == cereal::DeviceState::NetworkType::ETHERNET; + stack->setCurrentIndex(uploading ? 1 : 0); +} diff --git a/selfdrive/ui/qt/widgets/wifi.h b/selfdrive/ui/qt/widgets/wifi.h new file mode 100644 index 0000000000..60c865f2b8 --- /dev/null +++ b/selfdrive/ui/qt/widgets/wifi.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#include "selfdrive/ui/ui.h" + +class WiFiPromptWidget : public QFrame { + Q_OBJECT + +public: + explicit WiFiPromptWidget(QWidget* parent = 0); + +signals: + void openSettings(int index = 0, const QString ¶m = ""); + +public slots: + void updateState(const UIState &s); + +protected: + QStackedLayout *stack; +}; diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 5bec3f674a..71f3df7597 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -517,10 +517,6 @@ location set comma prime comma prime - - CONNECT.COMMA.AI - CONNECT.COMMA.AI -
QObject @@ -1076,6 +1072,29 @@ This may take up to a minute. Aktualisierung fehlgeschlagen + + WiFiPromptWidget + + Setup Wi-Fi + + + + Connect to Wi-Fi to upload driving data and help improve openpilot + + + + Open Settings + + + + Uploading training data + + + + Your data is used to train driving models and help improve openpilot + + + WifiUI diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 43e4974784..019eb1b71b 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -518,10 +518,6 @@ location set comma prime comma prime - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - QObject @@ -1070,6 +1066,29 @@ This may take up to a minute. 更新失敗 + + WiFiPromptWidget + + Setup Wi-Fi + + + + Connect to Wi-Fi to upload driving data and help improve openpilot + + + + Open Settings + + + + Uploading training data + + + + Your data is used to train driving models and help improve openpilot + + + WifiUI diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index c985fae0e9..cab5e2ada6 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -518,10 +518,6 @@ location set comma prime comma prime - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - QObject @@ -1071,6 +1067,29 @@ This may take up to a minute. 업데이트 실패 + + WiFiPromptWidget + + Setup Wi-Fi + + + + Connect to Wi-Fi to upload driving data and help improve openpilot + + + + Open Settings + + + + Uploading training data + + + + Your data is used to train driving models and help improve openpilot + + + WifiUI diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 9eeedea29c..70f06670a9 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -519,10 +519,6 @@ trabalho definido comma prime comma prime - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - QObject @@ -1075,6 +1071,29 @@ Isso pode levar até um minuto. Falha na atualização + + WiFiPromptWidget + + Setup Wi-Fi + + + + Connect to Wi-Fi to upload driving data and help improve openpilot + + + + Open Settings + + + + Uploading training data + + + + Your data is used to train driving models and help improve openpilot + + + WifiUI diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 9302047ab0..f6924b3c57 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -516,10 +516,6 @@ location set comma prime comma prime - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - QObject @@ -1068,6 +1064,29 @@ This may take up to a minute. 更新失败 + + WiFiPromptWidget + + Setup Wi-Fi + + + + Connect to Wi-Fi to upload driving data and help improve openpilot + + + + Open Settings + + + + Uploading training data + + + + Your data is used to train driving models and help improve openpilot + + + WifiUI diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 5d17a7b86a..243a91ebd1 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -518,10 +518,6 @@ location set comma prime comma 高級會員 - - CONNECT.COMMA.AI - CONNECT.COMMA.AI - QObject @@ -1070,6 +1066,29 @@ This may take up to a minute. 更新失敗 + + WiFiPromptWidget + + Setup Wi-Fi + + + + Connect to Wi-Fi to upload driving data and help improve openpilot + + + + Open Settings + + + + Uploading training data + + + + Your data is used to train driving models and help improve openpilot + + + WifiUI From 67b27b7496289fb7f05c603f44b4a76a104cd32f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 4 Jun 2023 02:43:27 +0800 Subject: [PATCH 141/283] replay: fixed incorrect totalSeconds when there are invalid segments in route (#28388) --- tools/replay/replay.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/replay.h b/tools/replay/replay.h index bf66b8d8b9..b7704132c2 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -68,7 +68,7 @@ public: inline QDateTime currentDateTime() const { return route_->datetime().addSecs(currentSeconds()); } inline uint64_t routeStartTime() const { return route_start_ts_; } inline int toSeconds(uint64_t mono_time) const { return (mono_time - route_start_ts_) / 1e9; } - inline int totalSeconds() const { return segments_.size() * 60; } + inline int totalSeconds() const { return (!segments_.empty()) ? (segments_.rbegin()->first + 1) * 60 : 0; } inline void setSpeed(float speed) { speed_ = speed; } inline float getSpeed() const { return speed_; } inline const std::vector *events() const { return events_.get(); } From 92d8295096468b65e35b660a9b536d99d2ce2b9f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sun, 4 Jun 2023 07:51:16 +1000 Subject: [PATCH 142/283] cabana: Add menu item that resets the window layout (#28390) --- tools/cabana/mainwin.cc | 7 +++++++ tools/cabana/mainwin.h | 1 + 2 files changed, 8 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index fd24c3f6db..421bb9a5d7 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -32,6 +32,9 @@ MainWindow::MainWindow() : QMainWindow() { createStatusBar(); createShortcuts(); + // save default window state to allow resetting it + default_state = saveState(); + // restore states restoreGeometry(settings.geometry); if (isMaximized()) { @@ -135,6 +138,10 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(new QUndoView(UndoStack::instance())); commands_menu->addAction(commands_act); + edit_menu->addSeparator(); + edit_menu->addAction(tr("Reset Window Layout"), + [this]() { restoreState(default_state); }); + tools_menu = menuBar()->addMenu(tr("&Tools")); tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); tools_menu->addAction(tr("&Find Signal"), this, &MainWindow::findSignal); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 72ed0ae5cc..77467e2e45 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -98,6 +98,7 @@ protected: QString car_fingerprint; int prev_undostack_index = 0; int prev_undostack_count = 0; + QByteArray default_state; friend class OnlineHelp; }; From 8bfc78c265c87bac8f167f09e31547a23da459bc Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Sat, 3 Jun 2023 21:15:39 -0300 Subject: [PATCH 143/283] update pt-BR translations (#28393) --- selfdrive/ui/translations/main_pt-BR.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 70f06670a9..6687fea865 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -285,11 +285,11 @@ ExperimentalModeButton EXPERIMENTAL MODE ON - MODO EXPERIMENTAL ATIVADO + MODO EXPERIMENTAL ON CHILL MODE ON - MODO CHILL ATIVADO + MODO CHILL ON @@ -1075,23 +1075,24 @@ Isso pode levar até um minuto. WiFiPromptWidget Setup Wi-Fi - + Configurar +Wi-Fi Connect to Wi-Fi to upload driving data and help improve openpilot - + Conecte se ao Wi-Fi para upload de dados de condução e ajudar a melhorar o openpilot Open Settings - + Abrir Configurações Uploading training data - + Subindo dados para treinamento Your data is used to train driving models and help improve openpilot - + Seus dados são utilizados para treinar modelos de direção e ajudar a melhorar o openpilot From f659d4d44b1192467a7ad0d34c4f6747ae7382b4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 5 Jun 2023 07:04:09 +1000 Subject: [PATCH 144/283] cabana dbc: Sort signals by name if start bits are equal (#28399) --- tools/cabana/dbc/dbc.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index cb5ebff602..aaa4a97ea9 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -9,7 +9,13 @@ std::vector cabana::Msg::getSignals() const { std::vector ret; ret.reserve(sigs.size()); for (auto &sig : sigs) ret.push_back(&sig); - std::sort(ret.begin(), ret.end(), [](auto l, auto r) { return l->start_bit < r->start_bit; }); + std::sort(ret.begin(), ret.end(), [](auto l, auto r) { + if (l->start_bit != r->start_bit) { + return l->start_bit < r->start_bit; + } + // For VECTOR__INDEPENDENT_SIG_MSG, many signals have same start bit + return l->name < r->name; + }); return ret; } From e276d2a417a5133fb91c93b2ef30df68a7d5f225 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 4 Jun 2023 14:06:04 -0700 Subject: [PATCH 145/283] update pylint (#28395) * update pylint * update config * fix --- .pylintrc | 4 ++-- poetry.lock | 18 +++++++++--------- system/sensord/rawgps/rawgpsd.py | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.pylintrc b/.pylintrc index 58988c5d74..ae91dd3d7c 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,7 +3,7 @@ # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code -extension-pkg-whitelist=scipy,cereal.messaging.messaging_pyx,PyQt5,av +extension-pkg-whitelist=scipy,cereal.messaging.messaging_pyx,PyQt5,av,pycurl # Add files or directories to the blacklist. They should be base names, not # paths. @@ -466,4 +466,4 @@ check-str-concat-over-line-jumps=yes # Exceptions that will emit a warning when being caught. Defaults to # "Exception" -overgeneral-exceptions=Exception +overgeneral-exceptions= diff --git a/poetry.lock b/poetry.lock index 91eb7e42e0..e0e843ff0d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -188,7 +188,7 @@ tests = ["pytest"] [[package]] name = "astroid" -version = "2.12.12" +version = "2.15.5" description = "An abstract syntax tree for Python with inference support." category = "main" optional = false @@ -196,7 +196,7 @@ python-versions = ">=3.7.2" [package.dependencies] lazy-object-proxy = ">=1.4.0" -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""} [[package]] @@ -3253,16 +3253,16 @@ python-versions = "*" [[package]] name = "pylint" -version = "2.15.4" +version = "2.17.4" description = "python code static checker" category = "main" optional = false python-versions = ">=3.7.2" [package.dependencies] -astroid = ">=2.12.11,<=2.14.0-dev0" +astroid = ">=2.15.4,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = ">=0.2" +dill = {version = ">=0.2", markers = "python_version < \"3.11\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" @@ -4969,8 +4969,8 @@ argon2-cffi-bindings = [ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, ] astroid = [ - {file = "astroid-2.12.12-py3-none-any.whl", hash = "sha256:72702205200b2a638358369d90c222d74ebc376787af8fb2f7f2a86f7b5cc85f"}, - {file = "astroid-2.12.12.tar.gz", hash = "sha256:1c00a14f5a3ed0339d38d2e2e5b74ea2591df5861c0936bb292b84ccf3a78d83"}, + {file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"}, + {file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"}, ] asttokens = [ {file = "asttokens-2.0.8-py2.py3-none-any.whl", hash = "sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86"}, @@ -7569,8 +7569,8 @@ pylev = [ {file = "pylev-1.4.0.tar.gz", hash = "sha256:9e77e941042ad3a4cc305dcdf2b2dec1aec2fbe3dd9015d2698ad02b173006d1"}, ] pylint = [ - {file = "pylint-2.15.4-py3-none-any.whl", hash = "sha256:629cf1dbdfb6609d7e7a45815a8bb59300e34aa35783b5ac563acaca2c4022e9"}, - {file = "pylint-2.15.4.tar.gz", hash = "sha256:5441e9294335d354b7bad57c1044e5bd7cce25c433475d76b440e53452fa5cb8"}, + {file = "pylint-2.17.4-py3-none-any.whl", hash = "sha256:7a1145fb08c251bdb5cca11739722ce64a63db479283d10ce718b2460e54123c"}, + {file = "pylint-2.17.4.tar.gz", hash = "sha256:5dcf1d9e19f41f38e4e85d10f511e5b9c35e1aa74251bf95cdd8cb23584e2db1"}, ] pymsalruntime = [ {file = "pymsalruntime-0.11.2-cp310-cp310-win32.whl", hash = "sha256:a45e35c9fa58c196029bb9f5b8bedd313b2a8ac971d576c57c31cb06139de247"}, diff --git a/system/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py index a5eafb268d..46f5cf83c9 100755 --- a/system/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -117,11 +117,11 @@ def download_and_inject_assistance(): # download assistance try: c = pycurl.Curl() - c.setopt(c.URL, assistance_url) - c.setopt(c.NOBODY, 1) + c.setopt(pycurl.URL, assistance_url) + c.setopt(pycurl.NOBODY, 1) c.setopt(pycurl.CONNECTTIMEOUT, 2) c.perform() - bytes_n = c.getinfo(c.CONTENT_LENGTH_DOWNLOAD) + bytes_n = c.getinfo(pycurl.CONTENT_LENGTH_DOWNLOAD) c.close() if bytes_n > 1e5: cloudlog.error("Qcom assistance data larger than expected") From 90d31b9db4aac2735a8c1a9e518753c8e450f2e3 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Mon, 5 Jun 2023 08:52:25 +0900 Subject: [PATCH 146/283] kor translation update (#28401) --- selfdrive/ui/translations/main_ko.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index cab5e2ada6..c5247ccfa0 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1071,23 +1071,23 @@ This may take up to a minute. WiFiPromptWidget Setup Wi-Fi - + Wi-Fi 설정 Connect to Wi-Fi to upload driving data and help improve openpilot - + Wi-Fi에 연결하여 주행 데이터를 업로드하고 openpilot 개선에 참여하세요. Open Settings - + 설정 열기 Uploading training data - + 트레이닝 데이터 업로드 Your data is used to train driving models and help improve openpilot - + 귀하의 데이터는 운전 모델을 교육하고 openpilot을 개선하는 데 사용됩니다. From 7c26fc716aa2611acc2e80ff19c138e9a077803c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 4 Jun 2023 18:57:11 -0700 Subject: [PATCH 147/283] match_fw_to_car_exact: get config once per candidate (#28384) lesss --- selfdrive/car/fw_versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 3c18c2e7bd..cd3ef7977c 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -103,8 +103,8 @@ def match_fw_to_car_exact(fw_versions_dict) -> Set[str]: candidates = FW_VERSIONS for candidate, fws in candidates.items(): + config = FW_QUERY_CONFIGS[MODEL_TO_BRAND[candidate]] for ecu, expected_versions in fws.items(): - config = FW_QUERY_CONFIGS[MODEL_TO_BRAND[candidate]] ecu_type = ecu[0] addr = ecu[1:] From b792485dfd0e2645baa52410a3b49b090486e16d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 4 Jun 2023 18:58:26 -0700 Subject: [PATCH 148/283] =?UTF-8?q?cars=20docs:=20add=20=C5=A0koda=20heate?= =?UTF-8?q?d=20windshield=20footnote=20(#28380)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add heated windshield footnote --- docs/CARS.md | 111 +++++++++++++++-------------- selfdrive/car/volkswagen/values.py | 10 ++- 2 files changed, 64 insertions(+), 57 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 6da46e79fd..373851932f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -11,12 +11,12 @@ A supported vehicle is one that just works when you install a comma three. All s |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 OBD-II connector
- 1 comma three
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -153,8 +153,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan B connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -162,8 +162,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Nissan A connector
- 1 RJ45 cable (7 ft)
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Ram connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -174,14 +174,14 @@ A supported vehicle is one that just works when you install a comma three. All s |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru B connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Subaru A connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Fabia 2022-23[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Škoda|Kamiq 2021[7,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Škoda|Karoq 2019-21[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Kodiaq 2017-23[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Octavia 2015, 2018-19[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Octavia RS 2016[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Škoda|Scala 2020[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Škoda|Superb 2015-22[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -225,41 +225,41 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[10](#footnotes)|| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[11](#footnotes)|| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| ### Footnotes 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
@@ -270,8 +270,9 @@ A supported vehicle is one that just works when you install a comma three. All s 6openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
7Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
8Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
-9Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC.
-10Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
+9Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma three functionality.
+10Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC.
+11Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
## Community Maintained Cars 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/). diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 68df7ea2d4..fd9d54d104 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -154,7 +154,11 @@ class Footnote(Enum): PASSAT = CarFootnote( "Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.", Column.MODEL) - VW_EXP_LONG = CarFootnote ( + SKODA_HEATED_WINDSHIELD = CarFootnote( + "Some Škoda vehicles are equipped with heated windshields, which are known " + + "to block GPS signal needed for some comma three functionality.", + Column.MODEL) + VW_EXP_LONG = CarFootnote( "Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness " + "are limited to using stock ACC.", Column.LONGITUDINAL) @@ -170,7 +174,9 @@ class VWCarInfo(CarInfo): car_parts: CarParts = CarParts.common([CarHarness.j533]) def init_make(self, CP: car.CarParams): - self.footnotes.insert(0, Footnote.VW_EXP_LONG) + self.footnotes.append(Footnote.VW_EXP_LONG) + if "SKODA" in CP.carFingerprint: + self.footnotes.append(Footnote.SKODA_HEATED_WINDSHIELD) if CP.carFingerprint in (CAR.CRAFTER_MK2, CAR.TRANSPORTER_T61): self.car_parts = CarParts([Device.three_angled_mount, CarHarness.j533]) From b7a2a921ecd9576799922287fd43d18c75c0042b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 6 Jun 2023 00:44:30 +0800 Subject: [PATCH 149/283] cabana: segment live stream logging (#28407) --- tools/cabana/streams/livestream.cc | 30 +++++++++++++++++++++++++----- tools/cabana/streams/livestream.h | 4 +++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 6ad929b2ee..91c88c97ca 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -1,10 +1,30 @@ #include "tools/cabana/streams/livestream.h" +struct LiveStream::Logger { + Logger() : start_ts(seconds_since_epoch()), segment_num(-1) {} + + void write(const char *data, const size_t size) { + int n = (seconds_since_epoch() - start_ts) / 60.0; + if (std::exchange(segment_num, n) != segment_num) { + QString dir = QString("%1/%2--%3") + .arg(settings.log_path) + .arg(QDateTime::fromSecsSinceEpoch(start_ts).toString("yyyy-MM-dd--hh-mm-ss")) + .arg(n); + util::create_directories(dir.toStdString(), 0755); + fs.reset(new std::ofstream((dir + "/rlog").toStdString(), std::ios::binary | std::ios::out)); + } + + fs->write(data, size); + } + + std::unique_ptr fs; + int segment_num; + uint64_t start_ts; +}; + LiveStream::LiveStream(QObject *parent) : AbstractStream(parent) { if (settings.log_livestream) { - std::string path = (settings.log_path + "/" + QDateTime::currentDateTime().toString("yyyy-MM-dd--hh-mm-ss") + "--0").toStdString(); - util::create_directories(path, 0755); - fs.reset(new std::ofstream(path + "/rlog", std::ios::binary | std::ios::out)); + logger = std::make_unique(); } stream_thread = new QThread(this); @@ -34,8 +54,8 @@ LiveStream::~LiveStream() { // called in streamThread void LiveStream::handleEvent(const char *data, const size_t size) { - if (fs) { - fs->write(data, size); + if (logger) { + logger->write(data, size); } std::lock_guard lk(lock); diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 577074b415..b4816d090f 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -42,7 +42,6 @@ private: std::vector receivedEvents; std::deque receivedMessages; - std::unique_ptr fs; int timer_id; QBasicTimer update_timer; @@ -53,4 +52,7 @@ private: bool post_last_event = true; double speed_ = 1; bool paused_ = false; + + struct Logger; + std::unique_ptr logger; }; From cabcde38ada58e34e829fa2b13282da87595b838 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 5 Jun 2023 09:49:11 -0700 Subject: [PATCH 150/283] Revert "Hyundai: explicitly copy signals to forward (#28020)" (#28406) This reverts commit f494abf0d2db769a0a55ac29a3914962c3db902b. --- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/car/hyundai/hyundaican.py | 33 ++--------------------- selfdrive/car/hyundai/hyundaicanfd.py | 36 +++++--------------------- 3 files changed, 10 insertions(+), 61 deletions(-) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 11ff2fb6e4..ac74d2cc5b 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -141,7 +141,7 @@ class CarController: # 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)) + can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CAN, CS.cruise_info)) self.last_button_frame = self.frame else: for _ in range(20): diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index dc5a5b6286..afd1123260 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -7,23 +7,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, torque_fault, lkas11, sys_warning, sys_state, enabled, left_lane, right_lane, left_lane_depart, right_lane_depart): - values = {s: lkas11[s] for s in [ - "CF_Lkas_LdwsActivemode", - "CF_Lkas_LdwsSysState", - "CF_Lkas_SysWarning", - "CF_Lkas_LdwsLHWarning", - "CF_Lkas_LdwsRHWarning", - "CF_Lkas_HbaLamp", - "CF_Lkas_FcwBasReq", - "CF_Lkas_HbaSysState", - "CF_Lkas_FcwOpt", - "CF_Lkas_HbaOpt", - "CF_Lkas_FcwSysState", - "CF_Lkas_FcwCollisionWarning", - "CF_Lkas_FusionState", - "CF_Lkas_FcwOpt_USM", - "CF_Lkas_LdwsOpt_USM", - ]} + values = lkas11 values["CF_Lkas_LdwsSysState"] = sys_state values["CF_Lkas_SysWarning"] = 3 if sys_warning else 0 values["CF_Lkas_LdwsLHWarning"] = left_lane_depart @@ -95,20 +79,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, def create_clu11(packer, frame, clu11, button, car_fingerprint): - values = {s: clu11[s] for s in [ - "CF_Clu_CruiseSwState", - "CF_Clu_CruiseSwMain", - "CF_Clu_SldMainSW", - "CF_Clu_ParityBit1", - "CF_Clu_VanzDecimal", - "CF_Clu_Vanz", - "CF_Clu_SPEED_UNIT", - "CF_Clu_DetentOut", - "CF_Clu_RheostatLevel", - "CF_Clu_CluInfo", - "CF_Clu_AmpInfo", - "CF_Clu_AliveCnt1", - ]} + values = clu11 values["CF_Clu_CruiseSwState"] = button values["CF_Clu_AliveCnt1"] = frame % 0x10 # send buttons to camera on camera-scc based cars diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index da9cff8225..3717a45909 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -63,11 +63,11 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer): return ret -def create_cam_0x2a4(packer, CAN, cam_0x2a4): - values = {f"BYTE{i}": cam_0x2a4[f"BYTE{i}"] for i in range(3, 24)} - values['COUNTER'] = cam_0x2a4['COUNTER'] - values["BYTE7"] = 0 - return packer.make_can_msg("CAM_0x2a4", CAN.ACAN, values) +def create_cam_0x2a4(packer, CAN, camera_values): + camera_values.update({ + "BYTE7": 0, + }) + return packer.make_can_msg("CAM_0x2a4", CAN.ACAN, camera_values) def create_buttons(packer, CP, CAN, cnt, btn): values = { @@ -79,30 +79,8 @@ def create_buttons(packer, CP, CAN, cnt, btn): bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM return packer.make_can_msg("CRUISE_BUTTONS", bus, values) -def create_acc_cancel(packer, CP, CAN, cruise_info_copy): - # 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", - "CHECKSUM", - "NEW_SIGNAL_1", - "MainMode_ACC", - "ACCMode", - "CRUISE_INACTIVE", - "ZEROS_9", - "CRUISE_STANDSTILL", - "ZEROS_5", - "DISTANCE_SETTING", - "VSetDis", - ]} - else: - values = {s: cruise_info_copy[s] for s in [ - "COUNTER", - "CHECKSUM", - "ACCMode", - "VSetDis", - "CRUISE_STANDSTILL", - ]} +def create_acc_cancel(packer, CAN, cruise_info_copy): + values = cruise_info_copy values.update({ "ACCMode": 4, }) From a6a9b65121ca7a08c3e05e3cdb542d895b0e5764 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 5 Jun 2023 13:45:03 -0700 Subject: [PATCH 151/283] Chrysler: fix FW sorting --- selfdrive/car/chrysler/values.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 24f3f92a92..f0b60a0da1 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -225,8 +225,8 @@ FW_VERSIONS = { b'68453513AD', b'68453514AD', b'68510283AG', - b'68527375AD', b'68527346AE', + b'68527375AD', ], (Ecu.srs, 0x744, None): [ b'68428609AB', @@ -248,8 +248,8 @@ FW_VERSIONS = { b'68438456AF', b'68535469AB', b'68535470AC', - b'68586307AB', b'68548900AB', + b'68586307AB', ], (Ecu.fwdRadar, 0x753, None): [ b'04672892AB', @@ -275,13 +275,14 @@ FW_VERSIONS = { b'68522583AB', b'68522585AB', b'68552788AA', + b'68552789AA', b'68552790AA', b'68585112AB', - b'68552789AA', ], (Ecu.engine, 0x7e0, None): [ b'05036065AE ', b'05036066AE ', + b'05149846AA ', b'68378701AI ', b'68378758AM ', b'68448163AJ', @@ -289,7 +290,6 @@ FW_VERSIONS = { b'68500630AD', b'68500630AE', b'68539650AD', - b'05149846AA ', ], (Ecu.transmission, 0x7e1, None): [ b'68360078AL', @@ -301,8 +301,8 @@ FW_VERSIONS = { b'68445533AB', b'68484467AC', b'68502994AD', - b'68540431AB', b'68520867AE', + b'68540431AB', ], }, From e8ccbd22dd3ae1b7ee53ebe0ca766eb639a15576 Mon Sep 17 00:00:00 2001 From: Vincent Wright Date: Mon, 5 Jun 2023 17:04:30 -0400 Subject: [PATCH 152/283] Ram 3500 Firmware (#28411) * Ram 3500 Firmware Dongle ID: d9855ccd97606ca8 * fix sorting --------- Co-authored-by: Cameron Clough --- selfdrive/car/chrysler/values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index f0b60a0da1..bd7c3acc36 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -314,6 +314,7 @@ FW_VERSIONS = { b'68525485AB', b'68525487AB', b'68525498AB', + b'68528791AF', ], (Ecu.srs, 0x744, None): [ b'68399794AC', @@ -329,9 +330,11 @@ FW_VERSIONS = { b'68504022AC', b'68530686AB', b'68530686AC', + b'68544596AC', ], (Ecu.fwdRadar, 0x753, None): [ b'04672895AB', + b'04672934AB', b'56029827AG', b'56029827AH', b'68462657AE', @@ -341,6 +344,7 @@ FW_VERSIONS = { (Ecu.eps, 0x761, None): [ b'68421036AC', b'68507906AB', + b'68534023AC', ], (Ecu.engine, 0x7e0, None): [ b'52370131AF', @@ -349,6 +353,7 @@ FW_VERSIONS = { b'52370931CT', b'52401032AE', b'52421132AF', + b'52421332AF', b'68527616AD ', b'M2370131MB', b'M2421132MB', From ff7444c156edaace0fdf0a52d9f189db136a82ed Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Tue, 6 Jun 2023 05:18:03 +0800 Subject: [PATCH 153/283] VW MQB: Add FW for 2018 Skoda Karoq (#28409) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VW MQB: Add FW for 2018 Skoda Karoq route name:5663ab22a30b9a6e|2023-06-05--14-07-24--0 * fix sorting --------- Co-authored-by: Cameron Clough --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index fd9d54d104..1fc21fe5c0 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1127,6 +1127,7 @@ FW_VERSIONS = { }, CAR.SKODA_KAROQ_MK1: { (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8705E906018P \xf1\x895472', b'\xf1\x8705E906018P \xf1\x896020', b'\xf1\x8705L906022BS\xf1\x890913', ], @@ -1135,14 +1136,17 @@ FW_VERSIONS = { b'\xf1\x870GC300014L \xf1\x892802', ], (Ecu.srs, 0x715, None): [ + b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\x0e1213001211001101131112012100', b'\xf1\x873Q0959655BH\xf1\x890712\xf1\x82\0161213001211001101131122012100', b'\xf1\x873Q0959655DE\xf1\x890731\xf1\x82\x0e1213001211001101131121012J00', ], (Ecu.eps, 0x712, None): [ + b'\xf1\x875Q0910143B \xf1\x892201\xf1\x82\x0563T6090500', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\00567T6100500', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T6100700', ], (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x872Q0907572AB\xf1\x890397', b'\xf1\x872Q0907572M \xf1\x890233', b'\xf1\x872Q0907572T \xf1\x890383', ], From 6d91b7c341afd1bf38e1bb044338a2026d0a6c94 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 5 Jun 2023 15:28:38 -0700 Subject: [PATCH 154/283] jenkins: ensure panda is in good state (#28414) --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index c7ef88811f..128273792e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -175,12 +175,12 @@ pipeline { steps { phone_steps("tici-common", [ ["build", "cd selfdrive/manager && ./build.py"], + ["test pandad", "python selfdrive/boardd/tests/test_pandad.py"], ["test power draw", "python system/hardware/tici/tests/test_power_draw.py"], ["test loggerd", "python system/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python system/loggerd/tests/test_encoder.py"], ["test pigeond", "python system/sensord/tests/test_pigeond.py"], ["test manager", "python selfdrive/manager/test/test_manager.py"], - ["test pandad", "python selfdrive/boardd/tests/test_pandad.py"], ]) } } From d5101e11ad79af24d77ed3b1b1f8894440cb5233 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 5 Jun 2023 17:17:38 -0700 Subject: [PATCH 155/283] modeld: adjust CL priority (#28413) --- selfdrive/modeld/thneed/thneed_qcom2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/modeld/thneed/thneed_qcom2.cc b/selfdrive/modeld/thneed/thneed_qcom2.cc index a29a82c8c8..eda037178a 100644 --- a/selfdrive/modeld/thneed/thneed_qcom2.cc +++ b/selfdrive/modeld/thneed/thneed_qcom2.cc @@ -43,7 +43,7 @@ int ioctl(int filedes, unsigned long request, void *argp) { if (request == IOCTL_KGSL_DRAWCTXT_CREATE) { struct kgsl_drawctxt_create *create = (struct kgsl_drawctxt_create *)argp; create->flags &= ~KGSL_CONTEXT_PRIORITY_MASK; - create->flags |= 1 << KGSL_CONTEXT_PRIORITY_SHIFT; // priority from 1-15, 1 is max priority + create->flags |= 6 << KGSL_CONTEXT_PRIORITY_SHIFT; // priority from 1-15, 1 is max priority printf("IOCTL_KGSL_DRAWCTXT_CREATE: creating context with flags 0x%x\n", create->flags); } From aa4bbcefd3d68ae670dd5c57b0dceb0e57931567 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 5 Jun 2023 17:27:34 -0700 Subject: [PATCH 156/283] ui: wrap missing updater text (#28417) * wrap more * wrap more * and that * update --- selfdrive/ui/qt/offroad/software_settings.cc | 14 +++++++------- selfdrive/ui/translations/main_de.ts | 20 ++++++++++++++++++++ selfdrive/ui/translations/main_ja.ts | 20 ++++++++++++++++++++ selfdrive/ui/translations/main_ko.ts | 20 ++++++++++++++++++++ selfdrive/ui/translations/main_pt-BR.ts | 20 ++++++++++++++++++++ selfdrive/ui/translations/main_zh-CHS.ts | 20 ++++++++++++++++++++ selfdrive/ui/translations/main_zh-CHT.ts | 20 ++++++++++++++++++++ 7 files changed, 127 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 6db6a6cdfe..d25c8490f3 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -126,19 +126,19 @@ void SoftwarePanel::updateLabels() { downloadBtn->setValue(updater_state); } else { if (failed) { - downloadBtn->setText("CHECK"); - downloadBtn->setValue("failed to check for update"); + downloadBtn->setText(tr("CHECK")); + downloadBtn->setValue(tr("failed to check for update")); } else if (params.getBool("UpdaterFetchAvailable")) { - downloadBtn->setText("DOWNLOAD"); - downloadBtn->setValue("update available"); + downloadBtn->setText(tr("DOWNLOAD")); + downloadBtn->setValue(tr("update available")); } else { - QString lastUpdate = "never"; + QString lastUpdate = tr("never"); auto tm = params.get("LastUpdateTime"); if (!tm.empty()) { lastUpdate = timeAgo(QDateTime::fromString(QString::fromStdString(tm + "Z"), Qt::ISODate)); } - downloadBtn->setText("CHECK"); - downloadBtn->setValue("up to date, last checked " + lastUpdate); + downloadBtn->setText(tr("CHECK")); + downloadBtn->setValue(tr("up to date, last checked %1").arg(lastUpdate)); } downloadBtn->setEnabled(true); } diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 71f3df7597..7fda980e92 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -858,6 +858,26 @@ This may take up to a minute. Uninstall Deinstallieren + + failed to check for update + + + + up to date, last checked %1 + + + + DOWNLOAD + + + + update available + + + + never + +
SshControl diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 019eb1b71b..10da629cf9 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -854,6 +854,26 @@ This may take up to a minute. Uninstall アンインストール + + failed to check for update + + + + up to date, last checked %1 + + + + DOWNLOAD + + + + update available + + + + never + + SshControl diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index c5247ccfa0..ad9a4e05d9 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -855,6 +855,26 @@ This may take up to a minute. Uninstall 제거 + + failed to check for update + + + + up to date, last checked %1 + + + + DOWNLOAD + + + + update available + + + + never + + SshControl diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 6687fea865..5aa4245fda 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -859,6 +859,26 @@ Isso pode levar até um minuto. Uninstall Desinstalar + + failed to check for update + + + + up to date, last checked %1 + + + + DOWNLOAD + + + + update available + + + + never + + SshControl diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index f6924b3c57..e7382075fb 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -852,6 +852,26 @@ This may take up to a minute. Uninstall 卸载 + + failed to check for update + + + + up to date, last checked %1 + + + + DOWNLOAD + + + + update available + + + + never + + SshControl diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 243a91ebd1..d112d86b08 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -854,6 +854,26 @@ This may take up to a minute. Uninstall 解除安裝 + + failed to check for update + + + + up to date, last checked %1 + + + + DOWNLOAD + + + + update available + + + + never + + SshControl From dd6f7116f70159c4f61e72f028abbdaeecc5eec9 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Mon, 5 Jun 2023 20:27:02 -0700 Subject: [PATCH 157/283] Test power usage for mapsd and navmodeld (#28378) * Test power usage for mapsd and navmodeld * Send LLK message from thread * Use threading.Event --- system/hardware/tici/tests/test_power_draw.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index df4852183e..4683bba1f9 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -2,9 +2,11 @@ import unittest import time import math +import threading from dataclasses import dataclass from tabulate import tabulate +import cereal.messaging as messaging from system.hardware import HARDWARE, TICI from system.hardware.tici.power_monitor import get_power from selfdrive.manager.process_config import managed_processes @@ -24,8 +26,22 @@ PROCS = [ Proc('modeld', 0.93, atol=0.2), Proc('dmonitoringmodeld', 0.4), Proc('encoderd', 0.23), + Proc('mapsd', 0.1), + Proc('navmodeld', 0.05), ] +def send_llk_msg(done): + pm = messaging.PubMaster(['liveLocationKalman']) + msg = messaging.new_message('liveLocationKalman') + msg.liveLocationKalman.positionGeodetic = {'value': [32.7174, -117.16277, 0], 'std': [0., 0., 0.], 'valid': True} + msg.liveLocationKalman.calibratedOrientationNED = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True} + msg.liveLocationKalman.status = 'valid' + + # Send liveLocationKalman at 20hz + while not done.is_set(): + pm.send('liveLocationKalman', msg) + time.sleep(1/20) + class TestPowerDraw(unittest.TestCase): @@ -46,6 +62,9 @@ class TestPowerDraw(unittest.TestCase): def test_camera_procs(self): baseline = get_power() + done = threading.Event() + thread = threading.Thread(target=send_llk_msg, args=(done,), daemon=True) + thread.start() prev = baseline used = {} @@ -57,6 +76,7 @@ class TestPowerDraw(unittest.TestCase): used[proc.name] = now - prev prev = now + done.set() manager_cleanup() tab = [] From 16ff32d2c20e2d792a351b031a698fac5fa2d36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 5 Jun 2023 20:56:43 -0700 Subject: [PATCH 158/283] bump cereal (#28421) --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 8af4582508..c331e76b96 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 8af4582508dd7acef082c40ede11eb7018415d9a +Subproject commit c331e76b966d324a4f8d56b48db44f59601423dc From 205c900742a18ca4662f4535a1a4008624c05995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 5 Jun 2023 22:17:41 -0700 Subject: [PATCH 159/283] Driving Personality setting (also changes follow distance) (#24742) * Skeleton * Adjustable follow parameter * fix rebase * long planner * typo * Add ui toggle * Fix icon * Improve text * Better toggle position * Im a UX engineer now * add param reader * CHange jerk to have same crash test performance * Try reading param * Unused comment * translate ui text * std stoi * Parametrized buttons * Empty strings are ints * Move to generic * Update translations * Fix translation diffs * Release notes * update refs * tweaks * Misc fixes * No param is standard --- RELEASES.md | 5 ++ common/params.cc | 1 + .../lib/longitudinal_mpc_lib/long_mpc.py | 49 ++++++++---- .../controls/lib/longitudinal_planner.py | 21 +++++- selfdrive/manager/manager.py | 2 + selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/ui/qt/offroad/settings.cc | 12 +++ selfdrive/ui/qt/widgets/controls.h | 74 +++++++++++++++++++ selfdrive/ui/translations/main_de.ts | 20 +++++ selfdrive/ui/translations/main_ja.ts | 20 +++++ selfdrive/ui/translations/main_ko.ts | 20 +++++ selfdrive/ui/translations/main_pt-BR.ts | 20 +++++ selfdrive/ui/translations/main_zh-CHS.ts | 20 +++++ selfdrive/ui/translations/main_zh-CHT.ts | 20 +++++ 14 files changed, 270 insertions(+), 16 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 547add8a80..482e959d9b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,11 @@ Version 0.9.3 (2023-06-XX) ======================== * New driving model +* New driving personality setting + * Three settings: aggressive, standard, and relaxed + * Standard is recommended and the default + * In aggressive mode lead follow distance is shorter and quicker gas/brake response + * In relaxed mode lead follow distance is longer Version 0.9.2 (2023-05-22) ======================== diff --git a/common/params.cc b/common/params.cc index 530ffe3051..843c57c564 100644 --- a/common/params.cc +++ b/common/params.cc @@ -104,6 +104,7 @@ std::unordered_map keys = { {"DisablePowerDown", PERSISTENT}, {"ExperimentalMode", PERSISTENT}, {"ExperimentalModeConfirmed", PERSISTENT}, + {"LongitudinalPersonality", PERSISTENT}, {"ExperimentalLongitudinalEnabled", PERSISTENT}, {"DisableUpdates", PERSISTENT}, {"DisengageOnAccelerator", PERSISTENT}, diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 660002691a..23fb1b7790 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import os import numpy as np - +from cereal import log from common.realtime import sec_since_boot from common.numpy_fast import clip from system.swaglog import cloudlog @@ -54,18 +54,38 @@ FCW_IDXS = T_IDXS < 5.0 T_DIFFS = np.diff(T_IDXS, prepend=[0.]) MIN_ACCEL = -3.5 MAX_ACCEL = 2.0 -T_FOLLOW = 1.45 COMFORT_BRAKE = 2.5 STOP_DISTANCE = 6.0 +def get_jerk_factor(personality=log.LongitudinalPersonality.standard): + if personality==log.LongitudinalPersonality.relaxed: + return 1.0 + elif personality==log.LongitudinalPersonality.standard: + return 1.0 + elif personality==log.LongitudinalPersonality.aggressive: + return 0.5 + else: + raise NotImplementedError("Longitudinal personality not supported") + + +def get_T_FOLLOW(personality=log.LongitudinalPersonality.standard): + if personality==log.LongitudinalPersonality.relaxed: + return 1.75 + elif personality==log.LongitudinalPersonality.standard: + return 1.45 + elif personality==log.LongitudinalPersonality.aggressive: + return 1.25 + else: + raise NotImplementedError("Longitudinal personality not supported") + def get_stopped_equivalence_factor(v_lead): return (v_lead**2) / (2 * COMFORT_BRAKE) -def get_safe_obstacle_distance(v_ego, t_follow=T_FOLLOW): +def get_safe_obstacle_distance(v_ego, t_follow): return (v_ego**2) / (2 * COMFORT_BRAKE) + t_follow * v_ego + STOP_DISTANCE -def desired_follow_distance(v_ego, v_lead): - return get_safe_obstacle_distance(v_ego) - get_stopped_equivalence_factor(v_lead) +def desired_follow_distance(v_ego, v_lead, t_follow=get_T_FOLLOW()): + return get_safe_obstacle_distance(v_ego, t_follow) - get_stopped_equivalence_factor(v_lead) def gen_long_model(): @@ -161,7 +181,8 @@ def gen_long_ocp(): x0 = np.zeros(X_DIM) ocp.constraints.x0 = x0 - ocp.parameter_values = np.array([-1.2, 1.2, 0.0, 0.0, T_FOLLOW, LEAD_DANGER_FACTOR]) + ocp.parameter_values = np.array([-1.2, 1.2, 0.0, 0.0, get_T_FOLLOW(), LEAD_DANGER_FACTOR]) + # We put all constraint cost weights to 0 and only set them at runtime cost_weights = np.zeros(CONSTR_DIM) @@ -249,10 +270,11 @@ class LongitudinalMpc: for i in range(N): self.solver.cost_set(i, 'Zl', Zl) - def set_weights(self, prev_accel_constraint=True): + def set_weights(self, prev_accel_constraint=True, personality=log.LongitudinalPersonality.standard): + jerk_factor = get_jerk_factor(personality) if self.mode == 'acc': a_change_cost = A_CHANGE_COST if prev_accel_constraint else 0 - cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, J_EGO_COST] + cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, jerk_factor * a_change_cost, jerk_factor * J_EGO_COST] constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST] elif self.mode == 'blended': a_change_cost = 40.0 if prev_accel_constraint else 0 @@ -307,7 +329,8 @@ class LongitudinalMpc: self.cruise_min_a = min_a self.max_a = max_a - def update(self, radarstate, v_cruise, x, v, a, j): + def update(self, radarstate, v_cruise, x, v, a, j, personality=log.LongitudinalPersonality.standard): + t_follow = get_T_FOLLOW(personality) v_ego = self.x0[1] self.status = radarstate.leadOne.status or radarstate.leadTwo.status @@ -334,7 +357,7 @@ class LongitudinalMpc: v_cruise_clipped = np.clip(v_cruise * np.ones(N+1), v_lower, v_upper) - cruise_obstacle = np.cumsum(T_DIFFS * v_cruise_clipped) + get_safe_obstacle_distance(v_cruise_clipped) + cruise_obstacle = np.cumsum(T_DIFFS * v_cruise_clipped) + get_safe_obstacle_distance(v_cruise_clipped, get_T_FOLLOW()) x_obstacles = np.column_stack([lead_0_obstacle, lead_1_obstacle, cruise_obstacle]) self.source = SOURCES[np.argmin(x_obstacles[0])] @@ -368,7 +391,7 @@ class LongitudinalMpc: self.params[:,2] = np.min(x_obstacles, axis=1) self.params[:,3] = np.copy(self.prev_a) - self.params[:,4] = T_FOLLOW + self.params[:,4] = t_follow self.run() if (np.any(lead_xv_0[FCW_IDXS,0] - self.x_sol[FCW_IDXS,0] < CRASH_DISTANCE) and @@ -380,9 +403,9 @@ class LongitudinalMpc: # Check if it got within lead comfort range # TODO This should be done cleaner if self.mode == 'blended': - if any((lead_0_obstacle - get_safe_obstacle_distance(self.x_sol[:,1], T_FOLLOW))- self.x_sol[:,0] < 0.0): + if any((lead_0_obstacle - get_safe_obstacle_distance(self.x_sol[:,1], t_follow))- self.x_sol[:,0] < 0.0): self.source = 'lead0' - if any((lead_1_obstacle - get_safe_obstacle_distance(self.x_sol[:,1], T_FOLLOW))- self.x_sol[:,0] < 0.0) and \ + if any((lead_1_obstacle - get_safe_obstacle_distance(self.x_sol[:,1], t_follow))- self.x_sol[:,0] < 0.0) and \ (lead_1_obstacle[0] - lead_0_obstacle[0]): self.source = 'lead1' diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 3089499687..8ad10818fa 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -2,6 +2,8 @@ import math import numpy as np from common.numpy_fast import clip, interp +from common.params import Params +from cereal import log import cereal.messaging as messaging from common.conversions import Conversions as CV @@ -57,6 +59,17 @@ class LongitudinalPlanner: self.a_desired_trajectory = np.zeros(CONTROL_N) self.j_desired_trajectory = np.zeros(CONTROL_N) self.solverExecutionTime = 0.0 + self.params = Params() + self.param_read_counter = 0 + self.read_param() + self.personality = log.LongitudinalPersonality.standard + + def read_param(self): + param_value = self.params.get('LongitudinalPersonality') + if param_value is not None: + self.personality = int(param_value) + else: + self.personality = log.LongitudinalPersonality.standard @staticmethod def parse_model(model_msg, model_error): @@ -75,6 +88,9 @@ class LongitudinalPlanner: return x, v, a, j def update(self, sm): + if self.param_read_counter % 50 == 0: + self.read_param() + self.param_read_counter += 1 self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc' v_ego = sm['carState'].vEgo @@ -114,11 +130,11 @@ class LongitudinalPlanner: accel_limits_turns[0] = min(accel_limits_turns[0], self.a_desired + 0.05) accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05) - self.mpc.set_weights(prev_accel_constraint) + self.mpc.set_weights(prev_accel_constraint, personality=self.personality) self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1]) self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired) x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error) - self.mpc.update(sm['radarState'], v_cruise, x, v, a, j) + self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=self.personality) self.v_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.v_solution) self.a_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.a_solution) @@ -154,5 +170,6 @@ class LongitudinalPlanner: longitudinalPlan.fcw = self.fcw longitudinalPlan.solverExecutionTime = self.mpc.solve_time + longitudinalPlan.personality = self.personality pm.send('longitudinalPlan', plan_send) diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index c6b135935f..e9a1b2cb5b 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -7,6 +7,7 @@ import sys import traceback from typing import List, Tuple, Union +from cereal import log import cereal.messaging as messaging import selfdrive.sentry as sentry from common.basedir import BASEDIR @@ -44,6 +45,7 @@ def manager_init() -> None: ("HasAcceptedTerms", "0"), ("LanguageSetting", "main_en"), ("OpenpilotEnabledToggle", "1"), + ("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)), ] if not PC: default_params.append(("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8'))) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c794a0434a..2332054b69 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -dfe1e4a5fd7a464c91c0d2e70592b4b1470fda8d \ No newline at end of file +3e684aef4483b8d311d71bab3bb543d7bad26563 diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 0c8132343c..c68e94b323 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -89,6 +89,13 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { #endif }; + + std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; + std::vector longi_button_widths{300, 250, 225}; + ButtonParamControl* long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), + tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake."), + "../assets/offroad/icon_speed_limit.png", + longi_button_texts, longi_button_widths); for (auto &[param, title, desc, icon] : toggle_defs) { auto toggle = new ParamControl(param, title, desc, icon, this); @@ -97,6 +104,11 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { addItem(toggle); toggles[param.toStdString()] = toggle; + + // insert longitudinal personality after NDOG toggle + if (param == "DisengageOnAccelerator") { + addItem(long_personality_setting); + } } // Toggles with confirmation dialogs diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 770b9b92dd..a1b50c1bd4 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -196,6 +196,80 @@ private: bool confirm = false; bool store_confirm = false; }; + +class ButtonParamControl : public AbstractControl { + Q_OBJECT +public: + ButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + std::vector button_texts, std::vector button_widths) : AbstractControl(title, desc, icon) { + select_style = (R"( + padding: 0; + border-radius: 50px; + font-size: 45px; + font-weight: 500; + color: #E4E4E4; + background-color: #33Ab4C; + )"); + unselect_style = (R"( + padding: 0; + border-radius: 50px; + font-size: 45px; + font-weight: 350; + color: #E4E4E4; + background-color: #393939; + )"); + key = param.toStdString(); + for (int i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(); + button->setText(button_texts[i]); + hlayout->addWidget(button); + button->setFixedSize(button_widths[i], 100); + button->setStyleSheet(unselect_style); + buttons.push_back(button); + QObject::connect(button, &QPushButton::clicked, [=]() { + params.put(key, (QString::number(i)).toStdString()); + refresh(); + }); + } + refresh(); + } + + void read_param() { + auto value = params.get(key); + if (!value.empty()) { + param_value = std::stoi(value); + } + }; + void set_param(int new_value) { + QString values = QString::number(new_value); + params.put(key, values.toStdString()); + refresh(); + }; + + void refresh() { + read_param(); + for (int i = 0; i < buttons.size(); i++) { + buttons[i]->setStyleSheet(unselect_style); + if (param_value == i) { + buttons[i]->setStyleSheet(select_style); + } + } + }; + void showEvent(QShowEvent *event) override { + refresh(); + }; + +private: + std::string key; + std::vector buttons; + QString unselect_style; + QString select_style; + Params params; + int param_value = 0; +}; + + + class ListWidget : public QWidget { Q_OBJECT diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 7fda980e92..24b3d6f299 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1056,6 +1056,26 @@ This may take up to a minute. On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + + Aggressive + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + + Updater diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 10da629cf9..b6b039eedd 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1050,6 +1050,26 @@ This may take up to a minute. On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + + Aggressive + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + + Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index ad9a4e05d9..26e20a6b15 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1051,6 +1051,26 @@ This may take up to a minute. On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. 이 차량은 openpilot 롱컨트롤 대신 차량의 내장 ACC로 기본 설정됩니다. openpilot 롱컨트롤으로 전환하려면 이 기능을 활성화하세요. openpilot 롱컨트롤 알파를 활성화하는경우 실험적 모드 활성화를 권장합니다. + + Aggressive + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 5aa4245fda..794b0c025e 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1055,6 +1055,26 @@ Isso pode levar até um minuto. On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o alfa de controle longitudinal openpilot. + + Aggressive + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index e7382075fb..65ff1a4632 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1048,6 +1048,26 @@ This may take up to a minute. On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + + Aggressive + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index d112d86b08..de40c0f9f8 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1050,6 +1050,26 @@ This may take up to a minute. On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + + Aggressive + + + + Standard + + + + Relaxed + + + + Driving Personality + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + + Updater From 06e1f468aa85e7678ebdedb73ea01e15307b9834 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 5 Jun 2023 21:55:47 -0700 Subject: [PATCH 160/283] bump pylint --- poetry.lock | 16 ++++++++-------- pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/poetry.lock b/poetry.lock index e0e843ff0d..e2ef2fc29e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -190,7 +190,7 @@ tests = ["pytest"] name = "astroid" version = "2.15.5" description = "An abstract syntax tree for Python with inference support." -category = "main" +category = "dev" optional = false python-versions = ">=3.7.2" @@ -837,7 +837,7 @@ tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytes name = "dill" version = "0.3.5.1" description = "serialize all of python" -category = "main" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" @@ -1631,7 +1631,7 @@ six = "*" name = "isort" version = "5.10.1" description = "A Python utility / library to sort Python imports." -category = "main" +category = "dev" optional = false python-versions = ">=3.6.1,<4.0" @@ -1982,7 +1982,7 @@ tabulate = "*" name = "lazy-object-proxy" version = "1.7.1" description = "A fast and thorough lazy object proxy." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -3255,7 +3255,7 @@ python-versions = "*" name = "pylint" version = "2.17.4" description = "python code static checker" -category = "main" +category = "dev" optional = false python-versions = ">=3.7.2" @@ -4403,7 +4403,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" +category = "dev" optional = false python-versions = ">=3.7" @@ -4709,7 +4709,7 @@ python-versions = ">=3.7" name = "wrapt" version = "1.14.1" description = "Module for decorators, wrappers and monkey patching." -category = "main" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" @@ -4804,7 +4804,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "454ab16c681fa1754b26156f767ca0701eac357b66c146d71d61b39cbed42f5a" +content-hash = "8c0419671beb3e8c8f0add750929f5be32be6fa3f077d44614cbd598b4cadc00" [metadata.files] adal = [ diff --git a/pyproject.toml b/pyproject.toml index fa03248b9b..52dd7f2a02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,6 @@ psutil = "^5.9.1" pycapnp = "==1.1.0" pycryptodome = "^3.15.0" PyJWT = "^2.5.0" -pylint = "^2.15.4" pyopencl = "^2022.2.4" pyserial = "^3.5" python-dateutil = "^2.8.2" @@ -92,6 +91,7 @@ pprofile = "^2.1.0" pre-commit = "^2.19.0" pycurl = "^7.45.1" pygame = "^2.1.2" +pylint = "^2.17.4" pyprof2calltree = "^1.4.5" pytest = "^7.1.2" pytest-xdist = "^2.5.0" From f97b2bb9d76cd50bf13cd4481735c5fb03c14aab Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:11:21 +0900 Subject: [PATCH 161/283] kor translation update (#28420) --- selfdrive/ui/translations/main_ko.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 26e20a6b15..cf2ab3ad6a 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -857,23 +857,23 @@ This may take up to a minute. failed to check for update - + 업데이트 확인 실패 up to date, last checked %1 - + 최신 상태, 마지막으로 확인 %1 DOWNLOAD - + 다운로드 update available - + 업데이트 가능 never - + 업데이트 안함 From 7f41047178b5390581b9f18435939ba43a43a423 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 6 Jun 2023 16:18:17 +0800 Subject: [PATCH 162/283] ui: refactor ButtonParamControl (#28425) * refactor ButtonParamControl * add pressed style * connect to buttonToggled * typo --- selfdrive/ui/qt/offroad/settings.cc | 3 +- selfdrive/ui/qt/widgets/controls.h | 107 +++++++++++----------------- 2 files changed, 42 insertions(+), 68 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index c68e94b323..ac500a60f2 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -91,11 +91,10 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; - std::vector longi_button_widths{300, 250, 225}; ButtonParamControl* long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake."), "../assets/offroad/icon_speed_limit.png", - longi_button_texts, longi_button_widths); + longi_button_texts); for (auto &[param, title, desc, icon] : toggle_defs) { auto toggle = new ParamControl(param, title, desc, icon, this); diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index a1b50c1bd4..43054b892f 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -60,7 +61,7 @@ public: public slots: void showDescription() { description->setVisible(true); - }; + } signals: void showDescriptionEvent(); @@ -106,7 +107,7 @@ signals: void clicked(); public slots: - void setEnabled(bool enabled) { btn.setEnabled(enabled); }; + void setEnabled(bool enabled) { btn.setEnabled(enabled); } private: QPushButton btn; @@ -163,7 +164,7 @@ public: void setConfirmation(bool _confirm, bool _store_confirm) { confirm = _confirm; store_confirm = _store_confirm; - }; + } void setActiveIcon(const QString &icon) { active_icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); @@ -175,11 +176,11 @@ public: toggle.togglePosition(); setIcon(state); } - }; + } void showEvent(QShowEvent *event) override { refresh(); - }; + } private: void setIcon(bool state) { @@ -188,7 +189,7 @@ private: } else if (!icon_pixmap.isNull()) { icon_label->setPixmap(icon_pixmap); } - }; + } std::string key; Params params; @@ -196,81 +197,55 @@ private: bool confirm = false; bool store_confirm = false; }; - + class ButtonParamControl : public AbstractControl { Q_OBJECT public: ButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - std::vector button_texts, std::vector button_widths) : AbstractControl(title, desc, icon) { - select_style = (R"( - padding: 0; + const std::vector &button_texts) : AbstractControl(title, desc, icon) { + const QString style = R"( + QPushButton { border-radius: 50px; - font-size: 45px; + font-size: 40px; font-weight: 500; - color: #E4E4E4; - background-color: #33Ab4C; - )"); - unselect_style = (R"( - padding: 0; - border-radius: 50px; - font-size: 45px; - font-weight: 350; + height:100px; + padding: 0 25 0 25; color: #E4E4E4; background-color: #393939; - )"); - key = param.toStdString(); - for (int i = 0; i < button_texts.size(); i++) { - QPushButton *button = new QPushButton(); - button->setText(button_texts[i]); - hlayout->addWidget(button); - button->setFixedSize(button_widths[i], 100); - button->setStyleSheet(unselect_style); - buttons.push_back(button); - QObject::connect(button, &QPushButton::clicked, [=]() { - params.put(key, (QString::number(i)).toStdString()); - refresh(); - }); - } - refresh(); - } - - void read_param() { - auto value = params.get(key); - if (!value.empty()) { - param_value = std::stoi(value); - } - }; - void set_param(int new_value) { - QString values = QString::number(new_value); - params.put(key, values.toStdString()); - refresh(); - }; - - void refresh() { - read_param(); - for (int i = 0; i < buttons.size(); i++) { - buttons[i]->setStyleSheet(unselect_style); - if (param_value == i) { - buttons[i]->setStyleSheet(select_style); } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked { + background-color: #33Ab4C; + } + )"; + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + + QButtonGroup *button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (int i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(i == value); + button->setStyleSheet(style); + hlayout->addWidget(button); + button_group->addButton(button, i); } - }; - void showEvent(QShowEvent *event) override { - refresh(); - }; + + QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonToggled), [=](int id, bool checked) { + if (checked) { + params.put(key, std::to_string(id)); + } + }); + } private: std::string key; - std::vector buttons; - QString unselect_style; - QString select_style; Params params; - int param_value = 0; }; - - - class ListWidget : public QWidget { Q_OBJECT public: @@ -310,7 +285,7 @@ class LayoutWidget : public QWidget { public: LayoutWidget(QLayout *l, QWidget *parent = nullptr) : QWidget(parent) { setLayout(l); - }; + } }; class ClickableWidget : public QWidget { From 64377a88f94527f56ba8e9cd7c01c97100681455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Tue, 6 Jun 2023 19:31:13 +0200 Subject: [PATCH 163/283] process_replay: helpers (#28367) * process_replay helper * Refactor * refactor check_enabled uses * fix __init__ * noqa in __init__ imports * Move compare_logs outside of process_replay * Move save_logs to tools.lib.helpers * Remove save_log from compare_logs * fix lint issues --- selfdrive/debug/run_process_on_route.py | 2 +- selfdrive/test/process_replay/__init__.py | 1 + selfdrive/test/process_replay/compare_logs.py | 11 -------- selfdrive/test/process_replay/model_replay.py | 3 ++- .../test/process_replay/process_replay.py | 25 +++++++++++++++++-- selfdrive/test/process_replay/regen.py | 4 +-- .../test/process_replay/test_processes.py | 7 +++--- tools/lib/helpers.py | 12 +++++++++ tools/plotjuggler/juggle.py | 2 +- 9 files changed, 46 insertions(+), 21 deletions(-) diff --git a/selfdrive/debug/run_process_on_route.py b/selfdrive/debug/run_process_on_route.py index 63b0733bba..0ea76d260f 100755 --- a/selfdrive/debug/run_process_on_route.py +++ b/selfdrive/debug/run_process_on_route.py @@ -2,10 +2,10 @@ import argparse -from selfdrive.test.process_replay.compare_logs import save_log from selfdrive.test.process_replay.process_replay import CONFIGS, replay_process from tools.lib.logreader import MultiLogIterator from tools.lib.route import Route +from tools.lib.helpers import save_log if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run process on route and create new logs", diff --git a/selfdrive/test/process_replay/__init__.py b/selfdrive/test/process_replay/__init__.py index e69de29bb2..6667deaa2d 100644 --- a/selfdrive/test/process_replay/__init__.py +++ b/selfdrive/test/process_replay/__init__.py @@ -0,0 +1 @@ +from selfdrive.test.process_replay.process_replay import CONFIGS, get_process_config, replay_process, replay_process_with_name # noqa: F401 diff --git a/selfdrive/test/process_replay/compare_logs.py b/selfdrive/test/process_replay/compare_logs.py index 48752d2222..52898d8810 100755 --- a/selfdrive/test/process_replay/compare_logs.py +++ b/selfdrive/test/process_replay/compare_logs.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import bz2 import sys import math import capnp @@ -12,16 +11,6 @@ from tools.lib.logreader import LogReader EPSILON = sys.float_info.epsilon -def save_log(dest, log_msgs, compress=True): - dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) - - if compress: - dat = bz2.compress(dat) - - with open(dest, "wb") as f: - f.write(dat) - - def remove_ignored_fields(msg, ignore): msg = msg.as_builder() for key in ignore: diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index 9c1ec4e931..55d95a6a6a 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -14,11 +14,12 @@ from common.transformations.camera import tici_f_frame_size, tici_d_frame_size from system.hardware import PC from selfdrive.manager.process_config import managed_processes from selfdrive.test.openpilotci import BASE_URL, get_url -from selfdrive.test.process_replay.compare_logs import compare_logs, save_log +from selfdrive.test.process_replay.compare_logs import compare_logs from selfdrive.test.process_replay.test_processes import format_diff from system.version import get_commit from tools.lib.framereader import FrameReader from tools.lib.logreader import LogReader +from tools.lib.helpers import save_log TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30" SEGMENT = 6 diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index d6d5b25bde..7ee1d05962 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -333,7 +333,28 @@ def get_process_config(name): raise Exception(f"Cannot find process config with name: {name}") from ex -def replay_process(cfg, lr, fingerprint=None): +def replay_process_with_name(name, lr, *args, **kwargs): + cfg = get_process_config(name) + return replay_process(cfg, lr, *args, **kwargs) + + +def replay_process(cfg, lr, fingerprint=None, return_all_logs=False): + all_msgs = list(lr) + process_logs = _replay_single_process(cfg, all_msgs, fingerprint) + + if return_all_logs: + keys = set(cfg.subs) + modified_logs = [m for m in all_msgs if m.which() not in keys] + modified_logs.extend(process_logs) + modified_logs.sort(key=lambda m: m.logMonoTime) + log_msgs = modified_logs + else: + log_msgs = process_logs + + return log_msgs + + +def _replay_single_process(cfg, lr, fingerprint): with OpenpilotPrefix(): controlsState = None initialized = False @@ -484,7 +505,7 @@ def setup_env(CP=None, cfg=None, controlsState=None, lr=None, fingerprint=None, params.put_bool("ExperimentalLongitudinalEnabled", True) -def check_enabled(msgs): +def check_openpilot_enabled(msgs): cur_enabled_count = 0 max_enabled_count = 0 for msg in msgs: diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index 63eb37d29d..cc697bb9bf 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -19,7 +19,7 @@ from panda.python import Panda from selfdrive.car.toyota.values import EPS_SCALE from selfdrive.manager.process import ensure_running from selfdrive.manager.process_config import managed_processes -from selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, setup_env, check_enabled +from selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, setup_env, check_openpilot_enabled from selfdrive.test.update_ci_routes import upload_route from tools.lib.route import Route from tools.lib.framereader import FrameReader @@ -343,7 +343,7 @@ def regen_segment(lr, frs=None, daemons="all", outdir=FAKEDATA, disable_tqdm=Fal segment = params.get("CurrentRoute", encoding='utf-8') + "--0" seg_path = os.path.join(outdir, segment) # check to make sure openpilot is engaged in the route - if not check_enabled(LogReader(os.path.join(seg_path, "rlog"))): + if not check_openpilot_enabled(LogReader(os.path.join(seg_path, "rlog"))): raise Exception(f"Route did not engage for long enough: {segment}") return seg_path diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index deed1ec48f..02922c530d 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -9,11 +9,12 @@ from typing import Any, DefaultDict, Dict from selfdrive.car.car_helpers import interface_names from selfdrive.test.openpilotci import get_url, upload_file -from selfdrive.test.process_replay.compare_logs import compare_logs, save_log -from selfdrive.test.process_replay.process_replay import CONFIGS, PROC_REPLAY_DIR, FAKEDATA, check_enabled, replay_process +from selfdrive.test.process_replay.compare_logs import compare_logs +from selfdrive.test.process_replay.process_replay import CONFIGS, PROC_REPLAY_DIR, FAKEDATA, check_openpilot_enabled, replay_process from system.version import get_commit from tools.lib.filereader import FileReader from tools.lib.logreader import LogReader +from tools.lib.helpers import save_log source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY @@ -104,7 +105,7 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non # check to make sure openpilot is engaged in the route if cfg.proc_name == "controlsd": - if not check_enabled(log_msgs): + if not check_openpilot_enabled(log_msgs): return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs try: diff --git a/tools/lib/helpers.py b/tools/lib/helpers.py index efe704b9ec..067b64b6ac 100644 --- a/tools/lib/helpers.py +++ b/tools/lib/helpers.py @@ -1,3 +1,4 @@ +import bz2 import datetime TIME_FMT = "%Y-%m-%d--%H-%M-%S" @@ -13,8 +14,19 @@ class RE: EXPLORER_FILE = r'^(?P{})--(?P[a-z]+\.[a-z0-9]+)$'.format(SEGMENT_NAME) OP_SEGMENT_DIR = r'^(?P{})$'.format(SEGMENT_NAME) + def timestamp_to_datetime(t: str) -> datetime.datetime: """ Convert an openpilot route timestamp to a python datetime """ return datetime.datetime.strptime(t, TIME_FMT) + + +def save_log(dest, log_msgs, compress=True): + dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) + + if compress: + dat = bz2.compress(dat) + + with open(dest, "wb") as f: + f.write(dat) diff --git a/tools/plotjuggler/juggle.py b/tools/plotjuggler/juggle.py index 1e592da3b1..e147cf9ce8 100755 --- a/tools/plotjuggler/juggle.py +++ b/tools/plotjuggler/juggle.py @@ -11,10 +11,10 @@ import requests import argparse from common.basedir import BASEDIR -from selfdrive.test.process_replay.compare_logs import save_log from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader from tools.lib.route import Route, SegmentName +from tools.lib.helpers import save_log from urllib.parse import urlparse, parse_qs juggle_dir = os.path.dirname(os.path.realpath(__file__)) From d6cfbd0097a3f4ebc4cd49858c8f14aff84a01dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 6 Jun 2023 11:07:31 -0700 Subject: [PATCH 164/283] Driving personality setting: add description (#28422) * Driving personality setting: add description * Missing word --- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/translations/main_de.ts | 2 +- selfdrive/ui/translations/main_ja.ts | 2 +- selfdrive/ui/translations/main_ko.ts | 2 +- selfdrive/ui/translations/main_pt-BR.ts | 2 +- selfdrive/ui/translations/main_zh-CHS.ts | 2 +- selfdrive/ui/translations/main_zh-CHT.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index ac500a60f2..64bf44d2ce 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -92,7 +92,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; ButtonParamControl* long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), - tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake."), + tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars."), "../assets/offroad/icon_speed_limit.png", longi_button_texts); for (auto &[param, title, desc, icon] : toggle_defs) { diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 24b3d6f299..447f66f016 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1073,7 +1073,7 @@ This may take up to a minute. - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index b6b039eedd..6dc183d7f7 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1067,7 +1067,7 @@ This may take up to a minute. - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index cf2ab3ad6a..b751e9cf57 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1068,7 +1068,7 @@ This may take up to a minute. - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 794b0c025e..f2012bbe3a 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1072,7 +1072,7 @@ Isso pode levar até um minuto. - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 65ff1a4632..1d7cdd9f60 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1065,7 +1065,7 @@ This may take up to a minute. - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index de40c0f9f8..954991c705 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1067,7 +1067,7 @@ This may take up to a minute. - Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. From 5b3ddabf51ac1b9c0062757f8bd3e6ec53bdf586 Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Wed, 7 Jun 2023 02:56:55 +0800 Subject: [PATCH 165/283] VW MQB: Add FW for 2020 Skoda Kodiaq (#28428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VW MQB: Add FW for 2020 Skoda Kodiaq route name:cd4c3e2031f01e61|2023-06-04--19-53-13--0 --- selfdrive/car/volkswagen/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 1fc21fe5c0..88fd31bc03 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1154,6 +1154,7 @@ FW_VERSIONS = { CAR.SKODA_KODIAQ_MK1: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027DD\xf1\x893123', + b'\xf1\x8704E906027NB\xf1\x896517', b'\xf1\x8704L906026DE\xf1\x895418', b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026HT\xf1\x893617', From ae0768909bbcf51325a0a8ed0e623a0177c13c18 Mon Sep 17 00:00:00 2001 From: mitchellgoffpc Date: Tue, 6 Jun 2023 11:57:37 -0700 Subject: [PATCH 166/283] Lowered expected power draw for mapsd --- system/hardware/tici/tests/test_power_draw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 4683bba1f9..1487db0842 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -26,7 +26,7 @@ PROCS = [ Proc('modeld', 0.93, atol=0.2), Proc('dmonitoringmodeld', 0.4), Proc('encoderd', 0.23), - Proc('mapsd', 0.1), + Proc('mapsd', 0.05), Proc('navmodeld', 0.05), ] From 80623956ae835b655c7b9ae8e5cdacb33873384a Mon Sep 17 00:00:00 2001 From: John Paull Date: Tue, 6 Jun 2023 16:07:48 -0400 Subject: [PATCH 167/283] Hyundai: add missing FW for Santa Fe Hybrid 2022 (#28410) * values.py added additional Firmware * add fwdCamera too --------- Co-authored-by: Cameron Clough --- selfdrive/car/hyundai/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index b6e97a38a8..ba0fefca00 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -847,12 +847,14 @@ FW_VERSIONS = { ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102', + b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLEC0 4TSHC102', b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105', b'\xf1\x00TM MDPS C 1.00 1.02 56310-GA000 4TSHA100', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00TMH MFC AT EUR LHD 1.00 1.06 99211-S1500 220727', b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224', + b'\xf1\x00TMH MFC AT USA LHD 1.00 1.06 99211-S1500 220727' b'\xf1\x00TMA MFC AT USA LHD 1.00 1.03 99211-S2500 220414', ], (Ecu.transmission, 0x7e1, None): [ From 48b507c0b4508171c1439e05344e6cb0f8672d12 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 7 Jun 2023 04:10:12 +0800 Subject: [PATCH 168/283] handle conversion exception for LongitudinalPersonality (#28426) * handle type conversion exception * catch multiple exception --- selfdrive/controls/lib/longitudinal_planner.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 8ad10818fa..a9c3cc7804 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -65,10 +65,9 @@ class LongitudinalPlanner: self.personality = log.LongitudinalPersonality.standard def read_param(self): - param_value = self.params.get('LongitudinalPersonality') - if param_value is not None: - self.personality = int(param_value) - else: + try: + self.personality = int(self.params.get('LongitudinalPersonality')) + except (ValueError, TypeError): self.personality = log.LongitudinalPersonality.standard @staticmethod From ffa10d784adf91d21bacdb5d3b51a523ceeb1c8f Mon Sep 17 00:00:00 2001 From: Vincent Wright Date: Tue, 6 Jun 2023 18:57:41 -0400 Subject: [PATCH 169/283] More missing FW for the Ram 1500s (#28397) Co-authored-by: Cameron Clough --- selfdrive/car/chrysler/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index bd7c3acc36..0b3f7131e6 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -227,6 +227,7 @@ FW_VERSIONS = { b'68510283AG', b'68527346AE', b'68527375AD', + b'68527382AE', ], (Ecu.srs, 0x744, None): [ b'68428609AB', @@ -254,6 +255,7 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x753, None): [ b'04672892AB', b'04672932AB', + b'22DTRHD_AA', b'68320950AH', b'68320950AI', b'68320950AJ', @@ -265,6 +267,7 @@ FW_VERSIONS = { b'68475160AG', ], (Ecu.eps, 0x75A, None): [ + b'21590101AA', b'68273275AF', b'68273275AG', b'68312176AE', @@ -283,6 +286,7 @@ FW_VERSIONS = { b'05036065AE ', b'05036066AE ', b'05149846AA ', + b'05149848AA ', b'68378701AI ', b'68378758AM ', b'68448163AJ', From 0d51a64bf2c7a97e91a8d33fe05d13bd48c99a37 Mon Sep 17 00:00:00 2001 From: Vincent Wright Date: Tue, 6 Jun 2023 18:58:46 -0400 Subject: [PATCH 170/283] Added additional Firmware for Ram 1500 (#28392) Co-authored-by: Cameron Clough --- selfdrive/car/chrysler/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 0b3f7131e6..b1390bee0b 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -270,6 +270,7 @@ FW_VERSIONS = { b'21590101AA', b'68273275AF', b'68273275AG', + b'68273275AH', b'68312176AE', b'68312176AG', b'68440789AC', @@ -288,6 +289,7 @@ FW_VERSIONS = { b'05149846AA ', b'05149848AA ', b'68378701AI ', + b'68378748AL ', b'68378758AM ', b'68448163AJ', b'68448165AK', From d97d908a2a991e2be40914007f16d4734777dddc Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Wed, 7 Jun 2023 07:15:25 +0800 Subject: [PATCH 171/283] VW MQB: Add FW for 2023 Skoda Koidaq RS (#28332) 0bbe367c98fa1538|2023-05-29--13-59-08--0 Co-authored-by: Cameron Clough --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 88fd31bc03..947fbf9872 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1163,6 +1163,7 @@ FW_VERSIONS = { b'\xf1\x8705E906018DJ\xf1\x891903', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', + b'\xf1\x875NA906259E \xf1\x890003', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870D9300043 \xf1\x895202', @@ -1171,6 +1172,7 @@ FW_VERSIONS = { b'\xf1\x870DL300012N \xf1\x892110', b'\xf1\x870DL300013G \xf1\x892119', b'\xf1\x870GC300014N \xf1\x892801', + b'\xf1\x870GC300019H \xf1\x892806', b'\xf1\x870GC300046Q \xf1\x892802', ], (Ecu.srs, 0x715, None): [ @@ -1180,6 +1182,7 @@ FW_VERSIONS = { b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', b'\xf1\x873Q0959655DJ\xf1\x890731\xf1\x82\x0e1513001511001205232113052J00', + b'\xf1\x875QF959655AT\xf1\x890755\xf1\x82\x1311110011110011111100010200--1121240749', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6050405', @@ -1187,6 +1190,7 @@ FW_VERSIONS = { b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6070405', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G500', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G600', + b'\xf1\x875TA907145F \xf1\x891063\xf1\x82\x002LT61A2LOM', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572Q \xf1\x890342', From 37859626844c061748f61eb85eb6e84d7f27e99d Mon Sep 17 00:00:00 2001 From: tanotaru <126554277+tanotaru@users.noreply.github.com> Date: Tue, 6 Jun 2023 17:25:03 -0700 Subject: [PATCH 172/283] VW: 2018 Audi RS3 FW (#27467) Co-authored-by: Cameron Clough --- selfdrive/car/volkswagen/values.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 947fbf9872..1529f4742c 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -923,6 +923,7 @@ FW_VERSIONS = { b'\xf1\x8704E906027CJ\xf1\x897798', b'\xf1\x8704L997022N \xf1\x899459', b'\xf1\x875G0906259A \xf1\x890004', + b'\xf1\x875G0906259D \xf1\x890002', b'\xf1\x875G0906259L \xf1\x890002', b'\xf1\x875G0906259Q \xf1\x890002', b'\xf1\x878V0906259F \xf1\x890002', @@ -932,7 +933,7 @@ FW_VERSIONS = { b'\xf1\x878V0906264B \xf1\x890003', b'\xf1\x878V0907115B \xf1\x890007', b'\xf1\x878V0907404A \xf1\x890005', - b'\xf1\x875G0906259D \xf1\x890002', + b'\xf1\x878V0907404G \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870CW300044T \xf1\x895245', @@ -949,6 +950,7 @@ FW_VERSIONS = { b'\xf1\x870DD300046F \xf1\x891602', b'\xf1\x870DD300046G \xf1\x891601', b'\xf1\x870DL300012E \xf1\x892012', + b'\xf1\x870DL300012H \xf1\x892112', b'\xf1\x870GC300011 \xf1\x890403', b'\xf1\x870GC300013M \xf1\x892402', b'\xf1\x870GC300042J \xf1\x891402', @@ -961,9 +963,9 @@ FW_VERSIONS = { b'\xf1\x875Q0959655BJ\xf1\x890339\xf1\x82\x1311110011131100311111011731179321342100', b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\x13111112111111--241115141112221291163221', b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\023111112111111--171115141112221291163221', - b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023121111111211--261117141112231291163221', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13111112111111--241115141112221291163221', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13121111111111--341117141212231291163221', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13121111111211--261117141112231291163221', b'\xf1\x875Q0959655N \xf1\x890361\xf1\x82\0211212001112110004110411111421149114', b'\xf1\x875Q0959655N \xf1\x890361\xf1\x82\0211212001112111104110411111521159114', ], @@ -972,6 +974,7 @@ FW_VERSIONS = { b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566G0HA14A1', b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571G01A16A1', b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571G0HA16A1', + b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571G0JA13A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571G0JA14A1', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521G0G809A1', b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00303A0', From 464585c7587bc8f5d1854ae9e652d9933ac2bc2c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 6 Jun 2023 18:50:37 -0700 Subject: [PATCH 173/283] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 5847d7dbc0..bf2c007103 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 5847d7dbc05df3bc76243b6704b9d98544eb53df +Subproject commit bf2c0071036bae4e0c00c37ae43237fce6063e31 From 2dda9a0532dc9b848e53317bd1a6dab1ef83e5c3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 6 Jun 2023 20:28:56 -0700 Subject: [PATCH 174/283] match_fw_to_car: pass down log (#28434) pass in log from match_fw_to_car --- selfdrive/car/fw_versions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index cd3ef7977c..5c36ba5664 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -94,7 +94,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): return set() -def match_fw_to_car_exact(fw_versions_dict) -> Set[str]: +def match_fw_to_car_exact(fw_versions_dict, log=True) -> Set[str]: """Do an exact FW match. Returns all cars that match the given FW versions for a list of "essential" ECUs. If an ECU is not considered essential the FW version can be missing to get a fingerprint, but if it's present it @@ -129,7 +129,7 @@ def match_fw_to_car_exact(fw_versions_dict) -> Set[str]: return set(candidates.keys()) - set(invalid) -def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): +def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True, log=True): # Try exact matching first exact_matches = [] if allow_exact: @@ -142,7 +142,7 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): matches = set() for brand in VERSIONS.keys(): fw_versions_dict = build_fw_dict(fw_versions, filter_brand=brand) - matches |= match_func(fw_versions_dict) + matches |= match_func(fw_versions_dict, log=log) if len(matches): return exact_match, matches From 2b07ec4bde5c7994d97746737cd40e2f3fa1adcd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 6 Jun 2023 21:14:03 -0700 Subject: [PATCH 175/283] FPv2: brand filter helper (#28439) * pass in brand * needs to be flipped for exact matching since it's subtractive * new helper * makes more sense flipped * clean up * not that stuff here * not here --- selfdrive/car/fw_versions.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 5c36ba5664..e44523c89d 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -28,11 +28,16 @@ def chunks(l, n=128): yield l[i:i + n] +def is_brand(brand: str, filter_brand: Optional[str]) -> bool: + """Returns if brand matches filter_brand or no brand filter is specified""" + return filter_brand is None or brand == filter_brand + + def build_fw_dict(fw_versions: List[capnp.lib.capnp._DynamicStructBuilder], filter_brand: Optional[str] = None) -> Dict[Tuple[int, Optional[int]], Set[bytes]]: fw_versions_dict = defaultdict(set) for fw in fw_versions: - if (filter_brand is None or fw.brand == filter_brand) and not fw.logging: + if is_brand(fw.brand, filter_brand) and not fw.logging: sub_addr = fw.subAddress if fw.subAddress != 0 else None fw_versions_dict[(fw.address, sub_addr)].add(fw.fwVersion) return dict(fw_versions_dict) @@ -277,7 +282,7 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # Get versions and build capnp list to put into CarParams car_fw = [] - requests = [(brand, config, r) for brand, config, r in REQUESTS if query_brand is None or brand == query_brand] + requests = [(brand, config, r) for brand, config, r in REQUESTS if is_brand(brand, query_brand)] for addr in tqdm(addrs, disable=not progress): for addr_chunk in chunks(addr): for brand, config, r in requests: From 0acc30d2644729283cb3e3a6021c05e41f965ded Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 6 Jun 2023 21:38:10 -0700 Subject: [PATCH 176/283] FPv2: test minimum fuzzy fingerprint ECUs (#28433) * basic messy test * draft * clean up * clean up * clean up * clean up * never was fuzzy, but be explicit * switch it up --- selfdrive/car/fw_versions.py | 13 +++++----- selfdrive/car/tests/test_fw_fingerprint.py | 29 +++++++++++++++++++--- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index e44523c89d..c8af8779d9 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -15,6 +15,7 @@ from system.swaglog import cloudlog Ecu = car.CarParams.Ecu ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa] +FUZZY_EXCLUDE_ECUS = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug] FW_QUERY_CONFIGS = get_interface_attr('FW_QUERY_CONFIG', ignore_none=True) VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True) @@ -58,12 +59,6 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): that were matched uniquely to that specific car. If multiple ECUs uniquely match to different cars the match is rejected.""" - # These ECUs are known to be shared between models (EPS only between hybrid/ICE version) - # Getting this exactly right isn't crucial, but excluding camera and radar makes it almost - # impossible to get 3 matching versions, even if two models with shared parts are released at the same - # time and only one is in our database. - exclude_types = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug] - # Build lookup table from (addr, sub_addr, fw) to list of candidate cars all_fw_versions = defaultdict(list) for candidate, fw_by_addr in FW_VERSIONS.items(): @@ -71,7 +66,11 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): continue for addr, fws in fw_by_addr.items(): - if addr[0] in exclude_types: + # These ECUs are known to be shared between models (EPS only between hybrid/ICE version) + # Getting this exactly right isn't crucial, but excluding camera and radar makes it almost + # impossible to get 3 matching versions, even if two models with shared parts are released at the same + # time and only one is in our database. + if addr[0] in FUZZY_EXCLUDE_ECUS: continue for f in fws: all_fw_versions[(addr[1], addr[2], f)].append(candidate) diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index c069280d11..0d653741fe 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -10,7 +10,7 @@ from cereal import car from common.params import Params from selfdrive.car.car_helpers import interfaces from selfdrive.car.fingerprints import FW_VERSIONS -from selfdrive.car.fw_versions import FW_QUERY_CONFIGS, VERSIONS, match_fw_to_car, get_fw_versions +from selfdrive.car.fw_versions import FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, match_fw_to_car, get_fw_versions CarFw = car.CarParams.CarFw Ecu = car.CarParams.Ecu @@ -33,7 +33,7 @@ class TestFwFingerprint(unittest.TestCase): self.assertEqual(candidates[0], expected) @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) - def test_fw_fingerprint(self, brand, car_model, ecus): + def test_exact_match(self, brand, car_model, ecus): CP = car.CarParams.new_message() for _ in range(200): fw = [] @@ -44,9 +44,32 @@ class TestFwFingerprint(unittest.TestCase): fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) CP.carFw = fw - _, matches = match_fw_to_car(CP.carFw) + _, matches = match_fw_to_car(CP.carFw, allow_fuzzy=False) self.assertFingerprints(matches, car_model) + @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) + def test_fuzzy_match(self, brand, car_model, ecus): + # TODO: speed up fuzzy matching and test more + CP = car.CarParams.new_message() + for _ in range(5): + fw = [] + for ecu, fw_versions in ecus.items(): + if not len(fw_versions): + raise unittest.SkipTest("Car model has no FW versions") + ecu_name, addr, sub_addr = ecu + fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, + "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) + CP.carFw = fw + _, matches = match_fw_to_car(CP.carFw, allow_exact=False, log=False) + + # Assert no match if there are not enough valid ECUs + valid_ecus = [f['ecu'] for f in fw if f['ecu'] not in FUZZY_EXCLUDE_ECUS] + if len(valid_ecus) < 2: + self.assertEqual(len(matches), 0, valid_ecus) + # There won't always be a match due to shared FW, but if there is it should be correct + elif len(matches): + self.assertFingerprints(matches, car_model) + def test_no_duplicate_fw_versions(self): for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): From 7cb4adfebbb3c1a5901018f177bf87add7c0799b Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 7 Jun 2023 15:22:06 +1000 Subject: [PATCH 177/283] Cabana: Improve contrast when using dark themes (#28389) --- tools/cabana/binaryview.cc | 4 +++- tools/cabana/chart/chart.cc | 12 +++++++++++- tools/cabana/historylog.cc | 5 ++++- tools/cabana/signalview.cc | 5 ++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 50f66e5182..13cd76af3a 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -437,9 +437,11 @@ void BinaryItemDelegate::drawSignalCell(QPainter *painter, const QStyleOptionVie auto sig_color = getColor(sig); QColor color = sig_color; color.setAlpha(item->bg_color.alpha()); - painter->fillRect(rc, Qt::white); + // Mixing the signal colour with the Base background color to fade it + painter->fillRect(rc, QApplication::palette().color(QPalette::Base)); painter->fillRect(rc, color); + // Draw edges color = sig_color.darker(125); painter->setPen(QPen(color, 1)); if (draw_left) painter->drawLine(rc.topLeft(), rc.bottomLeft()); diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index a7f700f3c2..353bb3fab3 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -213,9 +213,19 @@ void ChartView::updateTitle() { for (QLegendMarker *marker : chart()->legend()->markers()) { QObject::connect(marker, &QLegendMarker::clicked, this, &ChartView::handleMarkerClicked, Qt::UniqueConnection); } + + // Use CSS to draw titles in the WindowText color + auto tmp = palette().color(QPalette::WindowText); + auto titleColorCss = tmp.name(QColor::HexArgb); + // Draw message details in similar color, but slightly fade it to the background + tmp.setAlpha(180); + auto msgColorCss = tmp.name(QColor::HexArgb); + for (auto &s : sigs) { auto decoration = s.series->isVisible() ? "none" : "line-through"; - s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name, msgName(s.msg_id), s.msg_id.toString())); + s.series->setName(QString("%3 %5 %6") + .arg(decoration, titleColorCss, s.sig->name, + msgColorCss, msgName(s.msg_id), s.msg_id.toString())); } split_chart_act->setEnabled(sigs.size() > 1); resetChartCache(); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 51abc3d50f..01c1f31645 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -63,7 +63,10 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i return "Data"; } } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { - return QBrush(getColor(sigs[section - 1])); + // Alpha-blend the signal color with the background to ensure contrast + QColor sigColor = getColor(sigs[section - 1]); + sigColor.setAlpha(128); + return QBrush(sigColor); } } return {}; diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 762b494f35..98cd08a690 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -459,7 +459,10 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), tree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); tree->header()->setStretchLastSection(true); tree->setMinimumHeight(300); - tree->setStyleSheet("QSpinBox{background-color:white;border:none;} QLineEdit{background-color:white;}"); + + // Use a distinctive background for the whole row containing a QSpinBox or QLineEdit + QString nodeBgColor = palette().color(QPalette::AlternateBase).name(QColor::HexArgb); + tree->setStyleSheet(QString("QSpinBox{background-color:%1;border:none;} QLineEdit{background-color:%1;}").arg(nodeBgColor)); QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); From 42eb7c527e2287eae20a96d867c1be4f78761bb7 Mon Sep 17 00:00:00 2001 From: eFini Date: Wed, 7 Jun 2023 14:58:48 +0800 Subject: [PATCH 178/283] Multilang: add missing Chinese (Traditional) translations (#28427) update chinese tranditional translations --- selfdrive/ui/translations/main_zh-CHT.ts | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 954991c705..c6e2d22f5a 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -856,23 +856,23 @@ This may take up to a minute. failed to check for update - + 檢查更新失敗 up to date, last checked %1 - + 已經是最新版本,上次檢查時間為 %1 DOWNLOAD - + 下載 update available - + 有可用的更新 never - + 從未更新 @@ -1040,35 +1040,35 @@ This may take up to a minute. openpilot Longitudinal Control (Alpha) - + openpilot 縱向控制 (Alpha 版) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - + 警告:此車輛的 Openpilot 縱向控制功能目前處於 Alpha 版本,使用此功能將會停用自動緊急制動(AEB)功能。 On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - + 在這輛車上,Openpilot 預設使用車輛內建的主動巡航控制(ACC),而非 Openpilot 的縱向控制。啟用此項功能可切換至 Openpilot 的縱向控制。當啟用 Openpilot 縱向控制 Alpha 版本時,建議同時啟用實驗性模式(Experimental mode)。 Aggressive - + 積極 Standard - + 標準 Relaxed - + 舒適 Driving Personality - + 駕駛風格 Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. - + 推薦使用標準模式。在積極模式中,openpilot 會更靠近前車並在加速和剎車方面更積極。在舒適模式中,openpilot 會與前車保持較遠的距離。 @@ -1110,23 +1110,23 @@ This may take up to a minute. WiFiPromptWidget Setup Wi-Fi - + 設置 Wi-Fi 連接 Connect to Wi-Fi to upload driving data and help improve openpilot - + 請連接至 Wi-Fi 以上傳駕駛數據,並協助改進 openpilot。 Open Settings - + 開啟設置 Uploading training data - + 正在上傳訓練數據 Your data is used to train driving models and help improve openpilot - + 您的數據將用於訓練駕駛模型並協助改進 openpilot From 9e8936be9863ea27c598685ee1b14775aa12cac4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 7 Jun 2023 00:03:01 -0700 Subject: [PATCH 179/283] fuzzy fingerprint: track number of matching ECUs, not FW versions (#28423) * first attempt trying to do it implicitly bad * back to lists and explicitly do this * continue checking if candidate switches on these, that's fine to check * debugging * clean up * more clean up * spot free * only need to create/update on change * fix test * draft * Revert "draft" This reverts commit dbe32f58b172eddc8f9699044c6a5956e753305d. * Revert "fix test" This reverts commit 1d34269fe2de35d314aa0658fa47a78a08d93e08. * fix test for real * first draft of test * this should be good * can replace existing fuzzy test * rm * matching * test non-empty fws * TEST DOWN HERE * no test * unique + fix skip message + comment + clean up * less confusing * ing * better --- selfdrive/car/fw_versions.py | 11 ++++---- selfdrive/car/tests/test_fw_fingerprint.py | 32 ++++++++++++---------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index c8af8779d9..ca75ed62e5 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -75,24 +75,25 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): for f in fws: all_fw_versions[(addr[1], addr[2], f)].append(candidate) - match_count = 0 + matched_ecus = set() candidate = None for addr, versions in fw_versions_dict.items(): + ecu_key = (addr[0], addr[1]) for version in versions: # All cars that have this FW response on the specified address - candidates = all_fw_versions[(addr[0], addr[1], version)] + candidates = all_fw_versions[(*ecu_key, version)] if len(candidates) == 1: - match_count += 1 + matched_ecus.add(ecu_key) if candidate is None: candidate = candidates[0] # We uniquely matched two different cars. No fuzzy match possible elif candidate != candidates[0]: return set() - if match_count >= 2: + if len(matched_ecus) >= 2: if log: - cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {match_count} matching ECUs") + cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {len(matched_ecus)} matching ECUs") return {candidate} else: return set() diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index 0d653741fe..ef8b64946c 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -48,24 +48,26 @@ class TestFwFingerprint(unittest.TestCase): self.assertFingerprints(matches, car_model) @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) - def test_fuzzy_match(self, brand, car_model, ecus): - # TODO: speed up fuzzy matching and test more - CP = car.CarParams.new_message() - for _ in range(5): - fw = [] - for ecu, fw_versions in ecus.items(): - if not len(fw_versions): - raise unittest.SkipTest("Car model has no FW versions") - ecu_name, addr, sub_addr = ecu - fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, + def test_fuzzy_match_ecu_count(self, brand, car_model, ecus): + # Asserts that fuzzy matching does not count matching FW, but ECU address keys + valid_ecus = [e for e in ecus if e[0] not in FUZZY_EXCLUDE_ECUS and len(ecus[e])] + if not len(valid_ecus): + raise unittest.SkipTest("Car model has no compatible ECUs for fuzzy matching") + + fw = [] + for ecu in valid_ecus: + ecu_name, addr, sub_addr = ecu + for _ in range(5): + # Add multiple FW versions to simulate ECU returning to multiple queries in a brand + fw.append({"ecu": ecu_name, "fwVersion": random.choice(ecus[ecu]), 'brand': brand, "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) - CP.carFw = fw + CP = car.CarParams.new_message(carFw=fw) _, matches = match_fw_to_car(CP.carFw, allow_exact=False, log=False) - # Assert no match if there are not enough valid ECUs - valid_ecus = [f['ecu'] for f in fw if f['ecu'] not in FUZZY_EXCLUDE_ECUS] - if len(valid_ecus) < 2: - self.assertEqual(len(matches), 0, valid_ecus) + # Assert no match if there are not enough unique ECUs + unique_ecus = {(f['address'], f['subAddress']) for f in fw} + if len(unique_ecus) < 2: + self.assertEqual(len(matches), 0) # There won't always be a match due to shared FW, but if there is it should be correct elif len(matches): self.assertFingerprints(matches, car_model) From f976fce7d0142088244ae4af8a1116691b621843 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 7 Jun 2023 00:05:41 -0700 Subject: [PATCH 180/283] FPv2: assert non-empty FW lists (#28441) * test empty fw lists * fix * generic test name * can rmeove this check now * and here! * can remove that * add to print --- selfdrive/car/ford/values.py | 2 -- selfdrive/car/tests/test_fw_fingerprint.py | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index edc40f629c..9b7b6ad83e 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -213,8 +213,6 @@ FW_VERSIONS = { (Ecu.engine, 0x7E0, None): [ b'JX6A-14C204-BPL\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], - (Ecu.shiftByWire, 0x732, None): [ - ], }, CAR.MAVERICK_MK1: { (Ecu.eps, 0x730, None): [ diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index ef8b64946c..b90120a1e2 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -38,8 +38,6 @@ class TestFwFingerprint(unittest.TestCase): for _ in range(200): fw = [] for ecu, fw_versions in ecus.items(): - if not len(fw_versions): - raise unittest.SkipTest("Car model has no FW versions") ecu_name, addr, sub_addr = ecu fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) @@ -50,7 +48,7 @@ class TestFwFingerprint(unittest.TestCase): @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) def test_fuzzy_match_ecu_count(self, brand, car_model, ecus): # Asserts that fuzzy matching does not count matching FW, but ECU address keys - valid_ecus = [e for e in ecus if e[0] not in FUZZY_EXCLUDE_ECUS and len(ecus[e])] + valid_ecus = [e for e in ecus if e[0] not in FUZZY_EXCLUDE_ECUS] if not len(valid_ecus): raise unittest.SkipTest("Car model has no compatible ECUs for fuzzy matching") @@ -67,18 +65,19 @@ class TestFwFingerprint(unittest.TestCase): # Assert no match if there are not enough unique ECUs unique_ecus = {(f['address'], f['subAddress']) for f in fw} if len(unique_ecus) < 2: - self.assertEqual(len(matches), 0) + self.assertEqual(len(matches), 0, car_model) # There won't always be a match due to shared FW, but if there is it should be correct elif len(matches): self.assertFingerprints(matches, car_model) - def test_no_duplicate_fw_versions(self): + def test_fw_version_lists(self): for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): for ecu, ecu_fw in ecus.items(): with self.subTest(ecu): duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1} - self.assertFalse(len(duplicates), f"{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}") + self.assertFalse(len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}') + self.assertGreater(len(ecu_fw), 0, f'{car_model}: No FW versions: Ecu.{ECU_NAME[ecu[0]]}') def test_all_addrs_map_to_one_ecu(self): for brand, cars in VERSIONS.items(): From a92cd659cef7c517b40e7fd1455a12bacb3184b9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 7 Jun 2023 01:11:41 -0700 Subject: [PATCH 181/283] ButtonParamControl: minimum button width (#28442) * min width * param --- selfdrive/ui/qt/widgets/controls.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 43054b892f..654c6e2c1c 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -202,7 +202,7 @@ class ButtonParamControl : public AbstractControl { Q_OBJECT public: ButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts) : AbstractControl(title, desc, icon) { + const std::vector &button_texts, const int minimum_button_width = 225) : AbstractControl(title, desc, icon) { const QString style = R"( QPushButton { border-radius: 50px; @@ -230,6 +230,7 @@ public: button->setCheckable(true); button->setChecked(i == value); button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); hlayout->addWidget(button); button_group->addButton(button, i); } From 80430435bb0e2f450cfacda19a1cd692cba02334 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Wed, 7 Jun 2023 16:09:25 -0300 Subject: [PATCH 182/283] Multilang: update pt-BR translations (#28431) * update pt-BR translations * fix some cutoff texts * update pt-BR translations * Include the new relaxed explanation --- selfdrive/ui/translations/main_pt-BR.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index f2012bbe3a..4b2a3d88c8 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -861,23 +861,23 @@ Isso pode levar até um minuto. failed to check for update - + falha ao verificar por atualizações up to date, last checked %1 - + atualizado, última verificação %1 DOWNLOAD - + BAIXAR update available - + atualização disponível never - + nunca @@ -1057,23 +1057,23 @@ Isso pode levar até um minuto. Aggressive - + Disputador Standard - + Neutro Relaxed - + Calmo Driving Personality - + Personalidade de Condução Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. - + Neutro é o recomendado. No modo disputador o openpilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o openpilot se manterá mais longe do carro da frente. From 729d3ddcb55a294f244304e0d455424ce85c84a8 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Wed, 7 Jun 2023 14:06:11 -0700 Subject: [PATCH 183/283] Check msg count in test_power_draw (#28444) * Check msg count in test_power_draw. * Use drain_sock * Bug fix * Combine into a single table * Check camera state msgs and no default value for Proc.msgs * Update system/hardware/tici/tests/test_power_draw.py Co-authored-by: Adeeb Shihadeh --------- Co-authored-by: Adeeb Shihadeh --- system/hardware/tici/tests/test_power_draw.py | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 1487db0842..7ec31670b1 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -5,29 +5,33 @@ import math import threading from dataclasses import dataclass from tabulate import tabulate +from typing import List import cereal.messaging as messaging +from cereal.services import service_list from system.hardware import HARDWARE, TICI from system.hardware.tici.power_monitor import get_power from selfdrive.manager.process_config import managed_processes from selfdrive.manager.manager import manager_cleanup +SAMPLE_TIME = 8 # seconds to sample power @dataclass class Proc: name: str power: float + msgs: List[str] rtol: float = 0.05 atol: float = 0.12 warmup: float = 6. PROCS = [ - Proc('camerad', 2.1), - Proc('modeld', 0.93, atol=0.2), - Proc('dmonitoringmodeld', 0.4), - Proc('encoderd', 0.23), - Proc('mapsd', 0.05), - Proc('navmodeld', 0.05), + Proc('camerad', 2.1, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']), + Proc('modeld', 0.93, atol=0.2, msgs=['modelV2']), + Proc('dmonitoringmodeld', 0.4, msgs=['driverStateV2']), + Proc('encoderd', 0.23, msgs=[]), + Proc('mapsd', 0.05, msgs=['mapRenderState']), + Proc('navmodeld', 0.05, msgs=['navModel']), ] def send_llk_msg(done): @@ -39,6 +43,7 @@ def send_llk_msg(done): # Send liveLocationKalman at 20hz while not done.is_set(): + msg.clear_write_flag() pm.send('liveLocationKalman', msg) time.sleep(1/20) @@ -68,25 +73,33 @@ class TestPowerDraw(unittest.TestCase): prev = baseline used = {} + msg_counts = {} for proc in PROCS: + socks = {msg: messaging.sub_sock(msg) for msg in proc.msgs} managed_processes[proc.name].start() time.sleep(proc.warmup) + for sock in socks.values(): + messaging.drain_sock_raw(sock) - now = get_power(8) + now = get_power(SAMPLE_TIME) used[proc.name] = now - prev prev = now + for msg,sock in socks.items(): + msg_counts[msg] = len(messaging.drain_sock_raw(sock)) done.set() manager_cleanup() - tab = [] - tab.append(['process', 'expected (W)', 'measured (W)']) + tab = [['process', 'expected (W)', 'measured (W)', '# msgs expected', '# msgs received']] for proc in PROCS: cur = used[proc.name] expected = proc.power - tab.append([proc.name, round(expected, 2), round(cur, 2)]) + msgs_received = sum(msg_counts[msg] for msg in proc.msgs) + msgs_expected = int(sum(SAMPLE_TIME * service_list[msg].frequency for msg in proc.msgs)) + tab.append([proc.name, round(expected, 2), round(cur, 2), msgs_expected, msgs_received]) with self.subTest(proc=proc.name): self.assertTrue(math.isclose(cur, expected, rel_tol=proc.rtol, abs_tol=proc.atol)) + self.assertTrue(math.isclose(msgs_expected, msgs_received, rel_tol=.02, abs_tol=2)) print(tabulate(tab)) print(f"Baseline {baseline:.2f}W\n") From 02841cede3daed3ac2a8668c9596e0663c889e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 8 Jun 2023 01:22:48 +0200 Subject: [PATCH 184/283] process_replay: remove get_car_params_callback when it's not needed (#28451) * Add assertion for can msgs in get_car_params_callback * Remove get_car_params_callback from processes that don't need it --- selfdrive/test/process_replay/process_replay.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 7ee1d05962..16c0c0f6a3 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -147,6 +147,8 @@ def get_car_params_callback(rc, pm, msgs, fingerprint): sendcan = DummySocket() canmsgs = [msg for msg in msgs if msg.which() == "can"] + assert len(canmsgs) != 0, "CAN messages are required for carParams initialization" + for m in canmsgs[:300]: can.send(m.as_builder().to_bytes()) _, CP = get_car(can, sendcan, Params().get_bool("ExperimentalLongitudinalEnabled")) @@ -256,7 +258,7 @@ CONFIGS = [ subs=["liveCalibration"], ignore=["logMonoTime", "valid"], config_callback=None, - init_callback=get_car_params_callback, + init_callback=None, should_recv_callback=calibration_rcv_callback, ), ProcessConfig( @@ -265,7 +267,7 @@ CONFIGS = [ subs=["driverMonitoringState"], ignore=["logMonoTime", "valid"], config_callback=None, - init_callback=get_car_params_callback, + init_callback=None, should_recv_callback=FrequencyBasedRcvCallback("driverStateV2"), tolerance=NUMPY_TOLERANCE, ), @@ -278,7 +280,7 @@ CONFIGS = [ subs=["liveLocationKalman"], ignore=["logMonoTime", "valid"], config_callback=locationd_config_pubsub_callback, - init_callback=get_car_params_callback, + init_callback=None, should_recv_callback=None, tolerance=NUMPY_TOLERANCE, ), @@ -307,7 +309,7 @@ CONFIGS = [ subs=["gnssMeasurements"], ignore=["logMonoTime"], config_callback=laikad_config_pubsub_callback, - init_callback=get_car_params_callback, + init_callback=None, should_recv_callback=None, tolerance=NUMPY_TOLERANCE, timeout=60*10, # first messages are blocked on internet assistance From d932aae327fbaaae0c628ecbb571eef85f88f2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 8 Jun 2023 01:23:02 +0200 Subject: [PATCH 185/283] process_replay: improved support for drained pubs (#28452) Stop triggering empty update if there're no drained messages in the queue --- selfdrive/test/process_replay/process_replay.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 16c0c0f6a3..5871488fe6 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -77,9 +77,9 @@ class ReplayContext: def wait_for_recv_called(self): messaging.wait_for_one_event(self.all_recv_called_events) - def wait_for_next_recv(self, end_of_cycle): + def wait_for_next_recv(self, trigger_empty_recv): index = messaging.wait_for_one_event(self.all_recv_called_events) - if self.drained_pub is not None and end_of_cycle: + if self.drained_pub is not None and trigger_empty_recv: self.all_recv_called_events[index].clear() self.all_recv_ready_events[index].set() self.all_recv_called_events[index].wait() @@ -419,12 +419,17 @@ def _replay_single_process(cfg, lr, fingerprint): for s in sockets.values(): messaging.recv_one_or_none(s) + # empty recv on drained pub indicates the end of messages, only do that if there're any + trigger_empty_recv = False + if cfg.drained_pub: + trigger_empty_recv = next((True for m in msg_queue if m.which() == cfg.drained_pub), False) + for m in msg_queue: pm.send(m.which(), m.as_builder()) msg_queue = [] rc.unlock_sockets() - rc.wait_for_next_recv(True) + rc.wait_for_next_recv(trigger_empty_recv) for s in resp_sockets: ms = messaging.drain_sock(sockets[s]) From a2e75fdea6465bf41edd46875fb7dd241155aca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 8 Jun 2023 01:23:40 +0200 Subject: [PATCH 186/283] process_replay: progress bar support (#28447) * Add support for tqdm progress bar * Fix argument name --- selfdrive/test/process_replay/process_replay.py | 9 +++++---- selfdrive/test/process_replay/test_processes.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 5871488fe6..9261aee838 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -6,6 +6,7 @@ import platform from collections import OrderedDict from dataclasses import dataclass, field from typing import Dict, List, Optional, Callable +from tqdm import tqdm import cereal.messaging as messaging from cereal import car @@ -340,9 +341,9 @@ def replay_process_with_name(name, lr, *args, **kwargs): return replay_process(cfg, lr, *args, **kwargs) -def replay_process(cfg, lr, fingerprint=None, return_all_logs=False): +def replay_process(cfg, lr, fingerprint=None, return_all_logs=False, disable_progress=False): all_msgs = list(lr) - process_logs = _replay_single_process(cfg, all_msgs, fingerprint) + process_logs = _replay_single_process(cfg, all_msgs, fingerprint, disable_progress) if return_all_logs: keys = set(cfg.subs) @@ -356,7 +357,7 @@ def replay_process(cfg, lr, fingerprint=None, return_all_logs=False): return log_msgs -def _replay_single_process(cfg, lr, fingerprint): +def _replay_single_process(cfg, lr, fingerprint, disable_progress): with OpenpilotPrefix(): controlsState = None initialized = False @@ -404,7 +405,7 @@ def _replay_single_process(cfg, lr, fingerprint): # Do the replay cnt = 0 - for msg in pub_msgs: + for msg in tqdm(pub_msgs, disable=disable_progress): with Timeout(cfg.timeout, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): resp_sockets, end_of_cycle = cfg.subs, True if cfg.should_recv_callback is not None: diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 02922c530d..6962e51cb5 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -99,7 +99,7 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non ref_log_msgs = list(LogReader(ref_log_path)) try: - log_msgs = replay_process(cfg, lr) + log_msgs = replay_process(cfg, lr, disable_progress=True) except Exception as e: raise Exception("failed on segment: " + segment) from e From 3e3c8b7ddf6b3d6f71182aea75db2fa642946175 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 7 Jun 2023 16:24:54 -0700 Subject: [PATCH 187/283] soundd: only run onroad (#28449) --- selfdrive/manager/process_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 57c42aaaaa..ee8d079bdf 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -47,7 +47,7 @@ procs = [ NativeProcess("navmodeld", "selfdrive/modeld", ["./navmodeld"], enabled=False), NativeProcess("sensord", "system/sensord", ["./sensord"], enabled=not PC), NativeProcess("ui", "selfdrive/ui", ["./ui"], offroad=True, watchdog_max_dt=(5 if not PC else None)), - NativeProcess("soundd", "selfdrive/ui/soundd", ["./soundd"], offroad=True), + NativeProcess("soundd", "selfdrive/ui/soundd", ["./soundd"]), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"]), NativeProcess("boardd", "selfdrive/boardd", ["./boardd"], enabled=False), PythonProcess("calibrationd", "selfdrive.locationd.calibrationd"), From 28980cf4c60ca2fb79a7e0bb42be17a9abacf728 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 7 Jun 2023 20:25:15 -0700 Subject: [PATCH 188/283] pandad: test release -> devel bootstub reflash (#28330) * test * release bootstubs * rm that * fixup * skip earlier --------- Co-authored-by: Comma Device --- panda | 2 +- selfdrive/boardd/tests/bootstub.panda.bin | Bin 0 -> 15732 bytes selfdrive/boardd/tests/bootstub.panda_h7.bin | Bin 0 -> 16860 bytes selfdrive/boardd/tests/test_pandad.py | 31 ++++++++++++++++--- 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100755 selfdrive/boardd/tests/bootstub.panda.bin create mode 100755 selfdrive/boardd/tests/bootstub.panda_h7.bin diff --git a/panda b/panda index bf2c007103..1a9a94c519 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit bf2c0071036bae4e0c00c37ae43237fce6063e31 +Subproject commit 1a9a94c519cb74e9e0f57bea4d316a54c27ea8aa diff --git a/selfdrive/boardd/tests/bootstub.panda.bin b/selfdrive/boardd/tests/bootstub.panda.bin new file mode 100755 index 0000000000000000000000000000000000000000..43db5370613b9a3966790c2a14f5e121907a5ade GIT binary patch literal 15732 zcmch834Bx4w)Z~gBu(0;Z8`v*fD8<61K0tiOcIiEnl^<36@}uEwp3D3C=`%Ug5b3{ zp`!Ofc`Ax}RU9Z9wBgo*^vMC z0#F5523Q4H57-QN5b!8q2VfWAIlxPReSmtvyMRVOGvE`zmw;n{Q-Cu7AK)UO9nb}k z0LlSG9SMj93<3-W7y;>k8vx?~lK|5I`G6UK62N@Goq$Tf62Nl6y?~8?Er4wRFW?)% zcEHns-GJu-e+9e&cpK0FXaf8l@EPDcz*)d~z-2)H(sm-=17HRcwF(dghzHQ}B!oi& z!$WDBXSyz)h4^^D6o3^_04N5`1!yM7G;~e{ks*^Ox>=&y49htLwWUX?%6LyvcG1!)|=8A zM)F%#tfozxJdnTTf{L3ajv{P}j+ca|Bxc;ZKHA%N=gGcg{)DK=Om5{O6ua$hB=Se} zT_P$>iXA_qH)i+1)(AGgmE#JK$3DsJ_?XUc+F+h@>P&BRl8p-9?0?JU$}sz1cl~L1 zg30WE#nmFJ87_@$+26(tHT(Ctmh$!?+5D!gc#+w}ip=_lEnVKIHkT%cC;CPF4soMy zhq&Q%oWgP;x_pPY=`=!ihj`y0X=e?9-u~*Sn%T46XuhQA%OT~V* z+KhQPO~K}zOxdSwOJI`M3=o+}i}_ItCo(3%n_5VW1CbLaGAXr|8@x=8 z%XHPt=%TP5*xk)sTEg$f*ctq7e3ye}jK(34<~-u>`iS1`!$=5LMx%&kMMaT9!-`yy zB7zm!B4*NiKBDvbPLG4k0B?EsFXl;`mLqMmlnFd`Dka>r&yt5w^qTbvydrz};)*3p z%r7~IIhU9#%*7YlYnTZ~E84s*=M!FOIY01M)zXFhA$}Fl^IraTQLl?nXIr}}cIO$t zec*zE%Rw8i&28m6hvaZqcEvMUv(gvj6<;{W?&W9lQQnd~u5v}5x;31u%$uBNt-QbT z@0E(XX3JbXir>W#;J@~bOpo~XPZyLNrSu&rz0Gl*-&plI$9)y^k$M3!RaK)C& zy~t~>RNA?_h=CXnpJ$EL`HmYQAB@u%`OkdSEV^58Qo{UGxr2%Mtv}w28jCdiqlqtB zh*xYpl9(VeOQKg!HF0eW%X%eYhC~eU{AF;tP>hz96AFG1&+TUn3cBhlN%%&(NTy%7 zWfjh8#8tA_>1iV|oPVlX-Sl2tZp_VI9dC+e3{h<==220VDG5!INppSrUC9)2efllw zT56UgydvfNuJs-%=Xb4lN;$u4{rGRK9g?t3QnV#-X=6_=0iTYFjpjr}YOID6xzyMQ zPGnORIeRUBZ!XWtyTush^OWb8O1pie>C;@IUWs+fbU(9S$vgQ3lvpJvAHk<1b{k@n zuu4iWFla;kTSXl|cz&W(R*-IGxILw6 zK|L|53zB&z=PuJj4hE;H%d50EpC<;^P7KLq)%mEeC1x=sf05Qz=l5Z?y|n87{j6WX zGEXvfb5zrslm!vBOm>7zVJIzQ_seZ3Gv-&&ma`{Tx%@0S+-@dvK4Hx)@(#DV`qFBe zPFcs*mmj3%RNm8m{^S4s`>9-Ic5ksTM`<6-ZYJldkIm!w9pIhne5`RwmygTvyOk%V zT_DOgRFS-b&u$6hnF-l>f3}SE`Ws6`?cI5R5>bOtgHVl7jZlG5akq9#%xFcMR>9#! zpF18OzRVw^Q1oyH(#j2FTDe$*pW`$`pH>Tr?^{&fWquB&N<&iK7rp`f8Q;yK;!9ps zeCGGXipggSckTQ(~-3-NtYgD_Q6L7Z`4mxx~zYSI@K%Cb ziOec>&Nfdl&ol{D$=-fy&(M5n~-))NEKe0-}+fBLd*n+qsGCb1xcKwQj z6&nhjOisnhNN0+(#Qcym-omvMcepUy4N}DhX40tx6)WQ#`ub z#YSgknJI5~iqXMjzp%1wWo)RQ0W%VeTo0MM4SmNB7Z@e$3{upFhorOJ-RwW5z zq!kCtHRUx6Er$^L`(trqXlhdACeC>>6FQJIqE5(dhFrsqviJj6MxYq#kU- z{-IyBTU*aUk5M<$QXj_1$hGhNUG3^npISGxKJ**Y@(Sj!HGk=2`Dncw{oW}Vc$%ZM zQR?%W7z1acy_Vpvx#H6{(!Q8nE^WZ^AI=d!tB8nE^LP2w*H&bzJZ`1DB6K#KEkfUZ z-P#ZZYp!-{W-57RSk4;O6y@bcB{V^L8B6LJJzX!lTK|-kqb_@^8<|mlUpn6o`7A~e z-Sul#dfi$n|FBj}n##@cEan&0va=!5#yqLP46X#3IyGj+?Y|vbu_Ro0A2+3qmi!zf zhBlv^-}9f%@9HnV&F{8$?$&+o!7zwyG;a-YBP0?R984%+rU_8#lW@_pR8nWn*i zl5n-@k9+jgb#u7qe`yZ2*Ucg44|C|_XBMkJB1k!w1HaM}H8eCQIu9+C1NPfCFk^39 z$qakJqQE&OZ3>dgheP|hE6^|d=o!|Ut9}Ca20Fl_vK#@2M?nt6&8*q*v6{(IXV$D_ z{3_;VQJ1-m#EjeyiK4nrq9|Hj1nbtz8q#G=qcKn;ORXA6R>*Yo#Ggc&ZXa)r0dLt_ zNZLJK=5dXFJkHHa0j6%8jm}^XVmUSrvE7Je+7yWWIS`K1IvVxfmck8TdJ|%AN*T6D zgBqo;N@miTz+#P3Nbpu;y@(&qqOdp)QC}9i=;3c9it?aOB`Zh`gi+Jgv?`f zKh*9>P@r|j1k{Mpais@nJ4&AqNg6s5NtjCI5_nVXR@ZZBMsJ)wWli0X63hN>m%sSJ zEN#iOot6PD(V?-0VMKjnV*=r!aSV~^Ddn+9!k{L~C5=8c^f)RD{`<6#_x961+S^at zFY{bK?ep(b+S~sJv|qbM`=x8NKlmN(Lo)5M-_fS`TmSu3KxT=WssGsxx4);Kzf-`0 zxj5Bbp1wPdtzwMyPRqK$a+)SaN43HlncoNU#DG)Kn+;8v>dT)>eR|>Bovu4$P8rZ{ zpLvH>M=f_Yok!adWCZjMDU*lR*hsZTpHJ&n6-5{#A&a3)2P3ezGA zmN9B~luapfPGL}Kh~>kRTPg@``dv@b^f<8&VptGK8akWRS)p z5DN>cF%CLbCaB}p2D)anMt39S722xvY6Ctp`b;TtP!N6e>cYx-XRJ^tYp-%aFWK4&&s|PgeAWuJTa2Kb+H-27Owe z(w9TfmqXB(Lv1KDhe8+Hm7>0u{cYSd&CoRMe?=&y^P*`>D9kPm&5N;Vu_hmT%$OsA z2FV>_fXN}MI|n=*aJNSREO?Z_9iA}YHjfJUl1B~P>Inxv=ZOIR*%Jx;qelb$gC`33 zTTe9b2~Q00zdTytqn=pc7Ec`T7oK?FPdy31A9)4Ugf$KcOfdAqd4*Zm71n?7{ zk-(36(tscKqyyJ_GJqfOn1Jv1i~`=|84bL_GX{9A=LX=_o=o5xPZn^sCmZ-4PY&>6 z&sg9^o^iknJvRcEdBy|Z;mHMF;F$nC&odEtu4fYP9M5FnV$W3IB99rkz%vb)_gH|f z9xJfflLtJ-GaY!MhX)?-$p;?mu>og!3V_FWrU08fHvy-43W0}v?7#+35%5sY4B%AH zEZ`*1Y~X>OIl%Fr5@4<8X5c8#T;K@Lt-vbJJYa=qJ}~3C4LI0vCvZ=L16XV*1MX}n z2for!0erb(A@HvamB8m4wC>`o(h3Ev$29m27IaO&dgls84}TxQJ<~PSz{oPAxQiH# zW!gq+OWbLwD~CPjD24S*)AJU?igiQw1QYBDGX~ghG;9%bhb0s?i<5^j!^jAip;@#I zYZlE5o5j35+MD^xyR$LpE3LRCTHYRE)b_OoFDC9qx4Bo5)O>bE`G)I_azD{SxLlsqDFc8qmJvIDn{ znUQIz-4T#wR<^jq%t*rbqN-4BV^H^mNbis^+cN(eOL51BGVuI+3L|6YVm3)?9b?u2 z(6;ah7XeB6ff#O2b{gO%NOsgYaZcGfN3wH{s`uFOC9VVXj+3ORBo}R<^`ad;Tc;&; zqZ%vrt)#H0I2SxL&uYFZ)$H$S_tO>~xD!S9fSEbY1rUiPY)pi;R?($sczwCpn82U&O@s_xfKtY=zLR# zbsom8)8?c1Hl-yAC!45k1sT!A*b~=K8xZ#ll#c7qJ4qP&S(ujcP+HSM-8}0;BV7;HzSBi%(mJnz7g+3=Yq=!M zdJlJ3H8J<6r-#zH?nF@8z20^|M~ z-**3`(}46z#~`~JobS?6&s0l`O#UXfE4nxeTU9UMGN zl$&ZT7I0RbgP?^ZxFi-dWgdp#iJk+JM$8d(rLJ&2am0Lq)gC?oA5l2hx`iYD7(!aD z@Q#dkrxmgLxbqx=t}T6PtSB!ry7a?r73D#UNzZ@goEO%6>={vs^5c?%e?|;L?5M=C z&xk5wy`adGgwG|NRqbdL3E9)x?Qp@eYnGI#$)e`_avMs$L3##$ee(rtw&jA-ik3#Z zBeGBf8!{-2hKA}wxI$9GZ~#N7_}WyB+-tHX>yuaQ zu|eSr=qEHq=kgKs5*lX^KN1`z*GfSAP%z_K+#RGfM%rlpTfq^qBZ5L(aJY@i)S&Qk z&G(Qo%P0p2g@f;>5yqSd&;dpP#sYEylK~n4p+NZw`c*38c>wq_+zhXRzeEdv$p9~v zijtsiU<~0n9hvaJ&>R&krJ#`B1dGPTA~sC+E>OAGud7i>7wG1o(V5ZiYLG$fCP>b* z?kOR?F}iDFNM{W1$_?qFiY}^)jzv95%n9kD-C`zUDy&1Ncmr01+A247kCIm@DEP4U zbd`d_kHL|MsSx`vXtb&2df$pPMzz#$L_JDrOxNAF!a?DaU=l_^bZaiwAQ0 zJ*v0L`YY9AHPkMagk`v!Qk+yG?p{oEiTPC4(fo?*@|jRR%WL2-2nx%oZcY6+Y1ID{ z3mZ12MSX~R540#P560LGyb|-j9ehA3L$_-}sVvt@f(Bj%?@3UY8Dw;qeRMxqw91F? zMD`2Ov4J-AiS_%>fx=yl&{!m5ZE}p}`KA86RyjuV2>66rE8AgiPOdtrt2-7YU*TkpQR%7Hb|)hl41Mx)-BjV%0OLE()MuX6Tz_i5{y z+V(#u*qhcF{+4q^n$`;0m`RzC$$v`I) zL|sFeao=j4-RQ_|)Y(|sR{K>5y?dRUU&E9&O+Y7xCp6x93@^(+9gVpCE*3n~hTIHG|`kJ?pH7hb1 z^FoAzJFYmcsINV}8Gb~~7+W9JX!|MWsRQ(zUKT8UDI523W>BaFRjON2dbzyOA%9sj z2Zav~QJQAZECLY3p_^_>;?w9?Fk9rkln*{`Vlo6TXGp$RVOQFcYMHDK=!JBinKxmd zrx4wEgj#wxmFK)u=b##XwC%RV3~#xjU3I_nNtNap(R~&g6&(*Te&%5JXa0@SE?pd# z@|vaf1f#p?BcU-2vrjZsyC> z@Tr7maVKnrR}j9A@bSE6@x{DsKCvJP+@tA9=M&|%h3xIg<_8uGL@tBe0ioQU?!Ft* zjCJhnj3m$}rI-x??z1a`_o;?tWy7YxIxRPVhZQ7@uAL1q3vs$fj?f(F zy3+fR-erG*)=p(e^1br?hcz8?ZT+AFR~?Q4CxR~_I|@r-nbc;ZN6MSXGct>&bA0KL zhzvC!b-b!xRd|Y6{VW$>7GGuUaOK389d(}KdcQ_}U4I*e-FyZ1Rv82B@TxmYib@&pl#+2ABwnbI5YuEvsg4d74kQ^ie&VjOs=BZaB^94RUE<|@1TMc zjuXyl9eZYl7oh3gv}xu1Fb7@8hovYCoc25rp+&lDA-lT=y#!1 zk*0<=S|`tq+G(T561C&(K!QJ=nGo~8-qXyI*US!IU4hDwToH~J44fm<5$~{;*~?1G znjN1xj`pn$J<9~306^yCx~CeV_|19+b}zQOY6zDeg|8HhpH0%IJ7JwBlAvJkrgo|h zF}|B>J;fc}Ws0^@NQ+$+RrG9Bl;t)SceG6FtDn=Y)&Jt7ty58FR5xb5{Ci(tIn6QB zoY}{GYWD#90O$%^#63D{#lDDJrMTmU70u@};&fQ!{W|L1dQ&Rys4j;z>o7x_HFas= z9R@FUN6KNKD?$#ty27a~E8Cs2Evq2rRj^~#x!@=0@M?f2q{}M`Ib%tUY!PleMUK`; zf~SevJXH2#ZWY>hG<>PGV#q@Mfu6QD&NL7!!ui?os8~Atv6=W5Vh;-I8fYpvQ}EGn za%Q_6nlmr^XnA$M;GQuf&B;APOvJy#WiJZbXs9i#{h*bN`-(hyfN7n^#O7^N6Jwdn z=z6|(W&=qd?>)Od67N>d))3=f2N^N-G)bS`lF?vX&*Vs^v?j@T>cFD)#+tWVKZ+^# z6E6QdW6hyd&Xn848PzCP8^6BDu6yoc_PUCiz3V$JeY6g5kS=Mv_tu!cefyGPUB{*T zbu?{j@+0;k>OPdLy7YL)Q;7X=ark2EM)8tw-6`_dOE0fGTeB6pee`r_`H|dG`)%i? z!*VR@*bf&|)yqQ|+gs zi)yu0OS+>gJ(PEQ57icE-n^b+p}c##452({7mM!&LqKm)57j#^bW;uW%Wl??0{?AL zxUGlPCu4+jpfgFrU!g~hf!(`Eq_rODrdsV^y885}=ezr~+Gph4>|PDZUXiF)JMHSN zIXf*+$$kMz*x1u&5!`bKvW>9vx$V~zpd~<8#CZseD;gJCg_NG0&?*e<>DLu6i~YLd z1?Z1`bN^Y6(RrS}miI$I}rOoWJ6l$XnYA8Ag{s6 zZdRXwHE0RYH5e`hh1UT;L$icFBF}a}Xbm=p)?g!65k9vbx<02cU#dyBQeOjP)Nk?% zHmeYPUuEaAQk>h=T&Jsqv~Ff<<@XxNPCPC#iMV44vSTy6BGK zUuiOreE)z3Gtc6c&>=sU-myg5H76nqQ=C)sUQ8KK{?yi^;@C8L12iKP8b7Qdv?Jto5(8dK&u#u@WclwVDzKYv<@|8}yTiYohr;c-q%ZTw5mL z+HNJ(XMwu}qm6wOy;tmZHn&F^KS{<})ZZ_T(8fO?--V$u(r<}T_W2tMQ%hIw5HoZu z8mQ;$E74)!!>Nyj7kwaB+mVVi`xWL75YER-hrX9Lecu!57{H$l^*7PpN}Y-I)NfC3 zX#>LU&|YcXVMXwII+XS#XFzx+Sevha1|ATO1V~dact$~_p|SOEd_UeD5S|XE*i(w& z&sZ4{Zjh4g$py*Ihb)6(J-=X4wj|o_x3DcqXuCHske+qC?=fGgur#+vayu+>_V~iY zrcsVMha^^jc}?=ehJw zqI$flsK4$Pfv`|3ZLm)+Y8$UYKkTnBx;5Z71*93J{ANI5*pp}}kVXWA{ecnHrZs!3 z&4s6|XRD7c-s>=}X*Lbw?Jd#A516L3D39+qSzGE&!&@{M^AS^zcgKCkYDOnEf+N_k z4yZG(9B-MVHeEi>ynvUIe$sT$XuLfJoEY_c_-iO{FT&w??}ZnXCndqsb62&It~0!k zbk!K+gJNdpP%QaMK!@j48}Jpg=3< z6$G@pdLR87b&I6ay)Ks<>lxD?Z?rwSkU6aZPR8E4d!q^l$SpDh19Urm7qOmnpQzp^ z%SA{??K)}bVXQaZH@atZ57SZadAr~)T@#s+%Eug!%!tR$9_MG7IMVk&hb)$3CSWzA z%OL*9&6&X6u8P_>FxtJqT;>x6XAvqho&2LBm2Wpl)>Pt;*nFmTv*nd02GU{M0nh1e zMcWFE&TY`Ub?FkcnY8o=XEckmA|FJKITE^~sadRE(2R4_EILg`MY9PWNa&Jg#2uly z!$crkwfw}>t7cTxW;jzANRvdaBUlk>g*?gaE5)~&K*sOnO!MipYnVyVrd(NbQ74$j zkJpb6{ne5)wTtX!Gj`v%WMy1B^awVsDNdg@_>}KV?QKQVLpjr-y$vMrX$K5WFG}VX zMTANsP_lru`Sz|+n8J=TlQ>hj+)G00u<4gf_`)xbIPCP9+L<;*s15yEeq$gH9^8GP zRbczA-z!M-HchCWMt{LKvCvwOSDbB(uZEUZO@`y`+mg(1e4`3HUVW@O48B%;qY5-w zw9Dr%r>}S~dC$~lhuUZBGi;xL;y7DaC?`yR1nKPSdTc=2P&6S_J^{1YLmu*_!p>l; zE!C|4Ro_s1d2MM$ov*Gov53vs)G_6)6SWDU`U$9if~-K9G9#`P+m?2)FS>E;9-X7E+TvzA>=iHzRUAZi=G)%oa2nbt7`?{ zcOHlPIpy%Y*DYaQe3{VW?ea8y6@Z5eFAGz|#gg!+uAaq;oSyQFK6-9wzjzmG&6_#h z{%4VS+`s0XHCx~fw%Av!wG>-tJy!icQ^H%Po=L@Hw3mGcmR}*5&Np|t|rEPhBK-2QgH4?yz@!4Q*_U(yQlbkChS` zb__XO%w^QM*wS+!FTA8N)Xee!#JfspAj7`)QJeh=)`;5ebe%FSMCX@f z|B8d*p?7m?SRf>h-Y&OYdn-rZA!yBzS)S0H2s?N5`S$#(BBS$;sym%W#l+f91#=AV zXyA>gR@s_Loo!)>$5Iy4yQ{g~YGv`}evgZJhS_zy?MQn>lF}ceETHSr!;UulA9l^N z(UcT4ItTg>#|&vY3VYGgv8SBcjoDl#{Q0(&FI4Jd#RZT)DZiI9&XkW;T<4AD_a3tq z5@-M!+N1bQ#4+S$R^&D16(*PMb|$Lm=qdt6j8&Zi?F2Mz2yFei|Tqcgpn>QaV~E(MJUQqhHZ5tBTYB&sPLgR9@g8eUs`ckg!ko^Wnc%xikm z`6nOO83#S+WY~+xBB0^Jx7Yn#D389IraFvYL+xxeq5Fss6wna%P|!fm5Bi4~aMBlyk?NdddDXY(2b zJdugPU#N9lG?2cX#*KHA6c7mDvtSTkevHnP^(plM;TxouAQd%Z!D0q-WoLds2zD8r z1h+ARZ-HqzJ&zzw%ND>hOw(JtF3D$|-ix~DRgk4OAELgNk0sLdgP7R@K7_BGI~`$P zFwZ(mkri%>uv-%AELV?)7qX{`(SqNVsO)u?uA}(sC06HCI{(>kYl6^p{ccA0@P2$7 z5CcL(S5SC95EOC(N%o||BN(5R zK@LL}CjF#gI6~ZML>-92ZtXgx_%?tO8JarvS?U%K;=r zkNE?=wm;BI(){=6UB%dL1N4z&$glBzCqW7-Aq0=fVXfZnbUz5i;ytCm);Shl*VrfS*J%7vh| zva)7n)zU>-**S#leR=|$70l}txHx_h$Cs%F7?A>bk+ zBclH2Wt8N9^{3|4MD~#|ET>S0sqk>|ctpzjZmRRI08M)wl zV({%ck5rP?7+wX!0t{~@!WHB$43g&Llex&vLyMVYJ#uK?IFgOClZE(b)VdMzyAT_T za01F`-dL1nBbJRgtv?>&IJ79kVL0F&%M(9w2WHeeM2{_no?!mGe}calUZjHOp83R&(+x@A!X67yp`d zw?_Z)am&wdt^C*X?}?9^=gnMyaog>Q&7+@tbY}6UL35YB{Lz}X%DyuXy6LNwBY(T= zZJXYQPA{(P(L{&d@_t8KYr@gp_!KN|AxmnDB8(#n({?mkvBt@4YG8uy^u$;n59 zV@Brg9`a%EE%gIcyWIaOewLp-=61)T?i=&Adyg!oa*nRWH_5i7qz8Z8|Kjlhi#Fbz z|K_$stH*8g&3y6JznrgZ-R&Chu z{YTyhBDcJ7CXzF!Y`=K>*0WiU@ryn=+xXF&gPJ#-`tYBvlhfZ(?w`EUnDn=ag$G<$ zcaL1~WbE1P&Hvib{TTcDUz_LbZ;$$ke}cU6(v-EI7^ke8a`LIx1%anuY#2T2ojYDl zFdR2NVr;a0dW+?z)XIBx9{!Pr*<;7Y+|R`3#@J^J`TUM(^{DUQDH1H6D^fR6xQ0NMbj z0A~O{0@?wT=MKaopbx;I{b0c0cSHgo0?-4-0>%R}0h0mK0W$!0KoMZD&NIMiyVw72 z1MLn#8K45N46qXL0^k6k7VtJ;u#LgEae$WiU*rvzq5TZvzmKoyVX)lqY1gO!tNOpE z4W_Se@AtI9^#4md*zWap|0~+{`Pbt+F;=^;8?O~NEAydq@kD`M3(@)OXG>dmG#@|>Z8O^gLzI|eRZU<4l)gHl@BhChu$($hkJgnU}{(`@7+aX?1?IgzFCsG2ao!@jF#}x%Nl6FD|f)HRy?Z`U{C18YwV4 zHG8XOXj>E8gGgA1JT13f&1OsE$WYJW#ovAJZ?)9xiaM*RPUwyr46g{cm_Y zsb>EH&mZ^3BK4A|Mba=_GS_mbgBfY|KjT>{*hj2S&k$lHX8kq`D=}-jTEja$VVMHa zFBW!6>vT-|PHF8~erhzYOR-#xDBUS-I*XXyDQ%>&p#XhfY^CiLwify|8or~NnWED4m)$W;`huLoi-*}7VRp(aA-uIXr!uEJXIc(d zu4xbEHkMn07k)CdXa(l<3F{2Sq- ziVZ@p!5m}dIwFz(Z47tyU&Tq8ANvMt<%9YGYHhOKn%U?JwG#v92(@$NTt{`L6=90C z=IWnfYOZZ7+f-fyT5~yX=N1v;(F?56ook*#G>mb^V*fwCY?kUtg|VQgL5%%Y4!UKsj$La z$g#>UAw)<4b~`XxTq(yI7}O#Dt&&a{ekiSxG&Nl*+^)(CvVZDgJI|KJSU+=63Tf&? zo8%HX%ad-E#-3PFTnlNImmn~iTOG0KHKy)XmA&}_F)*0h1gATfXo*=Gkikgl+`0W> zq5qI|PG z4O_z66IXM!rH5&n%J|B|Dm&)X!RO6iUF~4>yDQm-pM36Inn!rnO#A)Me;W@GBkg;W zg=wQbF?*TJYd$uI6Lw-9xpN^Q61#j{s=r=!D*GZ)g$lgzx;mpJ2>UW4=TDZ2t^USh zNqdj><{X5@QrJB?fMQ95Sc8~H%-<6^p6}4|9QOJ7lQF@|{E0BHzDH&F!Z$?tr*E#r|4oqi&-}h9iJ2ZGF;km;#F$pU)55e8 zU0UM@w|{>73&5GotG+_NoOad6+8IMaB^??1?JS*#%F18IiL-z0(pnkANk_tp!Leg? zvUsJ5%WrcTFA~z?7^IsM+_}~yuHDKux4#dWqctDB5{wxbe?cl#3B!cS!y^jJzsNV8 zkyh+4^oNB$DFu641x*LTl~uB?jTaeis=3(AVFiC9hxU*w^Cd2ATkQc$WXr6Ehfww% z>@l|0sLW&Id1*WI2U+|`K3sR+MhgWCz0Cz09nT}9@}<|6YR*A(kK#~#NS zAN{uD(L@)5_4{^Hi13M37T;{js*lPeqoWE!U2oP_9xhv*?_x5`Dnng~u4406SB!;g zDeUy%YuCzUtC^{%>&hx)8v6TZZp4>lhNbVboNdj*`loFxYsaX{M^0KiR(OaIP+0Yfmbxv@{g@J=R4PcPufw%AKa1y@^H#li{o^T@f|VN33zk zOsw*V?9r#`A9T&Htj3 zc+7p*vlm(j4cVXyXzBIsRU*eYYJ=P#xP@E zw8S;(1ipje`6fo6Cj3wr*FpY9?}Q z)oM-J7FeCzm3gkJq%%EN(xvh39%6)bNM}4Xz#38%ZSZrTN?Gw$Sn=3v<~x6sl)0zt zCLHUA8(p@#f5kAFw577j*;3f_!IcyAD|fVZmU;S*bdONJH1*@`hq^uf#8u|tJtK-O z#o5HL%aYs@rXPzH&?0k&F#RZC2Lr?qt~UVt5VUapNMJ93rqT}wc0>*amH=!U^mLFu z4p<#%LHZ%K#`7ApEUs@->7zk?3AI&vEwDeLc91?C*gnvL^r67kf)=LN0NaV$VOUAB zSc(?I^&GG*poQyC_~<&I>qt|}C6m^DSe1;Ct)MGD{UXbSH8DD>r>c|@A1V-oEY1$3 z2pP&aE|&W>#+z3?cSW9NjD`vwH0c5JPAjwzi@IaT7+IVvrwPy}jZ~lbeA;?-L5Lw# zPqlKQ90I;5HdHS3yQ^v(m|+55>ced+l##^{S%nh8;8z7KT(1U3II4Xj>MFN+rgY6GWd2TGiK5Bd`As|`W6D1qjGjeO0o`E4{G^|kfR z0)iGOXIBH%)?vZRSAB!nv!KCR1MOc*F2z1jaw+zNlFI}8hmuRN!^q{YdKNMUn%bb0 zPy_q$SL_9pAm9b_uh1yASD^(1t5awc+o8}xfW55HDE4sQO*W#m{B(droPkkV*Ovhr zgWM-UWAqb1t5WLHaovi#&tLV-<&;rg+$W2f@?igKkr%9RV*j<*%0RF|Cq!X9vK3kw z+HfgYIIuDWQvtgZ7+t-xI9{Oz0h_DPC}s>qfG7GD`PhrW`VjCGk5w9?tWq;*A(&aZ z<7F{?U@oYAL+6Y@-UZv+q?0;}pHwy@Zj<~vODCDrjJTi9vXlF7(TOTUk{LwOi1Psd=e4CR5A`3d9U0sSZ7lpoqY<*jp|oz4OJ;P?@J|5y@z zn?&>mzo)brasT*f^$cd`@80tmO9Cq)@(6=4>K zw^xHu^admB^oAhp@P;D1>Jh%J>KyM|LmQB@Ja6t2zPih5I*M3M7Yg6 z7h$z`BErqy8xd~w-h^AT03iN0{fGj!^LCBeZ($2+iIC zgg1LOpYNUynLy>+Gu^~!bZQ%^ zy>`E0PbutW$9$YsXu4zxP6?2bU4dBpO$KHZ851+JM#>sx{$=#?sQhNhys%lCHp*jY zmU42MCEF<4TNqZ&%5J?td!ze%8G6zyHq(;s2~M>gHYYpZ;cldM8a)rCYltQpaTtL7 zlbluAgYx6C)NUs>Qj%34UQlrDbE`^F8;p(_zuZzxpihhrSu}K;!EcH{bxKnAITtbYwxX`l z=%D(X*5v^jK&*X_%it$-_Bi&qEPfB-1lN~*?+HrvSQKifC!;@?Ag!^-3wvB7wfA%a z$}?<&QjcNxI6_^g)x9Sa-gK;4YbWhyCgE;_Kax!-+sGu8sSR7r^PSK)-Nb*=Nqgf_ zE5TKST5JnVhz-X%)v^v-h9g9=4%AV+2u(iaBS*SYHbH(qe!>Ba91N|=551GXa znXUz{gjJu`#>`Az^=_@EmeIem{K5kyrLUDqJ?YxL?jb*;4#!wO*q!N`A}ny7S{DZ^ z{Qhpf;kD)PA_(VwQ?Oo^A(t^MaQ%$4FKwIJ50Unh50K=(*2GneiEV)m+TzX)&5w4? zaTU3u*9BMXG;g!U4p1xt42(wTZqGP+nD(bF{1_3Mi5P5r!h{Jl*)3ypLnSofb~{F!F_++>F9b zHYduSxXfg(vBc9eRC)y3%I=cI(=ts_+w118R6#FL+v{hE+K8|Znry!eztQ$fRP0$F zU0;+Js;ArlZM{$cS=Pfq|It0UyqoG`s@V?%qf}XZs%sE?L&2yPze6cUvFDU>6x%S6 z3+=v87I$@}LE}>Tj&26=cyQ!KiGJ(lVWk$eSr&DTMLBAbtV21qVx``$l%w`al~Rsk za}*l2Dk?yuc7-h3lpZ614N=NbZ2qs<Y&sHvogwav2aq78r)wDV_Rg znyxI{4&5ck*grMQFD(XO&vtrB_c*?G&B1&sDeTy<73$Xx&M=?uy3T4#|IR~urLyP? zuyzf4p!7I>Jb^?{rCvbnk!egIU#F3P*eNp;uoEW4w746wCW>^z9XLPU zAobgnCW*>kdTx}((eKFO80i}P6|~f7luDB5D!S~G#RRF#7b--v=4(G>*Y$LC)L!+h zPi{i)^8S6sW1qw%QjehIEpZ3D~EDT-_tT+rfnNbLD@SH_TQzDg_5uTgsMH zOC*hcmB(7TLR3;QIUE?KzU9BZB;lwoy+Ddkx^=Y$tS(HDnSy0vfCljJ|Nutt+X zs~-)C@P@1wSmQXP=$Z5-Im`+DW+TTeI*m< zQpg24gXmLj0r5th3+0RyTlOyrOhB9vVDw`^bq8dF6_PC=j#l!Gc}CzP72J?#03IJO z6cl#8Rkg`L^g3G^)|oa?*lEt}-`Pfo(UoMgcD`I@L=G27D4_Js7?FV3+vhgu^uvIO zIAfWwJ;pwy4~QLoL>H5= zPD4z;X&Q}VQ3fy$zys*~(Xk1kn(Y^^Cz_Zqvf86{@XrPlee&Oy z1>6OWV9oV@YV=^P%SwxlWu*b}VxM04%vBQ9dt#rYLjFma$Jz-3)+Tc-Rvock4 zb6IEAI2t8F_FwIGc*cD!f)2r+e82@y_U+spD+l1Bo$rTk!JSYbNqbHFEz-6$1J(0x~^06zH^p@pX zA=a}|Vm<$GM=if~`BTfOM529X)zewDTsz~OXqz}QAP(!BsLZSRmn%^j;5)J}S+Sz& zw*+HuX=w&H*GI8fWxe(F_T$NP{s(Zn;yQXcjCnxJ?4#B;U3uqwjnp%bGum(Z32B_W zeoH6WsKyM4j|3P)B)mTX@!>!}4~3mavjgIXN)HZw404Y4LJDO^*=YX(v7s0Ibyhp6 z#SsvtBgup@#{qPJae#?{EWk8C7=Tcq`iy5wl7Qy`Sb@XIFCea=dk{J|t3JCRAl?Vh zrv^G}I!4H#oa{B=a4|4S4~PpfGW}S#f^nclDCHZQj224FbC8+p?f(Q{ZK4iDHjTClv0jjoKlYVlc1ENSXVDmJQs8? zG#MjY=T|8%G98O^-BB<*4+ZwyIru6CET_D0DxWVmc^f%DDHtpiJs8o z$46+pS+FI7W@>6*d620!)>2#Oviuq(97*kIi4#Oc#<}aYGwGL8J)DKn3KBF5o&lT} zf)#vRAVj~BST5#pjKO*_h~(7K()vKo#iIlgqLIY*^LB62#z-UfBuq*|e(NpO6EFTZrAA3ysF|NH#?+Np@^_4bwz5?P+ zX#a94-3K=ybwiKaV21ZAAg1?b7s#b$-rfK{rVdS%cKDhBWgU3z!R-4JZM817PhZ zU39hep99Gp&d%r0cd#AR88~6%yhHmlGK*($f<~A>A}BTdWJPTvtIoILma)yz2Cd{l z98jvxakkr)k^tFR=BvimoR&vQ4l|7+ihdSs4%{3zzc|n7Dn);art34;L zM&id<^K)#?l4cCG&%?%8;3?3K!Khi9rPwi{IQto}{;AE~-wJGR|53}=O4@@sAimob z>Po1<`T6UF3g!IlOsI%Pou1a+cWZ@gte)LvY=@a)GPw2)Ok}FfA-1+jd>nU`lxF)` zrpU4TZha?-+Fcg!%J!R?cn6I=h~eLgfKG`+97p49+#XQ8u=62jyfeN6I_E3cIKZO( zTBfHp%30)Wb!sbgogTN=x!bu6vpdfjk+<7<%9Y)DwCI#$H(F+x-Hu|H(a&Is%{t6d)aJpT9m{NXAXK#%8~to)}+iVp7Fc+(g*s->qQNUU8b|P7vMx%Ioje5|!JZ zfVlk~t#Us@`JgX!5(?A;?pZw%0{tSAJ#3~~7#tH%7c>N9_u8(>0{wdW?c=)^ISy3N zG0|Y>4vx|RXF$|-nW-I*v2}JCU9@KZ*x;=TXt%*1P=ar!{VqgI$AFH3yZl zRwuPwk0@nyc~n9jmh=Ms){(#uNh6^%h66hwQ5)e4J(W@~C^(~7uFojAUZA$?ZfO{- z6A%1pkY_aP^hEC&@YNNKC7P(4h$ir$dPF1j*}-O|>mv>0VM9EQ+OUXqNIR|@s{*9y z`0+Hxx~F>cE}6$oyc+jV^Y8E1pIhG>TrWfHvf+&6J{oHqlIO3d{(54JDU6*JJ99|E zko?baI-BaqbeJ4Q2VToKVjQ1Kv1x0ZRnEJeWlpQp?kskGE`_D_IIcL_9p@a)j?Wxz z4nMVJATO!@Q}j2FnEDk4dVmhrRk`V<#V_HiU2 z&cxZB@6Z9WDI-_d+3n;z#*sd;TP~}htEbGFg)@Ikc7ORBC9VEnK3bceh$qmq{qpa8 z{rQwKno^2R_%!tz!w@^c9bb*KUpE9Y^LhBGZm4X&kQ%Ln-fET(!7g|MXJ9vUn|XP- ztxr5A^ZGE%8z=F4cty;8VgQt2Pg&zza;;X2NJ>`gxiz79$#$-azEP}kn9q`wIW4IT#x+c)Y)WpDji>7t zuQ67=+5S;vp`UQJZ;e&nq^~Zqt2xs%mnN>xYT}HYmp@vqL0OHlB&Yr>NV&s-X_M1A@3RO>qFvTyZia<1y7%P+2e2syO% zXD*FI&5x9t+HbC2KB{2hC(c|-SRHbfwsZ=!Yp$x<@U(A)aKc9^y=aGnz5c}|W;ISq zy62Y5Vv%feoxXck!*kX74QJPotT@<<%9|x~95iv4kI{)f>J=FDSrRhQvMhSj6hc0> zK&}#k`D90^?b>?Ogaw!Y>$0)iAn@2#{a#U>VtdkZ7@y?^c+C66%Q)?NmXE{=xeyqM zH!cfcIpMCYo8ERNfm$lFh6Ke1dO)If=&RiU(bWZ;s*8o4Pfr}#61};jQgs?u9ld*A z7@(fp2APM|9twJz#KV@?05f52o1Gf8TNjYA_WSp`&_Hb>#U7%25d7i%TcWme>4~l_ z8t$s6m_VynD{qbxTzD{LlAurU#kwdv(=k2FU!Ul@m5D6iu4>Eqiv<%^?UrF-)@jZa z^K$%r&Wa*iEtif~=5EpO?QAA(YXjQyH{xxpDZw$=79r9|a|%X=mFgpfmz&IE!vvM^ zUR^r85ueF#Swih$r$X~@&PjAVpE#uS$%opciOJL!X+|tH!v8Oksj#2Q-bZ|GfIlk3 z;vhj~d`Ytu2YVz97Dtj|mrzSW#xB;xZ*Wk{L*E&2Qp>}vpH~WNGirCKIlWopqyEzp z`2;peG4)7Q6+5UW2UZ%!A`T{ab6s%qS4~_;8sR!_qZWRy2KIZRE9y~LLS=hh%~!&W zpCrU=#tPAIl*VWk`wn#}pHv@*+vly$Pnuu3Q%coUHc*fKmy*N2pVOQOE_h#Z+mQ-2 z`+4*Gi04&CHT1tS8_>mQ2gWKB1j#{ro9~LNr8XnAJPnAu2gXEOkGq@#qXU+Kt52NN zSDnk-jgCI?mR{1-JCbDayZj@gYG40u5?1F8eTmQui3Rg3`@~QB66^_i39jM7R*Smj zIg6?#&bHCQw#1|Eq~4)+^Dmn$i7xtHt@%nQx6=}BkI9c~8t2&Kki~CtzT4Jia@ANu zTO$exZV&e2wt&$aT^fPj8_42Y@QbA>HpS2Hz5X5LgYxj*(bvDjoz(60O&`WsL-!uN zMbjBHd41x>UY$XmrxW_b4|>xYbfEHibf@)+E01U!&&rXSX?S0F2cc;OMZ>}v~`$p&fT`8 z#$j63Y_hjRoUAk5+@d;p$YgD)HH~fw)A47InR;5=9%OVzx73Ig!G2k%N&V$y%T$f& z=abBHcnj<&P1))A`vSo0Y5xvu254IlkF}r19Tf|yaI$NWd$gU=Ck~7nV|-XjOVitX zN=QY)jN<{ZM-sqjHeqB=G{?sH}lZapT{Ii-EHdtP6VuUSqZ=T&$ zuqof@+5{_4mm(WB&TN*FQ<|mOp&LLkhc-(#Q?uk=(2V`lEV)c=lG%iN1)PJ-z#Rj) z!$b^Gf>y{nTUNbnW+Id7;yMFmkS}qeR!Enu{#;q~^rilr)OqLZxmC>62-A&AoPIF5DO#UA{O%Rs_$c+(f*C1%$54{oGy~TAEqw-8n?j#m z5CZxF&_ndU_-a=1rl6C|RL&Hvv>%h8&%TWH*3XUVENv;z#-}7V(R-ncKC?Z+bx>(% zhAkS@XuMXVWh}NZq{8$+`6lIO7|nQ*7~|%Q(+i8;c*A*jTCgnsrSEa~33m{Dm$LY$ zz6OhSIeq1Qi~Djbt)GF~891STuC$h63qm?b|ACUaVW6k?l$5SuGWg#Q{wM37@Fm)) zPGj8`_d#E2^$7d?vS)pJs)rS@sp~s)51vBHe8(vgi`HWGYmlQ#jc!q=s$2Nf*w$0k z3ASY9Bf&@PXm7%U+L?m8u?UptnD#S9@AgN3wMq1i|-rk=XdDZgiJJhY+5q} zBbAM2k48(^>>|*Y0M-KNnhgU~1Ah##jUl>Ah~GpE`3#_MO8wd4LImz?iGH-7Q)Rls z3N^y$94fnBvjnx`23AjW3zpDRN?a~p#U@Hia5o_JEa5YIN-z27{-FKheYf?DWZsZ( z-z71R&k%M=9N8tY=1uUb=3FGBW`M5JC3$widuyF#y~rA^`7xfV^;a6ydNX$Fo6;`W z+iGFHsi>7C7q&cLWJckBWFn)V0=++_YsLMO8Zx(2i*KhTsfo$Vd|0tyHgTqsR%g=r z;aeabc1UXB@i!arx;3RWXx#WyYJ*F71=8(wm*y8Po4&YyuX{4oCW7Yi)K6rUKDrd;JZ(2qg z*-wp53+IQEQL=cO{8v!8$jd18Q%mN0V!F^mMoqlG*=NexiSqNzoba)a zjAci)`VM34=y{cn-&<79;B<$19YytJFm4A(bpNYRwVi63S--vm?LVvbiIW=!^drtd z<1bvvttc?M?yR`Wb(L?E;;I?Q)yq9@wb4aR%y)GJ#hpl8(yzm;Ru+F>@~ns1$Lv=5 zBUQKCj$H|f&%^js_ORp4{zp7{!fhD!j=)g=(MY39)dG)4vZZr>DXfO%3@#16a$DjT zYR!qlJV>C#f0s3`MDFTMr5~$Tov`H-*aE5AHvIJu?31z+YUV^veu8taD-IamqVySE z$V-H!f;Mc3ZHQfvV=mKj&U_+krqNY#H%TdJVNx6|21q2$WcI4I^mI_li35*JeRD@e z;kBccQ5Hjs*+i|Ybo3wI;rQv|1dXxedo%9(eS5if*rHW z7i3!BdGA4uVw--|z1X+IwS|B9t0!EWecaV(SVdn4)tq1q^iAPEx}P4P?eWpQ`&Jb8 zFE%cndmNPv-ig`X*wgNwaDT%In)-G7lyz1Vb6Y5a(p(Qc|7hBOIKTPelX5w z%-I+RpYfcfrwzAC616#5MZVFoSuvoC>EDqBFmnESMz`%yA3V){I3EYZE4=~nv)*`n ze15!Z2mD&}cAmaw9a=EVKF0N8herL3<=RQrtLYh&LJEvEi&_|L_wv^$$c(M=*X*{U=sXefwNhY_> zm{Xj?V&5|I|F0jG&VT-v2f@Yy{0R6KZr#{{B7b~%%hqj=Ji7hy9Zx*@)Sv#mYtP=l z?0fo|{m<1r|H6wez5L3n2VQ&Q;Gx>ux;NjdKm7JP4e!3|J<|Bzdre1=9ecmI`S|e< zKKSsXk3RbN<4->M^wUp2!|(I{-xvMAffUU^{wJS&{4q*@_`wIqk2g2Jf9%-NruW`! zJmP)#-G+DGK3xCSn{~CdhYr5++JRSJdHJOmUwFRex&6;Pz3(r3_w4%fpPqX1i5-t` zfAo=UTem#?$ITCI+~8TiZta@Y58Qv>$`w`1-OHBVd(V;z*WyLx3(HEKj=S!>n(GO=gcXZT{vsj%z^@Yetw?KmYXXGGiK!ESglrz#gdJmdGI%V5HV9Sa#1EH zXT}Uc$j!Cc^78ZT1qCx_%_^K-G-pon+*@wFtz_Q(1-IXE=UonGY1zW^MT=b(OYXUM z=`#27sue5myZ?dJYu2t?@7b{Nq0LLNMtK14xRn2d{18T`;9eY@ehkCknTF$Ua1not zjouM~zeOEJG-bfg0Gxn-0?q*z11e~Yw$8)0>~9Zk4z#B?ARq0#4){N9kMdD^U3(0} zkdNavYQhon#kl`@_I^LPJDC@@btV!eN%qW z-z+|t=YsiYu8b@r_u`+EOaN4nFwTv5DX!L?B#28R=_Hz)Ns5U;<^oT{KOIp;P9|)e zRz5PpK*M9a?6a53jXqC`M#$YZhZ#)20e|6u^h9q zs?_aVy3jeHY}vi{Iwv?QLJ0lQ{8-HUZF#e9DeiadD0C0(4u&L?98ym11AAqN^T6H; z#FbJ+}=~%D5H#Yg%ik_tp?it?s>V|cxBy;$hXUiiyqlaxK zZ;X6(a*uJIc=1)smw&1H`pMQwAIg_rO1~#ezwM;u$Ac^W{_H!_qvn!X zYc6fMBd&S;Gmp+HTtDoVr7wQ8>Y(#m^RPdBnRx8Tq9f&fZ_L^?&HVX8wv8#amDf75 zq{2t4=6y8c?Y|ZOnaC>=&)jpOIJ^9d&Z_!h)zcE%0u#n&?HzGEa8R?kVt4)D3!fH> zCfwmz++Gj*8xxm55Gnm|<@@{2)yq>7p8CV=@0S0qI&$H| z&ZQB%4qx^>7CLju{&8)?DvED<`o#7z_iR3BTDx-X+V4JU-5k2YKlQvVB3{Q_nYyANSUsuf!To8Xqw>T0Xti@`t4I`*rUM zk2DlboD{i{iOPz!&m8gjUyEOxHr!m&l`Bv9aQg1c_EVp(Obx1QnBt^k5yCCSj$eue HPRRcNEoX1h literal 0 HcmV?d00001 diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/boardd/tests/test_pandad.py index 50d24f4fe3..fff17523e3 100755 --- a/selfdrive/boardd/tests/test_pandad.py +++ b/selfdrive/boardd/tests/test_pandad.py @@ -1,16 +1,19 @@ #!/usr/bin/env python3 +import os import time import unittest import cereal.messaging as messaging from cereal import log from common.gpio import gpio_set, gpio_init -from panda import Panda +from panda import Panda, PandaDFU from selfdrive.test.helpers import phone_only from selfdrive.manager.process_config import managed_processes from system.hardware import HARDWARE from system.hardware.tici.pins import GPIO +HERE = os.path.dirname(os.path.realpath(__file__)) + class TestPandad(unittest.TestCase): @@ -27,11 +30,13 @@ class TestPandad(unittest.TestCase): if sm['peripheralState'].pandaType == log.PandaState.PandaType.unknown: raise Exception("boardd failed to start") + def _go_to_dfu(self): + HARDWARE.recover_internal_panda() + assert Panda.wait_for_dfu(None, 10) + @phone_only def test_in_dfu(self): HARDWARE.recover_internal_panda() - time.sleep(1) - managed_processes['pandad'].start() self._wait_for_boardd(60) @@ -66,9 +71,25 @@ class TestPandad(unittest.TestCase): managed_processes['pandad'].start() self._wait_for_boardd(8) + @phone_only + def test_release_to_devel_bootstub(self): + if HARDWARE.get_device_type() != 'tici': + self.skipTest("TODO: fix reset timeout") - #def test_out_of_date_fw(self): - # pass + # flash release bootstub + self._go_to_dfu() + pd = PandaDFU(None) + fn = os.path.join(HERE, pd.get_mcu_type().config.bootstub_fn) + with open(fn, "rb") as f: + pd.program_bootstub(f.read()) + pd.reset() + + assert Panda.wait_for_panda(None, 20) + with Panda() as p: + assert p.bootstub + + managed_processes['pandad'].start() + self._wait_for_boardd(60) if __name__ == "__main__": From a250e1cb2f176b9de808f8ee76b6999562c47463 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:54:23 -0300 Subject: [PATCH 189/283] Multilang: Fix text overlap in pt-BR translation (#28450) * update pt-BR translations * fix some cutoff texts * update pt-BR translations * Include the new relaxed explanation * fix text overlaps --- selfdrive/ui/translations/main_pt-BR.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 4b2a3d88c8..226416dca9 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1057,7 +1057,7 @@ Isso pode levar até um minuto. Aggressive - Disputador + Disputa Standard @@ -1069,11 +1069,11 @@ Isso pode levar até um minuto. Driving Personality - Personalidade de Condução + Temperamento de Direção Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. - Neutro é o recomendado. No modo disputador o openpilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o openpilot se manterá mais longe do carro da frente. + Neutro é o recomendado. No modo disputa o openpilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o openpilot se manterá mais longe do carro da frente. From 3b9fdf206efc0d014da617e60950304e3b1c95c2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Jun 2023 04:30:19 +0800 Subject: [PATCH 190/283] cabana: fix hang on exiting with CTRL+C (#28455) --- tools/cabana/cabana.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 0a4b9eb112..5dce53ba7d 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -83,5 +83,8 @@ int main(int argc, char *argv[]) { w.loadFile(dbc_file); } w.show(); - return app.exec(); + + int ret = app.exec(); + delete can; + return ret; } From ff4aae85fe39b6442c03963a6a8cbfc900ba61c3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Jun 2023 04:41:55 +0800 Subject: [PATCH 191/283] cabana: refactor dbc manager (#28445) * rafactor signal * cleanup * refacto dbcmanager * refactor dbcmanger --- tools/cabana/binaryview.cc | 9 +- tools/cabana/chart/chart.cc | 12 +- tools/cabana/chart/chart.h | 2 +- tools/cabana/chart/signalselector.cc | 2 +- tools/cabana/chart/sparkline.cc | 2 +- tools/cabana/dbc/dbc.cc | 113 ++++++++-- tools/cabana/dbc/dbc.h | 80 ++++--- tools/cabana/dbc/dbcfile.cc | 118 ++-------- tools/cabana/dbc/dbcfile.h | 33 +-- tools/cabana/dbc/dbcmanager.cc | 299 ++++++++------------------ tools/cabana/dbc/dbcmanager.h | 77 +++---- tools/cabana/historylog.cc | 2 +- tools/cabana/historylog.h | 2 +- tools/cabana/mainwin.cc | 56 ++--- tools/cabana/mainwin.h | 1 - tools/cabana/messageswidget.cc | 2 +- tools/cabana/signalview.cc | 10 +- tools/cabana/tests/test_cabana.cc | 28 +-- tools/cabana/tools/findsimilarbits.cc | 6 +- tools/cabana/util.cc | 20 +- tools/cabana/util.h | 5 +- 21 files changed, 350 insertions(+), 529 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 13cd76af3a..9865907069 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -165,7 +165,7 @@ void BinaryView::mousePressEvent(QMouseEvent *event) { if (bit_idx == s->lsb || bit_idx == s->msb) { anchor_index = model->bitIndex(bit_idx == s->lsb ? s->msb : s->lsb, true); resize_sig = s; - delegate->selection_color = getColor(s); + delegate->selection_color = s->color; break; } } @@ -381,7 +381,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (item->sigs.size() > 0) { for (auto &s : item->sigs) { if (s == bin_view->hovered_sig) { - painter->fillRect(option.rect, getColor(bin_view->hovered_sig).darker(125)); // 4/5x brightness + painter->fillRect(option.rect, s->color.darker(125)); // 4/5x brightness } else { drawSignalCell(painter, option, index, s); } @@ -434,15 +434,14 @@ void BinaryItemDelegate::drawSignalCell(QPainter *painter, const QStyleOptionVie painter->setClipRegion(QRegion(rc).subtracted(subtract)); auto item = (const BinaryViewModel::Item *)index.internalPointer(); - auto sig_color = getColor(sig); - QColor color = sig_color; + QColor color = sig->color; color.setAlpha(item->bg_color.alpha()); // Mixing the signal colour with the Base background color to fade it painter->fillRect(rc, QApplication::palette().color(QPalette::Base)); painter->fillRect(rc, color); // Draw edges - color = sig_color.darker(125); + color = sig->color.darker(125); painter->setPen(QPen(color, 1)); if (draw_left) painter->drawLine(rc.topLeft(), rc.bottomLeft()); if (draw_right) painter->drawLine(rc.topRight(), rc.bottomRight()); diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 353bb3fab3..622b79d806 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -38,7 +38,6 @@ ChartView::ChartView(const std::pair &x_range, ChartsWidget *par setChart(chart); createToolButtons(); - // TODO: enable zoomIn/seekTo in live streaming mode. setRubberBand(QChartView::HorizontalRubberBand); setMouseTracking(true); setTheme(settings.theme == DARK_THEME ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); @@ -107,14 +106,14 @@ void ChartView::setTheme(QChart::ChartTheme theme) { chart()->legend()->setLabelColor(palette().color(QPalette::Text)); } for (auto &s : sigs) { - s.series->setColor(getColor(s.sig)); + s.series->setColor(s.sig->color); } } void ChartView::addSignal(const MessageId &msg_id, const cabana::Signal *sig) { if (hasSignal(msg_id, sig)) return; - QXYSeries *series = createSeries(series_type, getColor(sig)); + QXYSeries *series = createSeries(series_type, sig->color); sigs.push_back({.msg_id = msg_id, .sig = sig, .series = series}); updateSeries(sig); updateSeriesPoints(); @@ -154,8 +153,9 @@ void ChartView::signalUpdated(const cabana::Signal *sig) { } void ChartView::msgUpdated(MessageId id) { - if (std::any_of(sigs.cbegin(), sigs.cend(), [=](auto &s) { return s.msg_id == id; })) + if (std::any_of(sigs.cbegin(), sigs.cend(), [=](auto &s) { return s.msg_id.address == id.address; })) { updateTitle(); + } } void ChartView::manageSignals() { @@ -277,7 +277,7 @@ void ChartView::updateSeries(const cabana::Signal *sig, bool clear) { s.step_vals.clear(); s.last_value_mono_time = 0; } - s.series->setColor(getColor(s.sig)); + s.series->setColor(s.sig->color); const auto &msgs = can->events(s.msg_id); s.vals.reserve(msgs.capacity()); @@ -799,7 +799,7 @@ void ChartView::setSeriesType(SeriesType type) { s.series->deleteLater(); } for (auto &s : sigs) { - auto series = createSeries(series_type, getColor(s.sig)); + auto series = createSeries(series_type, s.sig->color); series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); s.series = series; } diff --git a/tools/cabana/chart/chart.h b/tools/cabana/chart/chart.h index 3bb191e5cd..272ea0d193 100644 --- a/tools/cabana/chart/chart.h +++ b/tools/cabana/chart/chart.h @@ -56,7 +56,7 @@ private slots: void manageSignals(); void handleMarkerClicked(); void msgUpdated(MessageId id); - void msgRemoved(MessageId id) { removeIf([=](auto &s) { return s.msg_id == id; }); } + void msgRemoved(MessageId id) { removeIf([=](auto &s) { return s.msg_id.address == id.address && !dbc()->msg(id); }); } void signalRemoved(const cabana::Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: diff --git a/tools/cabana/chart/signalselector.cc b/tools/cabana/chart/signalselector.cc index 1aa8fc5016..50fe861a03 100644 --- a/tools/cabana/chart/signalselector.cc +++ b/tools/cabana/chart/signalselector.cc @@ -91,7 +91,7 @@ void SignalSelector::updateAvailableList(int index) { } void SignalSelector::addItemToList(QListWidget *parent, const MessageId id, const cabana::Signal *sig, bool show_msg_name) { - QString text = QString("■ %1").arg(getColor(sig).name(), sig->name); + QString text = QString("■ %1").arg(sig->color.name(), sig->name); if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id.toString()); QLabel *label = new QLabel(text); diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index 6d7b35f3a9..bac867bd20 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -37,7 +37,7 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, doubl max_val += 1; } } - render(getColor(sig), size); + render(sig->color, size); } else { pixmap = QPixmap(); min_val = -1; diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index aaa4a97ea9..1ac99ad464 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -1,32 +1,96 @@ #include "tools/cabana/dbc/dbc.h" + #include "tools/cabana/util.h" uint qHash(const MessageId &item) { return qHash(item.source) ^ qHash(item.address); } -std::vector cabana::Msg::getSignals() const { - std::vector ret; - ret.reserve(sigs.size()); - for (auto &sig : sigs) ret.push_back(&sig); - std::sort(ret.begin(), ret.end(), [](auto l, auto r) { - if (l->start_bit != r->start_bit) { - return l->start_bit < r->start_bit; - } - // For VECTOR__INDEPENDENT_SIG_MSG, many signals have same start bit - return l->name < r->name; - }); - return ret; +// cabana::Msg + +cabana::Msg::~Msg() { + for (auto s : sigs) { + delete s; + } } -void cabana::Msg::updateMask() { +cabana::Signal *cabana::Msg::addSignal(const cabana::Signal &sig) { + auto s = sigs.emplace_back(new cabana::Signal(sig)); + update(); + return s; +} + +cabana::Signal *cabana::Msg::updateSignal(const QString &sig_name, const cabana::Signal &new_sig) { + auto s = sig(sig_name); + if (s) { + *s = new_sig; + update(); + } + return s; +} + +void cabana::Msg::removeSignal(const QString &sig_name) { + auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s->name == sig_name; }); + if (it != sigs.end()) { + delete *it; + sigs.erase(it); + update(); + } +} + +cabana::Msg &cabana::Msg::operator=(const cabana::Msg &other) { + address = other.address; + name = other.name; + size = other.size; + comment = other.comment; + + for (auto s : sigs) delete s; + sigs.clear(); + for (auto s : other.sigs) { + sigs.push_back(new cabana::Signal(*s)); + } + + update(); + return *this; +} + +cabana::Signal *cabana::Msg::sig(const QString &sig_name) const { + auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s->name == sig_name; }); + return it != sigs.end() ? *it : nullptr; +} + +int cabana::Msg::indexOf(const cabana::Signal *sig) const { + for (int i = 0; i < sigs.size(); ++i) { + if (sigs[i] == sig) return i; + } + return -1; +} + +QString cabana::Msg::newSignalName() { + QString new_name; + for (int i = 1; /**/; ++i) { + new_name = QString("NEW_SIGNAL_%1").arg(i); + if (sig(new_name) == nullptr) break; + } + return new_name; +} + +void cabana::Msg::update() { mask = QVector(size, 0x00).toList(); + // sort signals + std::sort(sigs.begin(), sigs.end(), [](auto l, auto r) { + return std::tie(l->start_bit, l->name) < std::tie(r->start_bit, r->name); + }); + for (auto &sig : sigs) { - int i = sig.msb / 8; - int bits = sig.size; + sig->update(); + + // update mask + int i = sig->msb / 8; + int bits = sig->size; while (i >= 0 && i < size && bits > 0) { - int lsb = (int)(sig.lsb / 8) == i ? sig.lsb : i * 8; - int msb = (int)(sig.msb / 8) == i ? sig.msb : (i + 1) * 8 - 1; + int lsb = (int)(sig->lsb / 8) == i ? sig->lsb : i * 8; + int msb = (int)(sig->msb / 8) == i ? sig->msb : (i + 1) * 8 - 1; int sz = msb - lsb + 1; int shift = (lsb - (i * 8)); @@ -34,18 +98,27 @@ void cabana::Msg::updateMask() { mask[i] |= ((1ULL << sz) - 1) << shift; bits -= size; - i = sig.is_little_endian ? i - 1 : i + 1; + i = sig->is_little_endian ? i - 1 : i + 1; } } } -void cabana::Signal::updatePrecision() { +// cabana::Signal + +void cabana::Signal::update() { + float h = 19 * (float)lsb / 64.0; + h = fmod(h, 1.0); + size_t hash = qHash(name); + float s = 0.25 + 0.25 * (float)(hash & 0xff) / 255.0; + float v = 0.75 + 0.25 * (float)((hash >> 8) & 0xff) / 255.0; + + color = QColor::fromHsvF(h, s, v); precision = std::max(num_decimals(factor), num_decimals(offset)); } QString cabana::Signal::formatValue(double value) const { // Show enum string - for (auto &[val, desc] : val_desc) { + for (const auto &[val, desc] : val_desc) { if (std::abs(value - val) < 1e-6) { return desc; } diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index ad5f33a260..56a3ea9a65 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -1,9 +1,10 @@ #pragma once -#include +#include #include #include #include +#include #include "opendbc/can/common_dbc.h" @@ -45,41 +46,55 @@ struct std::hash { typedef QList> ValueDescription; namespace cabana { - struct Signal { - QString name; - int start_bit, msb, lsb, size; - bool is_signed; - double factor, offset; - bool is_little_endian; - double min, max; - QString unit; - QString comment; - ValueDescription val_desc; - int precision = 0; - void updatePrecision(); - QString formatValue(double value) const; - }; - struct Msg { - uint32_t address; - QString name; - uint32_t size; - QString comment; - QList sigs; +class Signal { +public: + Signal() = default; + Signal(const Signal &other) = default; + void update(); + QString formatValue(double value) const; - QList mask; - void updateMask(); + QString name; + int start_bit, msb, lsb, size; + double factor, offset; + bool is_signed; + bool is_little_endian; + double min, max; + QString unit; + QString comment; + ValueDescription val_desc; + int precision = 0; + QColor color; +}; - std::vector getSignals() const; - const cabana::Signal *sig(const QString &sig_name) const { - auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; }); - return it != sigs.end() ? &(*it) : nullptr; - } - }; +class Msg { +public: + Msg() = default; + Msg(const Msg &other) { *this = other; } + ~Msg(); + cabana::Signal *addSignal(const cabana::Signal &sig); + cabana::Signal *updateSignal(const QString &sig_name, const cabana::Signal &sig); + void removeSignal(const QString &sig_name); + Msg &operator=(const Msg &other); + int indexOf(const cabana::Signal *sig) const; + cabana::Signal *sig(const QString &sig_name) const; + QString newSignalName(); + inline const std::vector &getSignals() const { return sigs; } - bool operator==(const cabana::Signal &l, const cabana::Signal &r); - inline bool operator!=(const cabana::Signal &l, const cabana::Signal &r) { return !(l == r); } -} + uint32_t address; + QString name; + uint32_t size; + QString comment; + std::vector sigs; + + QList mask; + void update(); +}; + +bool operator==(const cabana::Signal &l, const cabana::Signal &r); +inline bool operator!=(const cabana::Signal &l, const cabana::Signal &r) { return !(l == r); } + +} // namespace cabana // Helper functions double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig); @@ -89,4 +104,3 @@ void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size); std::pair getSignalRange(const cabana::Signal *s); inline std::vector allDBCNames() { return get_dbc_names(); } inline QString doubleToString(double value) { return QString::number(value, 'g', std::numeric_limits::digits10); } - diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index 2a8d3d2d54..6de00fe77d 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -37,20 +37,18 @@ void DBCFile::open(const QString &content) { m.name = msg.name.c_str(); m.size = msg.size; for (auto &s : msg.sigs) { - m.sigs.push_back({}); - auto &sig = m.sigs.last(); - sig.name = s.name.c_str(); - sig.start_bit = s.start_bit; - sig.msb = s.msb; - sig.lsb = s.lsb; - sig.size = s.size; - sig.is_signed = s.is_signed; - sig.factor = s.factor; - sig.offset = s.offset; - sig.is_little_endian = s.is_little_endian; - sig.updatePrecision(); + auto sig = m.sigs.emplace_back(new cabana::Signal); + sig->name = s.name.c_str(); + sig->start_bit = s.start_bit; + sig->msb = s.msb; + sig->lsb = s.lsb; + sig->size = s.size; + sig->is_signed = s.is_signed; + sig->factor = s.factor; + sig->offset = s.offset; + sig->is_little_endian = s.is_little_endian; } - m.updateMask(); + m.update(); } parseExtraInfo(content); @@ -58,7 +56,7 @@ void DBCFile::open(const QString &content) { } bool DBCFile::save() { - assert (!filename.isEmpty()); + assert(!filename.isEmpty()); if (writeContents(filename)) { cleanupAutoSaveFile(); return true; @@ -90,41 +88,6 @@ bool DBCFile::writeContents(const QString &fn) { return false; } -cabana::Signal *DBCFile::addSignal(const MessageId &id, const cabana::Signal &sig) { - if (auto m = const_cast(msg(id.address))) { - m->sigs.push_back(sig); - m->updateMask(); - return &m->sigs.last(); - } - return nullptr; -} - - cabana::Signal *DBCFile::updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig) { - if (auto m = const_cast(msg(id))) { - if (auto s = (cabana::Signal *)m->sig(sig_name)) { - *s = sig; - m->updateMask(); - return s; - } - } - return nullptr; -} - -cabana::Signal *DBCFile::getSignal(const MessageId &id, const QString &sig_name) { - auto m = msg(id); - return m ? (cabana::Signal *)m->sig(sig_name) : nullptr; -} - -void DBCFile::removeSignal(const MessageId &id, const QString &sig_name) { - if (auto m = const_cast(msg(id))) { - auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [&](auto &s) { return s.name == sig_name; }); - if (it != m->sigs.end()) { - m->sigs.erase(it); - m->updateMask(); - } - } -} - void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) { auto &m = msgs[id.address]; m.address = id.address; @@ -133,60 +96,17 @@ void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size, m.comment = comment; } -void DBCFile::removeMsg(const MessageId &id) { - msgs.erase(id.address); -} - -QString DBCFile::newMsgName(const MessageId &id) { - return QString("NEW_MSG_") + QString::number(id.address, 16).toUpper(); -} - -QString DBCFile::newSignalName(const MessageId &id) { - auto m = msg(id); - assert(m != nullptr); - - QString name; - for (int i = 1; /**/; ++i) { - name = QString("NEW_SIGNAL_%1").arg(i); - if (m->sig(name) == nullptr) break; - } - return name; -} - -const QList& DBCFile::mask(const MessageId &id) const { - auto m = msg(id); - return m ? m->mask : empty_mask; -} - -const cabana::Msg *DBCFile::msg(uint32_t address) const { +cabana::Msg *DBCFile::msg(uint32_t address) { auto it = msgs.find(address); return it != msgs.end() ? &it->second : nullptr; } -const cabana::Msg* DBCFile::msg(const QString &name) { - auto it = std::find_if(msgs.cbegin(), msgs.cend(), [&name](auto &m) { return m.second.name == name; }); - return it != msgs.cend() ? &(it->second) : nullptr; +cabana::Msg *DBCFile::msg(const QString &name) { + auto it = std::find_if(msgs.begin(), msgs.end(), [&name](auto &m) { return m.second.name == name; }); + return it != msgs.end() ? &(it->second) : nullptr; } -QStringList DBCFile::signalNames() const { - // Used for autocompletion - QStringList ret; - for (auto const& [_, msg] : msgs) { - for (auto sig: msg.getSignals()) { - ret << sig->name; - } - } - ret.sort(); - ret.removeDuplicates(); - return ret; -} - -int DBCFile::signalCount(const MessageId &id) const { - if (msgs.count(id.address) == 0) return 0; - return msgs.at(id.address).sigs.size(); -} - -int DBCFile::signalCount() const { +int DBCFile::signalCount() { return std::accumulate(msgs.cbegin(), msgs.cend(), 0, [](int &n, const auto &m) { return n + m.second.sigs.size(); }); } @@ -194,8 +114,8 @@ void DBCFile::parseExtraInfo(const QString &content) { static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); - static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"([^"]*)\";)"); - static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"([^"]*)\";)"); + static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"([^"]*)\"\s*;)"); + static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"([^"]*)\"\s*;)"); static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))"); int line_num = 0; diff --git a/tools/cabana/dbc/dbcfile.h b/tools/cabana/dbc/dbcfile.h index 1ed9e9cd0a..76e71e189e 100644 --- a/tools/cabana/dbc/dbcfile.h +++ b/tools/cabana/dbc/dbcfile.h @@ -1,9 +1,7 @@ #pragma once #include -#include #include -#include #include "tools/cabana/dbc/dbc.h" @@ -26,30 +24,18 @@ public: void cleanupAutoSaveFile(); QString generateDBC(); - cabana::Signal *addSignal(const MessageId &id, const cabana::Signal &sig); - cabana::Signal *updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig); - cabana::Signal *getSignal(const MessageId &id, const QString &sig_name); - void removeSignal(const MessageId &id, const QString &sig_name); - void updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment); - void removeMsg(const MessageId &id); + inline void removeMsg(const MessageId &id) { msgs.erase(id.address); } - QString newMsgName(const MessageId &id); - QString newSignalName(const MessageId &id); + inline const std::map &getMessages() const { return msgs; } + cabana::Msg *msg(uint32_t address); + cabana::Msg *msg(const QString &name); + inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); } - const QList& mask(const MessageId &id) const; - - inline std::map getMessages() const { return msgs; } - const cabana::Msg *msg(uint32_t address) const; - const cabana::Msg* msg(const QString &name); - inline const cabana::Msg *msg(const MessageId &id) const { return msg(id.address); }; - - QStringList signalNames() const; - int signalCount(const MessageId &id) const; - int signalCount() const; - inline int msgCount() const { return msgs.size(); } - inline QString name() const { return name_.isEmpty() ? "untitled" : name_; } - inline bool isEmpty() const { return (signalCount() == 0) && name_.isEmpty(); } + int signalCount(); + inline int msgCount() { return msgs.size(); } + inline QString name() { return name_.isEmpty() ? "untitled" : name_; } + inline bool isEmpty() { return (signalCount() == 0) && name_.isEmpty(); } QString filename; @@ -57,5 +43,4 @@ private: void parseExtraInfo(const QString &content); std::map msgs; QString name_; - QList empty_mask; }; diff --git a/tools/cabana/dbc/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc index 2176635caa..388844098a 100644 --- a/tools/cabana/dbc/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -1,21 +1,16 @@ #include "tools/cabana/dbc/dbcmanager.h" + #include +#include -bool DBCManager::open(SourceSet s, const QString &dbc_file_name, QString *error) { - for (int i = 0; i < dbc_files.size(); i++) { - auto [ss, dbc_file] = dbc_files[i]; - - // Check if file is already open, and merge sources - if (dbc_file->filename == dbc_file_name) { - dbc_files[i] = {ss | s, dbc_file}; - - emit DBCFileChanged(); - return true; - } - } - +bool DBCManager::open(const SourceSet &sources, const QString &dbc_file_name, QString *error) { try { - dbc_files.push_back({s, new DBCFile(dbc_file_name, this)}); + auto it = std::find_if(dbc_files.begin(), dbc_files.end(), + [&](auto &f) { return f.second && f.second->filename == dbc_file_name; }); + auto file = (it != dbc_files.end()) ? it->second : std::make_shared(dbc_file_name, this); + for (auto s : sources) { + dbc_files[s] = file; + } } catch (std::exception &e) { if (error) *error = e.what(); return false; @@ -25,9 +20,12 @@ bool DBCManager::open(SourceSet s, const QString &dbc_file_name, QString *error) return true; } -bool DBCManager::open(SourceSet s, const QString &name, const QString &content, QString *error) { +bool DBCManager::open(const SourceSet &sources, const QString &name, const QString &content, QString *error) { try { - dbc_files.push_back({s, new DBCFile(name, content, this)}); + auto file = std::make_shared(name, content, this); + for (auto s : sources) { + dbc_files[s] = file; + } } catch (std::exception &e) { if (error) *error = e.what(); return false; @@ -37,263 +35,154 @@ bool DBCManager::open(SourceSet s, const QString &name, const QString &content, return true; } -void DBCManager::close(SourceSet s) { - // Build new list of dbc files, removing the ones that match the sourceset - QList> new_dbc_files; - for (auto entry : dbc_files) { - if (entry.first == s) { - delete entry.second; - } else { - new_dbc_files.push_back(entry); - } +void DBCManager::close(const SourceSet &sources) { + for (auto s : sources) { + dbc_files[s] = nullptr; } - - dbc_files = new_dbc_files; emit DBCFileChanged(); } void DBCManager::close(DBCFile *dbc_file) { - assert(dbc_file != nullptr); - - // Build new list of dbc files, removing the one that matches dbc_file* - QList> new_dbc_files; - for (auto entry : dbc_files) { - if (entry.second == dbc_file) { - delete entry.second; - } else { - new_dbc_files.push_back(entry); - } + for (auto &[_, f] : dbc_files) { + if (f.get() == dbc_file) f = nullptr; } - - dbc_files = new_dbc_files; emit DBCFileChanged(); } void DBCManager::closeAll() { - if (dbc_files.isEmpty()) return; - - while (dbc_files.size()) { - DBCFile *dbc_file = dbc_files.back().second; - dbc_files.pop_back(); - delete dbc_file; - } + dbc_files.clear(); emit DBCFileChanged(); } -void DBCManager::removeSourcesFromFile(DBCFile *dbc_file, SourceSet s) { - assert(dbc_file != nullptr); - - // Build new list of dbc files, for the given dbc_file* remove s from the current sources - QList> new_dbc_files; - for (auto entry : dbc_files) { - if (entry.second == dbc_file) { - SourceSet ss = (entry.first == SOURCE_ALL) ? sources : entry.first; - ss -= s; - if (ss.empty()) { // Close file if no more sources remain - delete dbc_file; - } else { - new_dbc_files.push_back({ss, dbc_file}); - } - } else { - new_dbc_files.push_back(entry); - } - } - - dbc_files = new_dbc_files; - emit DBCFileChanged(); -} - - void DBCManager::addSignal(const MessageId &id, const cabana::Signal &sig) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // Create new DBC? - auto [dbc_sources, dbc_file] = *sources_dbc_file; - - cabana::Signal *s = dbc_file->addSignal(id, sig); - - if (s != nullptr) { - dbc_sources.insert(id.source); - for (uint8_t source : dbc_sources) { - emit signalAdded({.source = source, .address = id.address}, s); + if (auto m = msg(id)) { + if (auto s = m->addSignal(sig)) { + emit signalAdded(id, s); } } } void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // This should be impossible - auto [_, dbc_file] = *sources_dbc_file; - - cabana::Signal *s = dbc_file->updateSignal(id, sig_name, sig); - - if (s != nullptr) { - emit signalUpdated(s); + if (auto m = msg(id)) { + if (auto s = m->updateSignal(sig_name, sig)) { + emit signalUpdated(s); + } } } void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // This should be impossible - auto [_, dbc_file] = *sources_dbc_file; - - cabana::Signal *s = dbc_file->getSignal(id, sig_name); - - if (s != nullptr) { - emit signalRemoved(s); - dbc_file->removeSignal(id, sig_name); + if (auto m = msg(id)) { + if (auto s = m->sig(sig_name)) { + emit signalRemoved(s); + m->removeSignal(sig_name); + } } } void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size, const QString &comment) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // This should be impossible - auto [dbc_sources, dbc_file] = *sources_dbc_file; - + auto dbc_file = findDBCFile(id); + assert(dbc_file); // This should be impossible dbc_file->updateMsg(id, name, size, comment); - - for (uint8_t source : dbc_sources) { - emit msgUpdated({.source = source, .address = id.address}); - } + emit msgUpdated(id); } void DBCManager::removeMsg(const MessageId &id) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // This should be impossible - auto [dbc_sources, dbc_file] = *sources_dbc_file; - + auto dbc_file = findDBCFile(id); + assert(dbc_file); // This should be impossible dbc_file->removeMsg(id); - - for (uint8_t source : dbc_sources) { - emit msgRemoved({.source = source, .address = id.address}); - } + emit msgRemoved(id); } QString DBCManager::newMsgName(const MessageId &id) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // This should be impossible - auto [_, dbc_file] = *sources_dbc_file; - return dbc_file->newMsgName(id); + return QString("NEW_MSG_") + QString::number(id.address, 16).toUpper(); } QString DBCManager::newSignalName(const MessageId &id) { - auto sources_dbc_file = findDBCFile(id); - assert(sources_dbc_file); // This should be impossible - auto [_, dbc_file] = *sources_dbc_file; - return dbc_file->newSignalName(id); + auto m = msg(id); + return m ? m->newSignalName() : ""; } -const QList& DBCManager::mask(const MessageId &id) const { - auto sources_dbc_file = findDBCFile(id); - if (!sources_dbc_file) { - return empty_mask; - } - auto [_, dbc_file] = *sources_dbc_file; - return dbc_file->mask(id); +const QList &DBCManager::mask(const MessageId &id) { + static QList empty_mask; + auto m = msg(id); + return m ? m->mask : empty_mask; } -std::map DBCManager::getMessages(uint8_t source) { - std::map ret; - - auto sources_dbc_file = findDBCFile({.source = source, .address = 0}); - if (!sources_dbc_file) { - return ret; - } - - auto [_, dbc_file] = *sources_dbc_file; - - for (auto &[address, msg] : dbc_file->getMessages()) { - MessageId id = {.source = source, .address = address}; - ret[id] = msg; - } - return ret; +const std::map &DBCManager::getMessages(uint8_t source) { + static std::map empty_msgs; + auto dbc_file = findDBCFile(source); + return dbc_file ? dbc_file->getMessages() : empty_msgs; } -const cabana::Msg *DBCManager::msg(const MessageId &id) const { - auto sources_dbc_file = findDBCFile(id); - if (!sources_dbc_file) { - return nullptr; - } - auto [_, dbc_file] = *sources_dbc_file; - return dbc_file->msg(id); +cabana::Msg *DBCManager::msg(const MessageId &id) { + auto dbc_file = findDBCFile(id); + return dbc_file ? dbc_file->msg(id) : nullptr; } -const cabana::Msg* DBCManager::msg(uint8_t source, const QString &name) { - auto sources_dbc_file = findDBCFile({.source = source, .address = 0}); - if (!sources_dbc_file) { - return nullptr; - } - auto [_, dbc_file] = *sources_dbc_file; - return dbc_file->msg(name); +cabana::Msg *DBCManager::msg(uint8_t source, const QString &name) { + auto dbc_file = findDBCFile(source); + return dbc_file ? dbc_file->msg(name) : nullptr; } -QStringList DBCManager::signalNames() const { +QStringList DBCManager::signalNames() { + // Used for autocompletion QStringList ret; - - for (auto &[_, dbc_file] : dbc_files) { - ret << dbc_file->signalNames(); + for (auto &f : allDBCFiles()) { + for (auto &[_, m] : f->getMessages()) { + for (auto sig : m.getSignals()) { + ret << sig->name; + } + } } - ret.sort(); ret.removeDuplicates(); return ret; } -int DBCManager::signalCount(const MessageId &id) const { - auto sources_dbc_file = findDBCFile(id); - if (!sources_dbc_file) { - return 0; - } - - auto [_, dbc_file] = *sources_dbc_file; - return dbc_file->signalCount(id); +int DBCManager::signalCount(const MessageId &id) { + auto m = msg(id); + return m ? m->sigs.size() : 0; } -int DBCManager::signalCount() const { - int ret = 0; - - for (auto &[_, dbc_file] : dbc_files) { - ret += dbc_file->signalCount(); - } - - return ret; +int DBCManager::signalCount() { + auto files = allDBCFiles(); + return std::accumulate(files.cbegin(), files.cend(), 0, [](int &n, auto &f) { return n + f->signalCount(); }); } -int DBCManager::msgCount() const { - int ret = 0; - - for (auto &[_, dbc_file] : dbc_files) { - ret += dbc_file->msgCount(); - } - - return ret; +int DBCManager::msgCount() { + auto files = allDBCFiles(); + return std::accumulate(files.cbegin(), files.cend(), 0, [](int &n, auto &f) { return n + f->msgCount(); }); } -int DBCManager::dbcCount() const { - return dbc_files.size(); +int DBCManager::dbcCount() { + return allDBCFiles().size(); } -int DBCManager::nonEmptyDBCCount() const { - return std::count_if(dbc_files.cbegin(), dbc_files.cend(), [](auto &f) { return !f.second->isEmpty(); }); +int DBCManager::nonEmptyDBCCount() { + auto files = allDBCFiles(); + return std::count_if(files.cbegin(), files.cend(), [](auto &f) { return !f->isEmpty(); }); } -void DBCManager::updateSources(const SourceSet &s) { - sources = s; -} - -std::optional> DBCManager::findDBCFile(const uint8_t source) const { +DBCFile *DBCManager::findDBCFile(const uint8_t source) { // Find DBC file that matches id.source, fall back to SOURCE_ALL if no specific DBC is found - - for (auto &[source_set, dbc_file] : dbc_files) { - if (source_set.contains(source)) return {{source_set, dbc_file}}; - } - for (auto &[source_set, dbc_file] : dbc_files) { - if (source_set == SOURCE_ALL) return {{sources, dbc_file}}; - } - return {}; + auto it = dbc_files.count(source) ? dbc_files.find(source) : dbc_files.find(-1); + return it != dbc_files.end() ? it->second.get() : nullptr; } -std::optional> DBCManager::findDBCFile(const MessageId &id) const { - return findDBCFile(id.source); +std::set DBCManager::allDBCFiles() { + std::set files; + for (const auto &[_, f] : dbc_files) { + if (f) files.insert(f.get()); + } + return files; +} + +const SourceSet DBCManager::sources(const DBCFile *dbc_file) const { + SourceSet sources; + for (auto &[s, f] : dbc_files) { + if (f.get() == dbc_file) sources.insert(s); + } + return sources; } DBCManager *dbc() { diff --git a/tools/cabana/dbc/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h index ba590ee56e..9af4e0c1cc 100644 --- a/tools/cabana/dbc/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -1,20 +1,15 @@ #pragma once +#include #include -#include +#include -#include -#include -#include -#include -#include - -#include "tools/cabana/dbc/dbc.h" #include "tools/cabana/dbc/dbcfile.h" -typedef QSet SourceSet; -const SourceSet SOURCE_ALL = {}; +typedef std::set SourceSet; +const SourceSet SOURCE_ALL = {-1}; const int INVALID_SOURCE = 0xff; +inline bool operator<(const std::shared_ptr &l, const std::shared_ptr &r) { return l.get() < r.get(); } class DBCManager : public QObject { Q_OBJECT @@ -22,12 +17,11 @@ class DBCManager : public QObject { public: DBCManager(QObject *parent) {} ~DBCManager() {} - bool open(SourceSet s, const QString &dbc_file_name, QString *error = nullptr); - bool open(SourceSet s, const QString &name, const QString &content, QString *error = nullptr); - void close(SourceSet s); + bool open(const SourceSet &sources, const QString &dbc_file_name, QString *error = nullptr); + bool open(const SourceSet &sources, const QString &name, const QString &content, QString *error = nullptr); + void close(const SourceSet &sources); void close(DBCFile *dbc_file); void closeAll(); - void removeSourcesFromFile(DBCFile *dbc_file, SourceSet s); void addSignal(const MessageId &id, const cabana::Signal &sig); void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig); @@ -38,31 +32,23 @@ public: QString newMsgName(const MessageId &id); QString newSignalName(const MessageId &id); + const QList& mask(const MessageId &id); - const QList& mask(const MessageId &id) const; + const std::map &getMessages(uint8_t source); + cabana::Msg *msg(const MessageId &id); + cabana::Msg* msg(uint8_t source, const QString &name); - std::map getMessages(uint8_t source); - const cabana::Msg *msg(const MessageId &id) const; - const cabana::Msg* msg(uint8_t source, const QString &name); + QStringList signalNames(); + int signalCount(const MessageId &id); + int signalCount(); + int msgCount(); + int dbcCount(); + int nonEmptyDBCCount(); - QStringList signalNames() const; - int signalCount(const MessageId &id) const; - int signalCount() const; - int msgCount() const; - int dbcCount() const; - int nonEmptyDBCCount() const; - - std::optional> findDBCFile(const uint8_t source) const; - std::optional> findDBCFile(const MessageId &id) const; - - QList> dbc_files; - -private: - SourceSet sources; - QList empty_mask; - -public slots: - void updateSources(const SourceSet &s); + const SourceSet sources(const DBCFile *dbc_file) const; + DBCFile *findDBCFile(const uint8_t source); + inline DBCFile *findDBCFile(const MessageId &id) { return findDBCFile(id.source); } + std::set allDBCFiles(); signals: void signalAdded(MessageId id, const cabana::Signal *sig); @@ -71,6 +57,9 @@ signals: void msgUpdated(MessageId id); void msgRemoved(MessageId id); void DBCFileChanged(); + +private: + std::map> dbc_files; }; DBCManager *dbc(); @@ -80,16 +69,10 @@ inline QString msgName(const MessageId &id) { return msg ? msg->name : UNTITLED; } -inline QString toString(SourceSet ss) { - if (ss == SOURCE_ALL) { - return "all"; - } else { - QStringList ret; - QList source_list = ss.values(); - std::sort(source_list.begin(), source_list.end()); - for (auto s : source_list) { - ret << QString::number(s); - } - return ret.join(", "); +inline QString toString(const SourceSet &ss) { + QStringList ret; + for (auto s : ss) { + ret << (s == -1 ? QString("all") : QString::number(s)); } + return ret.join(", "); } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 01c1f31645..eb8bada69e 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -64,7 +64,7 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i } } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { // Alpha-blend the signal color with the background to ensure contrast - QColor sigColor = getColor(sigs[section - 1]); + QColor sigColor = sigs[section - 1]->color; sigColor.setAlpha(128); return QBrush(sigColor); } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 1f8c157f21..2dea698f68 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -62,7 +62,7 @@ public: uint64_t last_fetch_time = 0; std::function filter_cmp = nullptr; std::deque messages; - std::vector sigs; + std::vector sigs; bool dynamic_mode = true; bool display_signals_mode = true; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 421bb9a5d7..3ae26106cf 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -353,7 +353,6 @@ void MainWindow::streamStarted() { QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::eventsMerged); - QObject::connect(can, &AbstractStream::sourcesUpdated, dbc(), &DBCManager::updateSources); QObject::connect(can, &AbstractStream::sourcesUpdated, this, &MainWindow::updateLoadSaveMenus); } @@ -374,7 +373,7 @@ void MainWindow::eventsMerged() { void MainWindow::save() { // Save all open DBC files - for (auto &[s, dbc_file] : dbc()->dbc_files) { + for (auto dbc_file : dbc()->allDBCFiles()) { if (dbc_file->isEmpty()) continue; saveFile(dbc_file); } @@ -382,7 +381,7 @@ void MainWindow::save() { void MainWindow::saveAs() { // Save as all open DBC files. Should not be called with more than 1 file open - for (auto &[s, dbc_file] : dbc()->dbc_files) { + for (auto dbc_file : dbc()->allDBCFiles()) { if (dbc_file->isEmpty()) continue; saveFileAs(dbc_file); } @@ -390,7 +389,7 @@ void MainWindow::saveAs() { void MainWindow::autoSave() { if (!UndoStack::instance()->isClean()) { - for (auto &[_, dbc_file] : dbc()->dbc_files) { + for (auto dbc_file : dbc()->allDBCFiles()) { if (!dbc_file->filename.isEmpty()) { dbc_file->autoSave(); } @@ -399,7 +398,7 @@ void MainWindow::autoSave() { } void MainWindow::cleanupAutoSaveFile() { - for (auto &[_, dbc_file] : dbc()->dbc_files) { + for (auto dbc_file : dbc()->allDBCFiles()) { dbc_file->cleanupAutoSaveFile(); } } @@ -436,9 +435,7 @@ void MainWindow::saveFile(DBCFile *dbc_file) { } void MainWindow::saveFileAs(DBCFile *dbc_file) { - auto it = std::find_if(dbc()->dbc_files.begin(), dbc()->dbc_files.end(), [=](auto &f) { return f.second == dbc_file; }); - assert(it != dbc()->dbc_files.end()); - QString title = tr("Save File (bus: %1)").arg(toString(it->first)); + QString title = tr("Save File (bus: %1)").arg(toString(dbc()->sources(dbc_file))); QString fn = QFileDialog::getSaveFileName(this, title, QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); if (!fn.isEmpty()) { dbc_file->saveAs(fn); @@ -447,15 +444,9 @@ void MainWindow::saveFileAs(DBCFile *dbc_file) { } } -void MainWindow::removeBusFromFile(DBCFile *dbc_file, uint8_t source) { - assert(dbc_file != nullptr); - SourceSet ss = {source, uint8_t(source + 128), uint8_t(source + 192)}; - dbc()->removeSourcesFromFile(dbc_file, ss); -} - void MainWindow::saveToClipboard() { // Copy all open DBC files to clipboard. Should not be called with more than 1 file open - for (auto &[s, dbc_file] : dbc()->dbc_files) { + for (auto dbc_file : dbc()->allDBCFiles()) { if (dbc_file->isEmpty()) continue; saveFileToClipboard(dbc_file); } @@ -480,13 +471,10 @@ void MainWindow::updateLoadSaveMenus() { // TODO: Support clipboard for multiple files copy_dbc_to_clipboard->setEnabled(cnt == 1); - QList sources_sorted = can->sources.toList(); - std::sort(sources_sorted.begin(), sources_sorted.end()); - manage_dbcs_menu->clear(); manage_dbcs_menu->setEnabled(dynamic_cast(can) == nullptr); - for (uint8_t source : sources_sorted) { + for (uint8_t source : can->sources) { if (source >= 64) continue; // Sent and blocked buses are handled implicitly SourceSet ss = {source, uint8_t(source + 128), uint8_t(source + 192)}; @@ -497,32 +485,26 @@ void MainWindow::updateLoadSaveMenus() { bus_menu->addAction(tr("Load DBC From Clipboard..."), [=]() { loadFromClipboard(ss, false); }); // Show sub-menu for each dbc for this source. - QStringList bus_menu_fns; - for (auto it : dbc()->dbc_files) { - auto &[src, dbc_file] = it; - if (!src.contains(source) && (src != SOURCE_ALL)) { - continue; - } - + QString file_name = "No DBCs loaded"; + if (auto dbc_file = dbc()->findDBCFile(source)) { bus_menu->addSeparator(); - bus_menu->addAction(dbc_file->name() + " (" + toString(src) + ")")->setEnabled(false); - bus_menu->addAction(tr("Save..."), [=]() { saveFile(it.second); }); - bus_menu->addAction(tr("Save As..."), [=]() { saveFileAs(it.second); }); - bus_menu->addAction(tr("Copy to Clipboard..."), [=]() { saveFileToClipboard(it.second); }); - bus_menu->addAction(tr("Remove from this bus..."), [=]() { removeBusFromFile(it.second, source); }); - bus_menu->addAction(tr("Remove from all buses..."), [=]() { closeFile(it.second); }); + bus_menu->addAction(dbc_file->name() + " (" + toString(dbc()->sources(dbc_file)) + ")")->setEnabled(false); + bus_menu->addAction(tr("Save..."), [=]() { saveFile(dbc_file); }); + bus_menu->addAction(tr("Save As..."), [=]() { saveFileAs(dbc_file); }); + bus_menu->addAction(tr("Copy to Clipboard..."), [=]() { saveFileToClipboard(dbc_file); }); + bus_menu->addAction(tr("Remove from this bus..."), [=]() { closeFile(ss); }); + bus_menu->addAction(tr("Remove from all buses..."), [=]() { closeFile(dbc_file); }); - bus_menu_fns << dbc_file->name(); + file_name = dbc_file->name(); } manage_dbcs_menu->addMenu(bus_menu); - QString bus_menu_title = bus_menu_fns.size() ? bus_menu_fns.join(", ") : "No DBCs loaded"; - bus_menu->setTitle(tr("Bus %1 (%2)").arg(source).arg(bus_menu_title)); + bus_menu->setTitle(tr("Bus %1 (%2)").arg(source).arg(file_name)); } QStringList title; - for (auto &[src, dbc_file] : dbc()->dbc_files) { - title.push_back(tr("(%1) %2").arg(toString(src), dbc_file->name())); + for (auto f : dbc()->allDBCFiles()) { + title.push_back(tr("(%1) %2").arg(toString(dbc()->sources(f)), f->name())); } setWindowFilePath(title.join(" | ")); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 77467e2e45..bbbe8730cb 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -50,7 +50,6 @@ protected: void saveFile(DBCFile *dbc_file); void saveFileAs(DBCFile *dbc_file); void saveFileToClipboard(DBCFile *dbc_file); - void removeBusFromFile(DBCFile *dbc_file, uint8_t source); void loadFromClipboard(SourceSet s = SOURCE_ALL, bool close_all = true); void autoSave(); void cleanupAutoSaveFile(); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index e24e8ab291..94b539505c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -273,7 +273,7 @@ bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, co case Column::NAME: { const auto msg = dbc()->msg(id); match = re.match(msg ? msg->name : UNTITLED).hasMatch(); - match |= msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), [&re](const auto &s) { return re.match(s.name).hasMatch(); }); + match |= msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), [&re](const auto &s) { return re.match(s->name).hasMatch(); }); break; } case Column::SOURCE: diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 98cd08a690..3fda5796d4 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -171,7 +171,6 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r case Item::Desc: s.val_desc = value.value(); break; default: return false; } - s.updatePrecision(); bool ret = saveSignal(item->sig, s); emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole}); return ret; @@ -249,17 +248,14 @@ void SignalModel::removeSignal(const cabana::Signal *sig) { } void SignalModel::handleMsgChanged(MessageId id) { - if (id == msg_id) { + if (id.address == msg_id.address) { refresh(); } } void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) { if (id == msg_id) { - int i = 0; - for (; i < root->children.size(); ++i) { - if (sig->start_bit < root->children[i]->sig->start_bit) break; - } + int i = dbc()->msg(msg_id)->indexOf(sig); beginInsertRows({}, i, i); insertItem(root.get(), i, sig); endInsertRows(); @@ -348,7 +344,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op path.addRoundedRect(icon_rect, 3, 3); painter->setPen(item->highlight ? Qt::white : Qt::black); painter->setFont(label_font); - painter->fillPath(path, getColor(item->sig).darker(item->highlight ? 125 : 0)); + painter->fillPath(path, item->sig->color.darker(item->highlight ? 125 : 0)); painter->drawText(icon_rect, Qt::AlignCenter, QString::number(item->row() + 1)); r.setLeft(icon_rect.right() + h_margin * 2); diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index abbb3dbf13..01b8dd7081 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -78,7 +78,7 @@ BO_ 160 message_1: 8 XXX VAL_ 160 signal_1 0 "disabled" 1.2 "initializing" 2 "fault"; -CM_ BO_ 160 "message comment"; +CM_ BO_ 160 "message comment" ; CM_ SG_ 160 signal_1 "signal comment"; CM_ SG_ 160 signal_2 "multiple line comment 1 @@ -94,19 +94,19 @@ CM_ SG_ 160 signal_2 "multiple line comment REQUIRE(msg->sigs.size() == 2); REQUIRE(file.msg("message_1") != nullptr); - auto &sig_1 = msg->sigs[0]; - REQUIRE(sig_1.name == "signal_1"); - REQUIRE(sig_1.start_bit == 0); - REQUIRE(sig_1.size == 12); - REQUIRE(sig_1.min == 0); - REQUIRE(sig_1.max == 4095); - REQUIRE(sig_1.unit == "unit"); - REQUIRE(sig_1.comment == "signal comment"); - REQUIRE(sig_1.val_desc.size() == 3); - REQUIRE(sig_1.val_desc[0] == std::pair{0, "disabled"}); - REQUIRE(sig_1.val_desc[1] == std::pair{1.2, "initializing"}); - REQUIRE(sig_1.val_desc[2] == std::pair{2, "fault"}); + auto sig_1 = msg->sigs[0]; + REQUIRE(sig_1->name == "signal_1"); + REQUIRE(sig_1->start_bit == 0); + REQUIRE(sig_1->size == 12); + REQUIRE(sig_1->min == 0); + REQUIRE(sig_1->max == 4095); + REQUIRE(sig_1->unit == "unit"); + REQUIRE(sig_1->comment == "signal comment"); + REQUIRE(sig_1->val_desc.size() == 3); + REQUIRE(sig_1->val_desc[0] == std::pair{0, "disabled"}); + REQUIRE(sig_1->val_desc[1] == std::pair{1.2, "initializing"}); + REQUIRE(sig_1->val_desc[2] == std::pair{2, "fault"}); auto &sig_2 = msg->sigs[1]; - REQUIRE(sig_2.comment == "multiple line comment\n1\n2"); + REQUIRE(sig_2->comment == "multiple line comment\n1\n2"); } diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index add4ee7928..5eb4d7fb86 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -24,14 +24,12 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi for (uint8_t bus : can->sources) { cb->addItem(QString::number(bus), bus); } - cb->model()->sort(0); - cb->setCurrentIndex(0); } msg_cb = new QComboBox(this); // TODO: update when src_bus_combo changes - for (auto &[id, msg] : dbc()->getMessages(0)) { - msg_cb->addItem(msg.name, id.address); + for (auto &[address, msg] : dbc()->getMessages(0)) { + msg_cb->addItem(msg.name, address); } msg_cb->model()->sort(0); msg_cb->setCurrentIndex(0); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 2660ae6837..b0bba891db 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -1,5 +1,6 @@ #include "tools/cabana/util.h" +#include #include #include #include @@ -144,17 +145,6 @@ void TabBar::closeTabClicked() { } } -QColor getColor(const cabana::Signal *sig) { - float h = 19 * (float)sig->lsb / 64.0; - h = fmod(h, 1.0); - - size_t hash = qHash(sig->name); - float s = 0.25 + 0.25 * (float)(hash & 0xff) / 255.0; - float v = 0.75 + 0.25 * (float)((hash >> 8) & 0xff) / 255.0; - - return QColor::fromHsvF(h, s, v); -} - NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) {} QValidator::State NameValidator::validate(QString &input, int &pos) const { @@ -237,10 +227,6 @@ QString toHex(uint8_t byte) { int num_decimals(double num) { const QString string = QString::number(num); - const QStringList split = string.split('.'); - if (split.size() == 1) { - return 0; - } else { - return split[1].size(); - } + auto dot_pos = string.indexOf('.'); + return dot_pos == -1 ? 0 : string.size() - dot_pos - 1; } diff --git a/tools/cabana/util.h b/tools/cabana/util.h index fed8ba94c3..4358190bc3 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -2,12 +2,10 @@ #include -#include #include #include #include #include -#include #include #include #include @@ -22,7 +20,7 @@ class LogSlider : public QSlider { Q_OBJECT public: - LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {}; + LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {} void setRange(double min, double max) { log_min = factor * std::log10(min); @@ -81,7 +79,6 @@ private: inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } QString toHex(uint8_t byte); -QColor getColor(const cabana::Signal *sig); class NameValidator : public QRegExpValidator { Q_OBJECT From 9295aca8eaebaadbc7ec96e82ece55dcaa3b668e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Jun 2023 07:03:18 +0800 Subject: [PATCH 192/283] ui: disable longitudinal personality settings when using stock long (#28443) * disable longitdinal personality settings * disable title label * Revert "disable title label" This reverts commit ef315ac2770191f1309f774185266e0cd9fe54b0. * gray checked button on disable --- selfdrive/ui/qt/offroad/settings.cc | 4 +++- selfdrive/ui/qt/offroad/settings.h | 1 + selfdrive/ui/qt/widgets/controls.h | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 64bf44d2ce..a165f34144 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -91,7 +91,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { std::vector longi_button_texts{tr("Aggressive"), tr("Standard"), tr("Relaxed")}; - ButtonParamControl* long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), + long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), tr("Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars."), "../assets/offroad/icon_speed_limit.png", longi_button_texts); @@ -143,6 +143,7 @@ void TogglesPanel::updateToggles() { .arg(tr("New Driving Visualization")) .arg(tr("The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.")); + long_personality_setting->setEnabled(false); const bool is_release = params.getBool("IsReleaseBranch"); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { @@ -161,6 +162,7 @@ void TogglesPanel::updateToggles() { // normal description and toggle e2e_toggle->setEnabled(true); e2e_toggle->setDescription(e2e_description); + long_personality_setting->setEnabled(true); } else { // no long for now e2e_toggle->setEnabled(false); diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index c63be4e138..e35811fdc8 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -64,6 +64,7 @@ public slots: private: Params params; std::map toggles; + ButtonParamControl *long_personality_setting; void updateToggles(); }; diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 654c6e2c1c..807441cc85 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -216,14 +216,17 @@ public: QPushButton:pressed { background-color: #4a4a4a; } - QPushButton:checked { + QPushButton:checked:enabled { background-color: #33Ab4C; } + QPushButton:disabled { + color: #33E4E4E4; + } )"; key = param.toStdString(); int value = atoi(params.get(key).c_str()); - QButtonGroup *button_group = new QButtonGroup(this); + button_group = new QButtonGroup(this); button_group->setExclusive(true); for (int i = 0; i < button_texts.size(); i++) { QPushButton *button = new QPushButton(button_texts[i], this); @@ -242,9 +245,16 @@ public: }); } + void setEnabled(bool enable) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enable); + } + } + private: std::string key; Params params; + QButtonGroup *button_group; }; class ListWidget : public QWidget { From f3299b19cf85031b93d3b53f4378e6dac444b723 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 8 Jun 2023 16:08:20 -0700 Subject: [PATCH 193/283] pj: fix camera timings layout default tab --- tools/plotjuggler/layouts/camera-timings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/plotjuggler/layouts/camera-timings.xml b/tools/plotjuggler/layouts/camera-timings.xml index 5cc1650909..f91cbd3f53 100644 --- a/tools/plotjuggler/layouts/camera-timings.xml +++ b/tools/plotjuggler/layouts/camera-timings.xml @@ -132,7 +132,7 @@ - + From 6bb61780ab48973c65086bd34185ee811eb6f0ec Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 8 Jun 2023 19:36:23 -0700 Subject: [PATCH 194/283] params: make ForcePowerDown persistent (#28460) --- common/params.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/params.cc b/common/params.cc index 843c57c564..be285c6aa2 100644 --- a/common/params.cc +++ b/common/params.cc @@ -113,7 +113,7 @@ std::unordered_map keys = { {"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START}, {"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"ForcePowerDown", CLEAR_ON_MANAGER_START}, + {"ForcePowerDown", PERSISTENT}, {"GitBranch", PERSISTENT}, {"GitCommit", PERSISTENT}, {"GitDiff", PERSISTENT}, From 6bf1f81859bc03456a9a49245b434dbd35cc4442 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 8 Jun 2023 19:50:49 -0700 Subject: [PATCH 195/283] boardd: log system and RTC time before sync (#28461) --- selfdrive/boardd/boardd.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 6f293d1c0d..4205d84781 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -94,11 +94,12 @@ void sync_time(Panda *panda, SyncTimeDir dir) { } } } else if (dir == SyncTimeDir::FROM_PANDA) { + LOGW("System time: %s, RTC time: %s", get_time_str(sys_time).c_str(), get_time_str(rtc_time).c_str()); + if (!util::time_valid(sys_time) && util::time_valid(rtc_time)) { const struct timeval tv = {mktime(&rtc_time), 0}; settimeofday(&tv, 0); - LOGE("System time wrong, setting from RTC. System: %s RTC: %s", - get_time_str(sys_time).c_str(), get_time_str(rtc_time).c_str()); + LOGE("System time wrong, setting from RTC."); } } } From 5736cb8a7ec2aab91a7b7d61908e8827e6031d51 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 8 Jun 2023 19:53:45 -0700 Subject: [PATCH 196/283] FPv2: fix accidental FW version concatenation (#28462) * fix missing commas * more * Revert "more" This reverts commit ebe481fee44f284a598ad9d5a83da37653faee99. * only --- selfdrive/car/hyundai/values.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index ba0fefca00..86ebaabf04 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -752,7 +752,7 @@ FW_VERSIONS = { b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409', b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8A12', b'\xf1\x00TM MDPS C 1.00 1.01 56340-S2000 9129', - b'\xf1\x00TM MDPS R 1.00 1.02 57700-S1100 4TMDP102' + b'\xf1\x00TM MDPS R 1.00 1.02 57700-S1100 4TMDP102', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00TM MFC AT EUR LHD 1.00 1.01 99211-S1010 181207', @@ -854,7 +854,7 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00TMH MFC AT EUR LHD 1.00 1.06 99211-S1500 220727', b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224', - b'\xf1\x00TMH MFC AT USA LHD 1.00 1.06 99211-S1500 220727' + b'\xf1\x00TMH MFC AT USA LHD 1.00 1.06 99211-S1500 220727', b'\xf1\x00TMA MFC AT USA LHD 1.00 1.03 99211-S2500 220414', ], (Ecu.transmission, 0x7e1, None): [ From 3234243c97c7c6bf6fb4bb1298a7fd262e697c04 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 8 Jun 2023 20:47:55 -0700 Subject: [PATCH 197/283] FPv2: add comment about nuance of fuzzy fingerprinting (#28465) add comment describing this nuance of fuzzy fingerprint function --- selfdrive/car/fw_versions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index ca75ed62e5..bfb65f7a12 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -91,6 +91,8 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): elif candidate != candidates[0]: return set() + # Note that it is possible to match to a candidate without all its ECUs being present + # if there are enough matches. FIXME: parameterize this or require all ECUs to exist like exact matching if len(matched_ecus) >= 2: if log: cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {len(matched_ecus)} matching ECUs") From f210b2da08cd2cf95cd6f47b33d83febd772b3ac Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 8 Jun 2023 21:05:38 -0700 Subject: [PATCH 198/283] Update SSH README --- tools/ssh/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/ssh/README.md b/tools/ssh/README.md index 67b5271a42..588ea71579 100644 --- a/tools/ssh/README.md +++ b/tools/ssh/README.md @@ -24,14 +24,12 @@ The `id_rsa` key in this directory only works while your device is in the setup See the [community wiki](https://github.com/commaai/openpilot/wiki/SSH) for more detailed instructions and information. # Connecting to ssh.comma.ai -SSH into your comma device from anywhere with `ssh.comma.ai`. +SSH into your comma device from anywhere with `ssh.comma.ai`. Requires a [comma prime subscription](https://comma.ai/connect). ## Setup With software version 0.6.1 or newer, enter your GitHub username on your device under Developer Settings. Your GitHub authorized public keys will become your authorized SSH keys for `ssh.comma.ai`. You can add any additional keys in `/system/comma/home/.ssh/authorized_keys.persist`. -Requires [comma SIM with comma prime](https://comma.ai/shop) activated with comma connect, available on iOS and Android. comma two and EON ship with a pre-inserted comma SIM. - ## Recommended .ssh/config With the below SSH configuration, you can type `ssh comma-{dongleid}` to connect to your device through `ssh.comma.ai`.
From 0e67d41eef5fd39c57c5c75f181194ebff85a252 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 10 Jun 2023 01:50:25 +0800 Subject: [PATCH 199/283] cabana: fix bg color issue for inactive item (#28468) --- tools/cabana/signalview.cc | 2 +- tools/cabana/util.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 3fda5796d4..46dfef1004 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -331,7 +331,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (item && item->type == SignalModel::Item::Sig) { painter->setRenderHint(QPainter::Antialiasing); if (option.state & QStyle::State_Selected) { - painter->fillRect(option.rect, option.palette.highlight()); + painter->fillRect(option.rect, option.palette.brush(QPalette::Normal, QPalette::Highlight)); } int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index b0bba891db..7a606b133e 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -96,7 +96,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); if (option.state & QStyle::State_Selected) { - painter->fillRect(option.rect, option.palette.highlight()); + painter->fillRect(option.rect, option.palette.brush(QPalette::Normal, QPalette::Highlight)); } const QPoint pt{option.rect.left() + h_margin, option.rect.top() + v_margin}; From b2288b366697a7ac16323e06419243a1785b371b Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Sat, 10 Jun 2023 02:54:39 +0900 Subject: [PATCH 200/283] kor translation update (#28469) --- selfdrive/ui/translations/main_ko.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index b751e9cf57..1936805aa5 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1053,23 +1053,23 @@ This may take up to a minute.
Aggressive - + 공격적 Standard - + 표준 Relaxed - + 편안한 Driving Personality - + 주행 모드 Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. - + 표준 모드를 권장합니다. 공격적 모드에서는 openpilot은 앞차를 더 가까이 따라가며 가속과 감속을 더 공격적으로 사용합니다. 편안한 모드에서 openpilot은 선두 차량에서 더 멀리 떨어져 있습니다.
From 376144dca3ed6875fa8b2cc2ccfea5593ae85e78 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 10 Jun 2023 01:54:52 +0800 Subject: [PATCH 201/283] cabana: add "view" menu to the menu bar (#28467) --- tools/cabana/mainwin.cc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 3ae26106cf..f424a3eecf 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -77,6 +77,7 @@ MainWindow::MainWindow() : QMainWindow() { } void MainWindow::createActions() { + // File menu QMenu *file_menu = menuBar()->addMenu(tr("&File")); file_menu->addAction(tr("Open Stream..."), this, &MainWindow::openStream); close_stream_act = file_menu->addAction(tr("Close stream"), this, &MainWindow::closeStream); @@ -124,6 +125,7 @@ void MainWindow::createActions() { file_menu->addSeparator(); file_menu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows)->setShortcuts(QKeySequence::Quit); + // Edit Menu QMenu *edit_menu = menuBar()->addMenu(tr("&Edit")); auto undo_act = UndoStack::instance()->createUndoAction(this, tr("&Undo")); undo_act->setShortcuts(QKeySequence::Undo); @@ -138,14 +140,22 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(new QUndoView(UndoStack::instance())); commands_menu->addAction(commands_act); - edit_menu->addSeparator(); - edit_menu->addAction(tr("Reset Window Layout"), - [this]() { restoreState(default_state); }); + // View Menu + QMenu *view_menu = menuBar()->addMenu(tr("&View")); + auto act = view_menu->addAction(tr("Full Screen"), this, &MainWindow::toggleFullScreen, QKeySequence::FullScreen); + addAction(act); + view_menu->addSeparator(); + view_menu->addAction(messages_dock->toggleViewAction()); + view_menu->addAction(video_dock->toggleViewAction()); + view_menu->addSeparator(); + view_menu->addAction(tr("Reset Window Layout"), [this]() { restoreState(default_state); }); + // Tools Menu tools_menu = menuBar()->addMenu(tr("&Tools")); tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); tools_menu->addAction(tr("&Find Signal"), this, &MainWindow::findSignal); + // Help Menu QMenu *help_menu = menuBar()->addMenu(tr("&Help")); help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents); help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); @@ -155,13 +165,13 @@ void MainWindow::createDockWindows() { messages_dock = new QDockWidget(tr("MESSAGES"), this); messages_dock->setObjectName("MessagesPanel"); messages_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); - messages_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + messages_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); addDockWidget(Qt::LeftDockWidgetArea, messages_dock); video_dock = new QDockWidget("", this); video_dock->setObjectName(tr("VideoPanel")); video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); addDockWidget(Qt::RightDockWidgetArea, video_dock); } @@ -206,8 +216,6 @@ void MainWindow::createStatusBar() { void MainWindow::createShortcuts() { auto shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this, nullptr, nullptr, Qt::ApplicationShortcut); QObject::connect(shortcut, &QShortcut::activated, []() { can->pause(!can->isPaused()); }); - shortcut = new QShortcut(QKeySequence(QKeySequence::FullScreen), this, nullptr, nullptr, Qt::ApplicationShortcut); - QObject::connect(shortcut, &QShortcut::activated, this, &MainWindow::toggleFullScreen); // TODO: add more shortcuts here. } From 7a64385fcd5354efd3bd9dcf6972669c46d99c10 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Jun 2023 11:20:42 -0700 Subject: [PATCH 202/283] Honda: set autoResumeSng for docs (#28458) set autoResumeSng for Honda --- docs/CARS.md | 20 ++++++++++---------- selfdrive/car/honda/interface.py | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 373851932f..a4af5fc4c0 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -8,8 +8,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -55,20 +55,20 @@ A supported vehicle is one that just works when you install a comma three. All s |Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 2c936cf3b6..11eff61b33 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -292,8 +292,8 @@ class CarInterface(CarInterfaceBase): # min speed to enable ACC. if car can do stop and go, then set enabling speed # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not # conflict with PCM acc - stop_and_go = candidate in (HONDA_BOSCH | {CAR.CIVIC}) or ret.enableGasInterceptor - ret.minEnableSpeed = -1. if stop_and_go else 25.5 * CV.MPH_TO_MS + ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.CIVIC}) or ret.enableGasInterceptor + ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.5 * CV.MPH_TO_MS # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors From 181b44b28ea51429e270eb2c7a0cac20a871f214 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 9 Jun 2023 14:13:22 -0700 Subject: [PATCH 203/283] car docs: test print_docs_diff (#28459) * test print docs * delete * remove this * print --- selfdrive/car/tests/test_docs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py index f42c094856..7ea9f6c9fe 100755 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -1,12 +1,16 @@ #!/usr/bin/env python3 from collections import defaultdict +import os import re import unittest +from common.basedir import BASEDIR from selfdrive.car.car_helpers import interfaces, get_interface_attr from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info from selfdrive.car.docs_definitions import Cable, Column, PartType, Star from selfdrive.car.honda.values import CAR as HONDA +from selfdrive.debug.dump_car_info import dump_car_info +from selfdrive.debug.print_docs_diff import print_car_info_diff class TestCarDocs(unittest.TestCase): @@ -22,6 +26,12 @@ class TestCarDocs(unittest.TestCase): self.assertEqual(generated_cars_md, current_cars_md, "Run selfdrive/car/docs.py to update the compatibility documentation") + def test_docs_diff(self): + dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump") + dump_car_info(dump_path) + print_car_info_diff(dump_path) + os.remove(dump_path) + def test_duplicate_years(self): make_model_years = defaultdict(list) for car in self.all_cars: From d1499fa5d8e28722dbaddae0c5941f9be12013bf Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Jun 2023 14:44:57 -0700 Subject: [PATCH 204/283] bump cereal and panda --- cereal | 2 +- panda | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cereal b/cereal index c331e76b96..44c93ef17c 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit c331e76b966d324a4f8d56b48db44f59601423dc +Subproject commit 44c93ef17cd0973347935b93c67b65ddd5ace22c diff --git a/panda b/panda index 1a9a94c519..b563405904 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 1a9a94c519cb74e9e0f57bea4d316a54c27ea8aa +Subproject commit b56340590485bba2428538259e020f176127458c From a412cd07b105807a3fcd5fdc8b9caae0e227cf06 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Jun 2023 15:36:15 -0700 Subject: [PATCH 205/283] cloudlog process not running (#28472) * cloudlog process not running * error --- selfdrive/controls/controlsd.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 3903340c8d..82c66a20f9 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -170,6 +170,7 @@ class Controls: self.events_prev = [] self.current_alert_types = [ET.PERMANENT] self.logged_comm_issue = None + self.not_running_prev = None self.last_actuators = car.CarControl.Actuators.new_message() self.steer_limited = False self.desired_curvature = 0.0 @@ -330,6 +331,9 @@ class Controls: not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning} if self.sm.rcv_frame['managerState'] and (not_running - IGNORE_PROCESSES): self.events.add(EventName.processNotRunning) + if not_running != self.not_running_prev: + cloudlog.event("process_not_running", not_running=not_running, error=True) + self.not_running_prev = not_running else: if not SIMULATION and not self.rk.lagging: if not self.sm.all_alive(self.camera_packets): From dec3c5a57d5893bd2f456fc88d3799300095a02e Mon Sep 17 00:00:00 2001 From: Comma Device Date: Fri, 9 Jun 2023 15:36:41 -0700 Subject: [PATCH 206/283] test_amp: wait for panda --- system/hardware/tici/tests/test_amplifier.py | 1 + 1 file changed, 1 insertion(+) diff --git a/system/hardware/tici/tests/test_amplifier.py b/system/hardware/tici/tests/test_amplifier.py index 5d5a86c512..4cacef4080 100755 --- a/system/hardware/tici/tests/test_amplifier.py +++ b/system/hardware/tici/tests/test_amplifier.py @@ -21,6 +21,7 @@ class TestAmplifier(unittest.TestCase): # clear dmesg subprocess.check_call("sudo dmesg -C", shell=True) + Panda.wait_for_panda(None, 30) self.panda = Panda() self.panda.reset() From f7f5537af74625e3a08352fef73eebffd4991a49 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 9 Jun 2023 17:08:57 -0700 Subject: [PATCH 207/283] MapPanel cleanup (#28474) --- selfdrive/ui/qt/maps/map_settings.cc | 78 +++++++++++++--------------- selfdrive/ui/qt/maps/map_settings.h | 9 +++- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/selfdrive/ui/qt/maps/map_settings.cc b/selfdrive/ui/qt/maps/map_settings.cc index 3205ca517d..f626925ad4 100644 --- a/selfdrive/ui/qt/maps/map_settings.cc +++ b/selfdrive/ui/qt/maps/map_settings.cc @@ -13,46 +13,46 @@ static QString shorten(const QString &str, int max_len) { } MapPanel::MapPanel(QWidget* parent) : QWidget(parent) { - stack = new QStackedWidget; + QStackedLayout *stack = new QStackedLayout(this); - QWidget * main_widget = new QWidget; + QWidget *main_widget = new QWidget; QVBoxLayout *main_layout = new QVBoxLayout(main_widget); - const int icon_size = 200; - - // Home - QHBoxLayout *home_layout = new QHBoxLayout; - home_button = new QPushButton; - home_button->setIconSize(QSize(icon_size, icon_size)); - home_layout->addWidget(home_button); - - home_address = new QLabel; - home_address->setWordWrap(true); - home_layout->addSpacing(30); - home_layout->addWidget(home_address); - home_layout->addStretch(); - - // Work - QHBoxLayout *work_layout = new QHBoxLayout; - work_button = new QPushButton; - work_button->setIconSize(QSize(icon_size, icon_size)); - work_layout->addWidget(work_button); - - work_address = new QLabel; - work_address->setWordWrap(true); - work_layout->addSpacing(30); - work_layout->addWidget(work_address); - work_layout->addStretch(); + main_layout->setSpacing(20); // Home & Work layout QHBoxLayout *home_work_layout = new QHBoxLayout; - home_work_layout->addLayout(home_layout, 1); - home_work_layout->addSpacing(50); - home_work_layout->addLayout(work_layout, 1); + { + // Home + home_button = new QPushButton; + home_button->setIconSize(QSize(MAP_PANEL_ICON_SIZE, MAP_PANEL_ICON_SIZE)); + home_address = new QLabel; + home_address->setWordWrap(true); + + QHBoxLayout *home_layout = new QHBoxLayout; + home_layout->addWidget(home_button); + home_layout->addSpacing(30); + home_layout->addWidget(home_address); + home_layout->addStretch(); + + // Work + work_button = new QPushButton; + work_button->setIconSize(QSize(MAP_PANEL_ICON_SIZE, MAP_PANEL_ICON_SIZE)); + work_address = new QLabel; + work_address->setWordWrap(true); + + QHBoxLayout *work_layout = new QHBoxLayout; + work_layout->addWidget(work_button); + work_layout->addSpacing(30); + work_layout->addWidget(work_address); + work_layout->addStretch(); + + home_work_layout->addLayout(home_layout, 1); + home_work_layout->addSpacing(50); + home_work_layout->addLayout(work_layout, 1); + } main_layout->addLayout(home_work_layout); - main_layout->addSpacing(20); main_layout->addWidget(horizontal_line()); - main_layout->addSpacing(20); // Current route { @@ -81,7 +81,6 @@ MapPanel::MapPanel(QWidget* parent) : QWidget(parent) { QLabel *recents_title = new QLabel(tr("Recent Destinations")); recents_title->setStyleSheet("font-size: 55px"); main_layout->addWidget(recents_title); - main_layout->addSpacing(20); recent_layout = new QVBoxLayout; QWidget *recent_widget = new LayoutWidget(recent_layout, this); @@ -119,9 +118,6 @@ MapPanel::MapPanel(QWidget* parent) : QWidget(parent) { stack->setCurrentIndex(prime_type ? 0 : 1); }); - QVBoxLayout *wrapper = new QVBoxLayout(this); - wrapper->addWidget(stack); - clear(); @@ -207,8 +203,9 @@ void MapPanel::refresh() { prev_destinations = cur_destinations; clear(); + // add favorites before recents bool has_recents = false; - for (auto &save_type: {"favorite", "recent"}) { + for (auto &save_type: {NAV_TYPE_FAVORITE, NAV_TYPE_RECENT}) { for (auto location : doc.array()) { auto obj = location.toObject(); @@ -219,7 +216,7 @@ void MapPanel::refresh() { if (type != save_type) continue; - if (type == "favorite" && label == "home") { + if (type == NAV_TYPE_FAVORITE && label == NAV_FAVORITE_LABEL_HOME) { home_address->setText(name); home_address->setStyleSheet(R"(font-size: 50px; color: white;)"); home_button->setIcon(QPixmap("../assets/navigation/home.png")); @@ -227,7 +224,7 @@ void MapPanel::refresh() { navigateTo(obj); emit closeSettings(); }); - } else if (type == "favorite" && label == "work") { + } else if (type == NAV_TYPE_FAVORITE && label == NAV_FAVORITE_LABEL_WORK) { work_address->setText(name); work_address->setStyleSheet(R"(font-size: 50px; color: white;)"); work_button->setIcon(QPixmap("../assets/navigation/work.png")); @@ -245,7 +242,7 @@ void MapPanel::refresh() { sp.setRetainSizeWhenHidden(true); star->setSizePolicy(sp); - star->setVisible(type == "favorite"); + star->setVisible(type == NAV_TYPE_FAVORITE); star->setStyleSheet(R"(font-size: 60px;)"); layout->addWidget(star); layout->addSpacing(10); @@ -284,7 +281,6 @@ void MapPanel::refresh() { has_recents = true; } } - } if (!has_recents) { diff --git a/selfdrive/ui/qt/maps/map_settings.h b/selfdrive/ui/qt/maps/map_settings.h index 165673b7c1..8dd044c374 100644 --- a/selfdrive/ui/qt/maps/map_settings.h +++ b/selfdrive/ui/qt/maps/map_settings.h @@ -11,6 +11,14 @@ #include "common/params.h" #include "selfdrive/ui/qt/widgets/controls.h" +const int MAP_PANEL_ICON_SIZE = 200; + +const QString NAV_TYPE_FAVORITE = "favorite"; +const QString NAV_TYPE_RECENT = "recent"; + +const QString NAV_FAVORITE_LABEL_HOME = "home"; +const QString NAV_FAVORITE_LABEL_WORK = "work"; + class MapPanel : public QWidget { Q_OBJECT public: @@ -27,7 +35,6 @@ private: Params params; QString prev_destinations, cur_destinations; - QStackedWidget *stack; QPushButton *home_button, *work_button; QLabel *home_address, *work_address; QVBoxLayout *recent_layout; From 838346d8a3a139a160e3cc602ba38d6f3b09a00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Sat, 10 Jun 2023 04:17:50 +0200 Subject: [PATCH 208/283] process_replay: deprecated message migration (#28456) * Move migration code to new file * Migrate messages in process replay. Remove old code * Fix old_logtime * Keep old logtimes on migrated messages * Update ref commit --- selfdrive/test/process_replay/migration.py | 65 +++++++++++++++++++ .../test/process_replay/process_replay.py | 3 +- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/regen.py | 59 +---------------- 4 files changed, 70 insertions(+), 59 deletions(-) create mode 100644 selfdrive/test/process_replay/migration.py diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py new file mode 100644 index 0000000000..31b3acde56 --- /dev/null +++ b/selfdrive/test/process_replay/migration.py @@ -0,0 +1,65 @@ +from cereal import messaging + + +def migrate_all(lr, old_logtime=False): + msgs = migrate_sensorEvents(lr, old_logtime) + msgs = migrate_carParams(msgs, old_logtime) + + return msgs + + +def migrate_carParams(lr, old_logtime=False): + all_msgs = [] + for msg in lr: + if msg.which() == 'carParams': + CP = messaging.new_message('carParams') + CP.carParams = msg.carParams.as_builder() + for car_fw in CP.carParams.carFw: + car_fw.brand = CP.carParams.carName + if old_logtime: + CP.logMonoTime = msg.logMonoTime + msg = CP.as_reader() + all_msgs.append(msg) + + return all_msgs + + +def migrate_sensorEvents(lr, old_logtime=False): + all_msgs = [] + for msg in lr: + if msg.which() != 'sensorEventsDEPRECATED': + all_msgs.append(msg) + continue + + # migrate to split sensor events + for evt in msg.sensorEventsDEPRECATED: + # build new message for each sensor type + sensor_service = '' + if evt.which() == 'acceleration': + sensor_service = 'accelerometer' + elif evt.which() == 'gyro' or evt.which() == 'gyroUncalibrated': + sensor_service = 'gyroscope' + elif evt.which() == 'light' or evt.which() == 'proximity': + sensor_service = 'lightSensor' + elif evt.which() == 'magnetic' or evt.which() == 'magneticUncalibrated': + sensor_service = 'magnetometer' + elif evt.which() == 'temperature': + sensor_service = 'temperatureSensor' + + m = messaging.new_message(sensor_service) + m.valid = True + if old_logtime: + m.logMonoTime = msg.logMonoTime + + m_dat = getattr(m, sensor_service) + m_dat.version = evt.version + m_dat.sensor = evt.sensor + m_dat.type = evt.type + m_dat.source = evt.source + if old_logtime: + m_dat.timestamp = evt.timestamp + setattr(m_dat, evt.which(), getattr(evt, evt.which())) + + all_msgs.append(m.as_reader()) + + return all_msgs diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 9261aee838..22d1516373 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -18,6 +18,7 @@ from panda.python import ALTERNATIVE_EXPERIENCE from selfdrive.car.car_helpers import get_car, interfaces from selfdrive.manager.process_config import managed_processes from selfdrive.test.process_replay.helpers import OpenpilotPrefix +from selfdrive.test.process_replay.migration import migrate_all # Numpy gives different results based on CPU features after version 19 NUMPY_TOLERANCE = 1e-7 @@ -342,7 +343,7 @@ def replay_process_with_name(name, lr, *args, **kwargs): def replay_process(cfg, lr, fingerprint=None, return_all_logs=False, disable_progress=False): - all_msgs = list(lr) + all_msgs = migrate_all(lr, old_logtime=True) process_logs = _replay_single_process(cfg, all_msgs, fingerprint, disable_progress) if return_all_logs: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 2332054b69..f3a9408671 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3e684aef4483b8d311d71bab3bb543d7bad26563 +67bcd498f0432252a3f11a9fd2b59b344ee214ba diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index cc697bb9bf..18c7e3a8dc 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -20,6 +20,7 @@ from selfdrive.car.toyota.values import EPS_SCALE from selfdrive.manager.process import ensure_running from selfdrive.manager.process_config import managed_processes from selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, setup_env, check_openpilot_enabled +from selfdrive.test.process_replay.migration import migrate_all from selfdrive.test.update_ci_routes import upload_route from tools.lib.route import Route from tools.lib.framereader import FrameReader @@ -179,67 +180,11 @@ def replay_cameras(lr, frs, disable_tqdm=False): return vs, p -def migrate_carparams(lr): - all_msgs = [] - for msg in lr: - if msg.which() == 'carParams': - CP = messaging.new_message('carParams') - CP.carParams = msg.carParams.as_builder() - for car_fw in CP.carParams.carFw: - car_fw.brand = CP.carParams.carName - msg = CP.as_reader() - all_msgs.append(msg) - - return all_msgs - - -def migrate_sensorEvents(lr, old_logtime=False): - all_msgs = [] - for msg in lr: - if msg.which() != 'sensorEventsDEPRECATED': - all_msgs.append(msg) - continue - - # migrate to split sensor events - for evt in msg.sensorEventsDEPRECATED: - # build new message for each sensor type - sensor_service = '' - if evt.which() == 'acceleration': - sensor_service = 'accelerometer' - elif evt.which() == 'gyro' or evt.which() == 'gyroUncalibrated': - sensor_service = 'gyroscope' - elif evt.which() == 'light' or evt.which() == 'proximity': - sensor_service = 'lightSensor' - elif evt.which() == 'magnetic' or evt.which() == 'magneticUncalibrated': - sensor_service = 'magnetometer' - elif evt.which() == 'temperature': - sensor_service = 'temperatureSensor' - - m = messaging.new_message(sensor_service) - m.valid = True - if old_logtime: - m.logMonoTime = msg.logMonoTime - - m_dat = getattr(m, sensor_service) - m_dat.version = evt.version - m_dat.sensor = evt.sensor - m_dat.type = evt.type - m_dat.source = evt.source - if old_logtime: - m_dat.timestamp = evt.timestamp - setattr(m_dat, evt.which(), getattr(evt, evt.which())) - - all_msgs.append(m.as_reader()) - - return all_msgs - - def regen_segment(lr, frs=None, daemons="all", outdir=FAKEDATA, disable_tqdm=False): if not isinstance(daemons, str) and not hasattr(daemons, "__iter__"): raise ValueError("whitelist_proc must be a string or iterable") - lr = migrate_carparams(list(lr)) - lr = migrate_sensorEvents(list(lr)) + lr = migrate_all(lr) if frs is None: frs = dict() From a77d226f33f618b965204c700fd0bfeb5f1547ab Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Jun 2023 20:15:13 -0700 Subject: [PATCH 209/283] thermald: lower threshold to exit red band --- selfdrive/thermald/thermald.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 57387e5186..aa78978619 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -41,7 +41,7 @@ HardwareState = namedtuple("HardwareState", ['network_type', 'network_info', 'ne THERMAL_BANDS = OrderedDict({ ThermalStatus.green: ThermalBand(None, 80.0), ThermalStatus.yellow: ThermalBand(75.0, 96.0), - ThermalStatus.red: ThermalBand(80.0, 107.), + ThermalStatus.red: ThermalBand(88.0, 107.), ThermalStatus.danger: ThermalBand(94.0, None), }) From fc9660c96206220e3b7f4656826fd2a88ea1ad4b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Jun 2023 22:04:56 -0700 Subject: [PATCH 210/283] env: add dateutil types (#28478) * add dateutil types * lock --- poetry.lock | 14 +++++++++++++- pyproject.toml | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index e2ef2fc29e..679d4b40a1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4565,6 +4565,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "types-python-dateutil" +version = "2.8.19.13" +description = "Typing stubs for python-dateutil" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "types-pyyaml" version = "6.0.12" @@ -4804,7 +4812,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "8c0419671beb3e8c8f0add750929f5be32be6fa3f077d44614cbd598b4cadc00" +content-hash = "2e03ebb1f6c441a0154531ee92f6f1f8c9e74544d4295d3753029bb8dcd457d1" [metadata.files] adal = [ @@ -8597,6 +8605,10 @@ types-pycurl = [ {file = "types-pycurl-7.45.1.tar.gz", hash = "sha256:82e00aa2981595bfa55e5a3bac42221eb3435b0026dffbe1177f6ac9f2d51200"}, {file = "types_pycurl-7.45.1-py3-none-any.whl", hash = "sha256:9eab3414da4a1b1e9a628bd288fc5172b8c182e1d9fb6d8d082441b0fd64baed"}, ] +types-python-dateutil = [ + {file = "types-python-dateutil-2.8.19.13.tar.gz", hash = "sha256:09a0275f95ee31ce68196710ed2c3d1b9dc42e0b61cc43acc369a42cb939134f"}, + {file = "types_python_dateutil-2.8.19.13-py3-none-any.whl", hash = "sha256:0b0e7c68e7043b0354b26a1e0225cb1baea7abb1b324d02b50e2d08f1221043f"}, +] types-pyyaml = [ {file = "types-PyYAML-6.0.12.tar.gz", hash = "sha256:f6f350418125872f3f0409d96a62a5a5ceb45231af5cc07ee0034ec48a3c82fa"}, {file = "types_PyYAML-6.0.12-py3-none-any.whl", hash = "sha256:29228db9f82df4f1b7febee06bbfb601677882e98a3da98132e31c6874163e15"}, diff --git a/pyproject.toml b/pyproject.toml index 52dd7f2a02..8877a262ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,6 +106,7 @@ tenacity = "^8.0.1" types-atomicwrites = "^1.4.5" types-certifi = "^2021.10.8" types-pycurl = "^7.45.1" +types-python-dateutil = "^2.8.19.13" types-PyYAML = "^6.0" types-requests = "^2.28.11" types-tabulate = "^0.8.10" From f5e032b67f6e37d2c12dcd90168a2b33b3b78831 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Jun 2023 22:51:55 -0700 Subject: [PATCH 211/283] FwQueryConfig: add platform code support and tests (#28475) * add config options * you know what, platform codes don't need to be related to fuzzy fingerprinting at all * better comment? * add comment * add test from other PR * add platform code function to hyundai * comment and add eps! * clean up config test * fix test * add error message to test * until we have multiple ways a brand can set up fuzzy FP, let's leave func name fuzzy-specific * rename in comment too * hyundai tests * simpler test! * check all ecus with platform codes * add types-python-dateutil = "^2.8.19.13" * these aren't used any more * Update selfdrive/car/hyundai/tests/test_hyundai.py * not to imply this is active yet --- selfdrive/car/fw_query_definitions.py | 8 ++- selfdrive/car/hyundai/tests/test_hyundai.py | 62 ++++++++++++++++++++- selfdrive/car/hyundai/values.py | 43 +++++++++++++- selfdrive/car/tests/test_fw_fingerprint.py | 15 +++++ 4 files changed, 125 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index 7ae9bee404..b3fb8476e5 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -3,7 +3,7 @@ import capnp import copy from dataclasses import dataclass, field import struct -from typing import Dict, List, Optional, Tuple +from typing import Callable, Dict, List, Optional, Set, Tuple import panda.python.uds as uds @@ -75,6 +75,12 @@ class FwQueryConfig: # Ecus added for data collection, not to be fingerprinted on extra_ecus: List[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]]] = field(default_factory=list) + # Brand-specific fuzzy fingerprinting config options: + # A function to get unique, platform-specific identification codes for a set of versions + fuzzy_get_platform_codes: Optional[Callable[[List[bytes]], Set[bytes]]] = None + # List of ECUs expected to have platform codes + platform_code_ecus: List[capnp.lib.capnp._EnumModule] = field(default_factory=list) + def __post_init__(self): for i in range(len(self.requests)): if self.requests[i].auxiliary: diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index fba99ae74d..f2e27788a6 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -2,7 +2,8 @@ import unittest from cereal import car -from selfdrive.car.hyundai.values import CANFD_CAR, FW_QUERY_CONFIG, FW_VERSIONS, CAN_GEARS, LEGACY_SAFETY_MODE_CAR, CHECKSUM, CAMERA_SCC_CAR +from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, FW_QUERY_CONFIG, \ + FW_VERSIONS, LEGACY_SAFETY_MODE_CAR Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} @@ -24,6 +25,65 @@ class TestHyundaiFingerprint(unittest.TestCase): ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist]) self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}') + def test_platform_code_ecus_available(self): + no_eps_platforms = CANFD_CAR | {CAR.KIA_SORENTO, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, + CAR.SONATA_LF, CAR.TUCSON, CAR.GENESIS_G90, CAR.GENESIS_G80} + + # Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms + for car_model, ecus in FW_VERSIONS.items(): + with self.subTest(car_model=car_model): + for fuzzy_ecu in FW_QUERY_CONFIG.platform_code_ecus: + if fuzzy_ecu in (Ecu.fwdRadar, Ecu.eps) and car_model == CAR.HYUNDAI_GENESIS: + continue + if fuzzy_ecu == Ecu.eps and car_model in no_eps_platforms: + continue + self.assertIn(fuzzy_ecu, [e[0] for e in ecus]) + + def test_fuzzy_fw_dates(self): + # Some newer platforms have date codes in a different format we don't yet parse, + # for now assert date format is consistent for all FW across each platform + for car_model, ecus in FW_VERSIONS.items(): + with self.subTest(car_model=car_model): + for ecu, fws in ecus.items(): + if ecu[0] not in FW_QUERY_CONFIG.platform_code_ecus: + continue + + codes = set() + for fw in fws: + codes |= FW_QUERY_CONFIG.fuzzy_get_platform_codes([fw]) + + # Either no dates should be parsed or all dates should be parsed + self.assertEqual(len({b'-' in code for code in codes}), 1) + + def test_fuzzy_platform_codes(self): + # Asserts basic platform code parsing behavior + codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00DH LKAS 1.1 -150210']) + self.assertEqual(codes, {b"DH-1502"}) + + # Some cameras and all radars do not have dates + codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ']) + self.assertEqual(codes, {b"AEhe"}) + + codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ']) + self.assertEqual(codes, {b"CV1"}) + + codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([ + b'\xf1\x00DH LKAS 1.1 -150210', + b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ', + b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', + ]) + self.assertEqual(codes, {b"DH-1502", b"AEhe", b"CV1"}) + + # Returned platform codes must inclusively contain start/end dates + codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([ + b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222', + b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103', + b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405', + b'\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 190720', + ]) + self.assertEqual(codes, {b'LX2-2111', b'LX2-2112', b'LX2-2201', b'LX2-2202', + b'ON-1904', b'ON-1905', b'ON-1906', b'ON-1907'}) + if __name__ == "__main__": unittest.main() diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 86ebaabf04..7852f389f3 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1,6 +1,10 @@ +import re +from datetime import datetime +from dateutil import rrule +from collections import defaultdict from dataclasses import dataclass from enum import Enum, IntFlag -from typing import Dict, List, Optional, Union +from typing import DefaultDict, Dict, List, Optional, Set, Union from cereal import car from panda.python import uds @@ -8,6 +12,7 @@ from common.conversions import Conversions as CV from selfdrive.car import dbc_dict from selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 +from system.swaglog import cloudlog Ecu = car.CarParams.Ecu @@ -342,6 +347,36 @@ FINGERPRINTS = { }], } + +def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]: + codes: DefaultDict[bytes, Set[bytes]] = defaultdict(set) + for fw in fw_versions: + match = PLATFORM_CODE_PATTERN.search(fw) + if match is not None: + code, date = match.groups() + codes[code].add(date) + + # Create platform codes for all dates inclusive if ECU has FW dates + final_codes = set() + for code, dates in codes.items(): + # Radar and some cameras don't have FW dates + if None in dates: + final_codes.add(code) + continue + + try: + parsed = {datetime.strptime(date.decode()[:4], '%y%m') for date in dates} + except ValueError: + cloudlog.exception(f'Error parsing date in FW versions: {code!r}, {dates}') + final_codes.add(code) + continue + + for date in rrule.rrule(rrule.MONTHLY, dtstart=min(parsed), until=max(parsed)): + final_codes.add(code + b'-' + date.strftime('%y%m').encode()) + + return final_codes + + HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ p16(0xf100) # Long description @@ -355,6 +390,9 @@ HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER] HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) +PLATFORM_CODE_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] + + b')[A-Z]{2}[A-Za-z0-9]{0,2})(?:.*([0-9]{6}))?') + FW_QUERY_CONFIG = FwQueryConfig( requests=[ # TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD @@ -411,6 +449,9 @@ FW_QUERY_CONFIG = FwQueryConfig( (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], + fuzzy_get_platform_codes=get_platform_codes, + # Camera and radar should exist on all cars + platform_code_ecus=[Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps], ) FW_VERSIONS = { diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index b90120a1e2..97441f89af 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -123,6 +123,21 @@ class TestFwFingerprint(unittest.TestCase): with self.subTest(): self.fail(f"Brands do not implement FW_QUERY_CONFIG: {brand_versions - brand_configs}") + def test_fuzzy_fingerprint_config(self): + for brand, config in FW_QUERY_CONFIGS.items(): + with self.subTest(brand=brand): + if config.fuzzy_get_platform_codes is None: + self.assertEqual(len(config.platform_code_ecus), 0, "Cannot specify platform code ECUs without full config") + else: + self.assertGreater(len(config.platform_code_ecus), 0, "Need to specify platform code ECUs") + + # Assert every supported ECU FW version returns one platform code + for fw_by_addr in VERSIONS[brand].values(): + for addr, fws in fw_by_addr.items(): + if addr[0] in config.platform_code_ecus: + for f in fws: + self.assertEqual(1, len(config.fuzzy_get_platform_codes([f])), f"Unable to parse FW: {f}") + def test_fw_request_ecu_whitelist(self): for brand, config in FW_QUERY_CONFIGS.items(): with self.subTest(brand=brand): From f0eef38dc0287baa0c8450290b90a948fa7bf01f Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 10 Jun 2023 16:01:16 -0400 Subject: [PATCH 212/283] offroad ui: remove irrelevant comment (#28485) --- selfdrive/ui/qt/offroad/settings.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index a165f34144..e37e5a9843 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -27,7 +27,7 @@ #include "selfdrive/ui/qt/widgets/input.h" TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { - // param, title, desc, icon, confirm + // param, title, desc, icon std::vector> toggle_defs{ { "OpenpilotEnabledToggle", From 22ebd4fa8f7f9974daf096db6d3e11034149d6d9 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 10 Jun 2023 22:09:48 -0700 Subject: [PATCH 213/283] UI: consider border when setting map width (#28488) --- selfdrive/ui/qt/onroad.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index af07f179c4..0dcf38ccf0 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -95,7 +95,7 @@ void OnroadWindow::offroadTransition(bool offroad) { QObject::connect(uiState(), &UIState::offroadTransition, m, &MapWindow::offroadTransition); - m->setFixedWidth(topWidget(this)->width() / 2); + m->setFixedWidth(topWidget(this)->width() / 2 - bdr_s); split->insertWidget(0, m); // Make map visible after adding to split From 28bf7436937a14f16020dd00ee224c1d3fe26705 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 10 Jun 2023 22:50:19 -0700 Subject: [PATCH 214/283] selfdrive/car: reusable CanBus helper (#28489) --- selfdrive/car/__init__.py | 19 +++++++++++++++++-- selfdrive/car/hyundai/hyundaicanfd.py | 23 ++++++++++------------- selfdrive/car/hyundai/interface.py | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 58cde85817..74197ad941 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -1,10 +1,13 @@ # functions common among cars -import capnp +import math from collections import namedtuple +from typing import Dict, Optional + +import capnp from cereal import car from common.numpy_fast import clip, interp -from typing import Dict + # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. @@ -175,3 +178,15 @@ def get_safety_config(safety_model, safety_param = None): if safety_param is not None: ret.safetyParam = safety_param return ret + + +class CanBusBase: + offset: int + + def __init__(self, CP, fingerprint: Optional[Dict[int, Dict[int, int]]]) -> None: + if CP is None: + assert fingerprint is not None + num = math.ceil(max([k for k, v in fingerprint.items() if len(v)], default=1) / 4) + else: + num = len(CP.safetyConfigs) + self.offset = 4 * (num - 1) diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index 3717a45909..c727649ffc 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -1,17 +1,15 @@ -import math - from common.numpy_fast import clip +from selfdrive.car import CanBusBase from selfdrive.car.hyundai.values import HyundaiFlags -class CanBus: - def __init__(self, CP, hda2=None, fingerprint=None): - if CP is None: - assert None not in (hda2, fingerprint) - num = math.ceil(max([k for k, v in fingerprint.items() if len(v)], default=1) / 4) - else: +class CanBus(CanBusBase): + def __init__(self, CP, hda2=None, fingerprint=None) -> None: + super().__init__(CP, fingerprint) + + if hda2 is None: + assert CP is not None hda2 = CP.flags & HyundaiFlags.CANFD_HDA2.value - num = len(CP.safetyConfigs) # On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars # have a different harness than the HDA1 and non-HDA variants in order to split @@ -20,10 +18,9 @@ class CanBus: if hda2: self._a, self._e = 0, 1 - offset = 4*(num - 1) - self._a += offset - self._e += offset - self._cam = 2 + offset + self._a += self.offset + self._e += self.offset + self._cam = 2 + self.offset @property def ECAN(self): diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 59d7319de0..418068a5c5 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -311,7 +311,7 @@ class CarInterface(CarInterfaceBase): # for blinkers if CP.flags & HyundaiFlags.ENABLE_BLINKERS: - disable_ecu(logcan, sendcan, bus=CanBus(CP.ECAN), addr=0x7B1, com_cont_req=b'\x28\x83\x01') + disable_ecu(logcan, sendcan, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01') def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) From 30c12e45575d94563ae85a79e19823e9120ef76b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 10 Jun 2023 23:22:12 -0700 Subject: [PATCH 215/283] Ford: detect auxiliary panda (#28491) --- selfdrive/car/ford/carcontroller.py | 29 ++++++++-------- selfdrive/car/ford/carstate.py | 7 ++-- selfdrive/car/ford/fordcan.py | 49 ++++++++++++++++++--------- selfdrive/car/ford/interface.py | 14 +++++--- selfdrive/car/ford/radar_interface.py | 15 ++++---- selfdrive/car/ford/values.py | 6 ---- 6 files changed, 70 insertions(+), 50 deletions(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 5bdafa58b5..2a930e735e 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -2,9 +2,9 @@ from cereal import car from common.numpy_fast import clip from opendbc.can.packer import CANPacker from selfdrive.car import apply_std_steer_angle_limits -from selfdrive.car.ford.fordcan import create_acc_msg, create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, \ - create_lat_ctl2_msg, create_lka_msg, create_lkas_ui_msg -from selfdrive.car.ford.values import CANBUS, CANFD_CARS, CarControllerParams +from selfdrive.car.ford.fordcan import CanBus, create_acc_msg, create_acc_ui_msg, create_button_msg, \ + create_lat_ctl_msg, create_lat_ctl2_msg, create_lka_msg, create_lkas_ui_msg +from selfdrive.car.ford.values import CANFD_CARS, CarControllerParams LongCtrlState = car.CarControl.Actuators.LongControlState VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -27,6 +27,7 @@ class CarController: self.CP = CP self.VM = VM self.packer = CANPacker(dbc_name) + self.CAN = CanBus(CP) self.frame = 0 self.apply_curvature_last = 0 @@ -45,15 +46,15 @@ class CarController: ### acc buttons ### if CC.cruiseControl.cancel: - can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, cancel=True)) - can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, cancel=True, bus=CANBUS.main)) + can_sends.append(create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, cancel=True)) + can_sends.append(create_button_msg(self.packer, self.CAN.main, CS.buttons_stock_values, cancel=True)) elif CC.cruiseControl.resume and (self.frame % CarControllerParams.BUTTONS_STEP) == 0: - can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, resume=True)) - can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, resume=True, bus=CANBUS.main)) + can_sends.append(create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, resume=True)) + can_sends.append(create_button_msg(self.packer, self.CAN.main, CS.buttons_stock_values, resume=True)) # if stock lane centering isn't off, send a button press to toggle it off # the stock system checks for steering pressed, and eventually disengages cruise control elif CS.acc_tja_status_stock_values["Tja_D_Stat"] != 0 and (self.frame % CarControllerParams.ACC_UI_STEP) == 0: - can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, tja_toggle=True)) + can_sends.append(create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, tja_toggle=True)) ### lateral control ### # send steer msg at 20Hz @@ -71,13 +72,13 @@ class CarController: # TODO: extended mode mode = 1 if CC.latActive else 0 counter = (self.frame // CarControllerParams.STEER_STEP) % 0xF - can_sends.append(create_lat_ctl2_msg(self.packer, mode, 0., 0., -apply_curvature, 0., counter)) + can_sends.append(create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -apply_curvature, 0., counter)) else: - can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.)) + can_sends.append(create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -apply_curvature, 0.)) # send lka msg at 33Hz if (self.frame % CarControllerParams.LKA_STEP) == 0: - can_sends.append(create_lka_msg(self.packer)) + can_sends.append(create_lka_msg(self.packer, self.CAN)) ### longitudinal control ### # send acc msg at 50Hz @@ -89,16 +90,16 @@ class CarController: gas = CarControllerParams.INACTIVE_GAS stopping = CC.actuators.longControlState == LongCtrlState.stopping - can_sends.append(create_acc_msg(self.packer, CC.longActive, gas, accel, stopping)) + can_sends.append(create_acc_msg(self.packer, self.CAN, CC.longActive, gas, accel, stopping)) ### ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) # send lkas ui msg at 1Hz or if ui state changes if (self.frame % CarControllerParams.LKAS_UI_STEP) == 0 or send_ui: - can_sends.append(create_lkas_ui_msg(self.packer, main_on, CC.latActive, steer_alert, hud_control, CS.lkas_status_stock_values)) + can_sends.append(create_lkas_ui_msg(self.packer, self.CAN, main_on, CC.latActive, steer_alert, hud_control, CS.lkas_status_stock_values)) # send acc ui msg at 5Hz or if ui state changes if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui: - can_sends.append(create_acc_ui_msg(self.packer, self.CP, main_on, CC.latActive, + can_sends.append(create_acc_ui_msg(self.packer, self.CAN, self.CP, main_on, CC.latActive, CS.out.cruiseState.standstill, hud_control, CS.acc_tja_status_stock_values)) diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 9be2c7637c..b768749325 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -3,7 +3,8 @@ from common.conversions import Conversions as CV from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from selfdrive.car.interfaces import CarStateBase -from selfdrive.car.ford.values import CANBUS, DBC, CarControllerParams +from selfdrive.car.ford.fordcan import CanBus +from selfdrive.car.ford.values import DBC, CarControllerParams GearShifter = car.CarState.GearShifter TransmissionType = car.CarParams.TransmissionType @@ -211,7 +212,7 @@ class CarState(CarStateBase): ("Side_Detect_R_Stat", 5), ] - return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.main) + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CanBus(CP).main) @staticmethod def get_cam_can_parser(CP): @@ -268,4 +269,4 @@ class CarState(CarStateBase): ("IPMA_Data", 1), ] - return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.camera) + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CanBus(CP).camera) diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index 97a8c025d4..30a53597d6 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -1,9 +1,26 @@ from cereal import car -from selfdrive.car.ford.values import CANBUS +from selfdrive.car import CanBusBase HUDControl = car.CarControl.HUDControl +class CanBus(CanBusBase): + def __init__(self, CP=None, fingerprint=None) -> None: + super().__init__(CP, fingerprint) + + @property + def main(self) -> int: + return self.offset + + @property + def radar(self): + return self.offset + 1 + + @property + def camera(self): + return self.offset + 2 + + def calculate_lat_ctl2_checksum(mode: int, counter: int, dat: bytearray): curvature = (dat[2] << 3) | ((dat[3]) >> 5) curvature_rate = (dat[6] << 3) | ((dat[7]) >> 5) @@ -17,7 +34,7 @@ def calculate_lat_ctl2_checksum(mode: int, counter: int, dat: bytearray): return 0xFF - (checksum & 0xFF) -def create_lka_msg(packer): +def create_lka_msg(packer, CAN: CanBus): """ Creates an empty CAN message for the Ford LKA Command. @@ -26,10 +43,10 @@ def create_lka_msg(packer): Frequency is 33Hz. """ - return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {}) + return packer.make_can_msg("Lane_Assist_Data1", CAN.main, {}) -def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float, +def create_lat_ctl_msg(packer, CAN: CanBus, lat_active: bool, path_offset: float, path_angle: float, curvature: float, curvature_rate: float): """ Creates a CAN message for the Ford TJA/LCA Command. @@ -66,10 +83,10 @@ def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: "LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2 "LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter } - return packer.make_can_msg("LateralMotionControl", CANBUS.main, values) + return packer.make_can_msg("LateralMotionControl", CAN.main, values) -def create_lat_ctl2_msg(packer, mode: int, path_offset: float, path_angle: float, curvature: float, +def create_lat_ctl2_msg(packer, CAN: CanBus, 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. @@ -95,13 +112,13 @@ def create_lat_ctl2_msg(packer, mode: int, path_offset: float, path_angle: float } # calculate checksum - dat = packer.make_can_msg("LateralMotionControl2", CANBUS.main, values)[2] + dat = packer.make_can_msg("LateralMotionControl2", 0, values)[2] values["LatCtlPath_No_Cs"] = calculate_lat_ctl2_checksum(mode, counter, dat) - return packer.make_can_msg("LateralMotionControl2", CANBUS.main, values) + return packer.make_can_msg("LateralMotionControl2", CAN.main, values) -def create_acc_msg(packer, long_active: bool, gas: float, accel: float, stopping: bool): +def create_acc_msg(packer, CAN: CanBus, long_active: bool, gas: float, accel: float, stopping: bool): """ Creates a CAN message for the Ford ACC Command. @@ -122,10 +139,10 @@ def create_acc_msg(packer, long_active: bool, gas: float, accel: float, stopping "AccBrkDecel_B_Rq": 1 if decel else 0, # Deceleration request: 0=Inactive, 1=Active "AccStopStat_B_Rq": 1 if stopping else 0, } - return packer.make_can_msg("ACCDATA", CANBUS.main, values) + return packer.make_can_msg("ACCDATA", CAN.main, values) -def create_acc_ui_msg(packer, CP, main_on: bool, enabled: bool, standstill: bool, hud_control, +def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, standstill: bool, hud_control, stock_values: dict): """ Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam @@ -197,10 +214,11 @@ def create_acc_ui_msg(packer, CP, main_on: bool, enabled: bool, standstill: bool "AccTGap_D_Dsply": 4, # Fixed time gap in UI }) - return packer.make_can_msg("ACCDATA_3", CANBUS.main, values) + return packer.make_can_msg("ACCDATA_3", CAN.main, values) -def create_lkas_ui_msg(packer, main_on: bool, enabled: bool, steer_alert: bool, hud_control, stock_values: dict): +def create_lkas_ui_msg(packer, CAN: CanBus, main_on: bool, enabled: bool, steer_alert: bool, hud_control, + stock_values: dict): """ Creates a CAN message for the Ford IPC IPMA/LKAS status. @@ -263,11 +281,10 @@ def create_lkas_ui_msg(packer, main_on: bool, enabled: bool, steer_alert: bool, "LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31] "LaHandsOff_D_Dsply": hands_on_wheel_dsply, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed }) - return packer.make_can_msg("IPMA_Data", CANBUS.main, values) + return packer.make_can_msg("IPMA_Data", CAN.main, values) -def create_button_msg(packer, stock_values: dict, cancel=False, resume=False, tja_toggle=False, - bus: int = CANBUS.camera): +def create_button_msg(packer, bus: int, stock_values: dict, cancel=False, resume=False, tja_toggle=False): """ Creates a CAN message for the Ford SCCM buttons/switches. diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 626853dd8f..fef7fcefc8 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -3,6 +3,7 @@ from cereal import car from panda import Panda from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, get_safety_config +from selfdrive.car.ford.fordcan import CanBus from selfdrive.car.ford.values import CAR, Ecu from selfdrive.car.interfaces import CarInterfaceBase @@ -14,7 +15,6 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.carName = "ford" - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.ford)] # These cars are dashcam only for lack of test coverage. # Once a user confirms each car works and a test route is @@ -26,9 +26,15 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.2 ret.steerLimitTimer = 1.0 + CAN = CanBus(fingerprint=fingerprint) + cfgs = [get_safety_config(car.CarParams.SafetyModel.ford)] + if CAN.main >= 4: + cfgs.insert(0, get_safety_config(car.CarParams.SafetyModel.noOutput)) + ret.safetyConfigs = cfgs + ret.experimentalLongitudinalAvailable = True if experimental_long: - ret.safetyConfigs[0].safetyParam |= Panda.FLAG_FORD_LONG_CONTROL + ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_FORD_LONG_CONTROL ret.openpilotLongitudinalControl = True if candidate == CAR.BRONCO_SPORT_MK1: @@ -61,7 +67,7 @@ class CarInterface(CarInterfaceBase): # Auto Transmission: 0x732 ECU or Gear_Shift_by_Wire_FD1 found_ecus = [fw.ecu for fw in car_fw] - if Ecu.shiftByWire in found_ecus or 0x5A in fingerprint[0] or docs: + if Ecu.shiftByWire in found_ecus or 0x5A in fingerprint[CAN.main] or docs: ret.transmissionType = TransmissionType.automatic else: ret.transmissionType = TransmissionType.manual @@ -69,7 +75,7 @@ class CarInterface(CarInterfaceBase): # BSM: Side_Detect_L_Stat, Side_Detect_R_Stat # TODO: detect bsm in car_fw? - ret.enableBsm = 0x3A6 in fingerprint[0] and 0x3A7 in fingerprint[0] + ret.enableBsm = 0x3A6 in fingerprint[CAN.main] and 0x3A7 in fingerprint[CAN.main] # LCA can steer down to zero ret.minSteerSpeed = 0. diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py index ee4efb311d..e44730ca4f 100644 --- a/selfdrive/car/ford/radar_interface.py +++ b/selfdrive/car/ford/radar_interface.py @@ -3,7 +3,8 @@ from math import cos, sin from cereal import car from opendbc.can.parser import CANParser from common.conversions import Conversions as CV -from selfdrive.car.ford.values import CANBUS, DBC, RADAR +from selfdrive.car.ford.fordcan import CanBus +from selfdrive.car.ford.values import DBC, RADAR from selfdrive.car.interfaces import RadarInterfaceBase DELPHI_ESR_RADAR_MSGS = list(range(0x500, 0x540)) @@ -12,16 +13,16 @@ DELPHI_MRR_RADAR_START_ADDR = 0x120 DELPHI_MRR_RADAR_MSG_COUNT = 64 -def _create_delphi_esr_radar_can_parser(): +def _create_delphi_esr_radar_can_parser(CP) -> CANParser: msg_n = len(DELPHI_ESR_RADAR_MSGS) signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n, DELPHI_ESR_RADAR_MSGS * 3)) checks = list(zip(DELPHI_ESR_RADAR_MSGS, [20] * msg_n)) - return CANParser(RADAR.DELPHI_ESR, signals, checks, CANBUS.radar) + return CANParser(RADAR.DELPHI_ESR, signals, checks, CanBus(CP).radar) -def _create_delphi_mrr_radar_can_parser(): +def _create_delphi_mrr_radar_can_parser(CP) -> CANParser: signals = [] checks = [] @@ -37,7 +38,7 @@ def _create_delphi_mrr_radar_can_parser(): ] checks += [(msg, 20)] - return CANParser(RADAR.DELPHI_MRR, signals, checks, CANBUS.radar) + return CANParser(RADAR.DELPHI_MRR, signals, checks, CanBus(CP).radar) class RadarInterface(RadarInterfaceBase): @@ -50,11 +51,11 @@ class RadarInterface(RadarInterfaceBase): if self.radar is None or CP.radarUnavailable: self.rcp = None elif self.radar == RADAR.DELPHI_ESR: - self.rcp = _create_delphi_esr_radar_can_parser() + self.rcp = _create_delphi_esr_radar_can_parser(CP) self.trigger_msg = DELPHI_ESR_RADAR_MSGS[-1] self.valid_cnt = {key: 0 for key in DELPHI_ESR_RADAR_MSGS} elif self.radar == RADAR.DELPHI_MRR: - self.rcp = _create_delphi_mrr_radar_can_parser() + self.rcp = _create_delphi_mrr_radar_can_parser(CP) self.trigger_msg = DELPHI_MRR_RADAR_START_ADDR + DELPHI_MRR_RADAR_MSG_COUNT - 1 else: raise ValueError(f"Unsupported radar: {self.radar}") diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 9b7b6ad83e..1807a26b17 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -38,12 +38,6 @@ class CarControllerParams: pass -class CANBUS: - main = 0 - radar = 1 - camera = 2 - - class CAR: BRONCO_SPORT_MK1 = "FORD BRONCO SPORT 1ST GEN" ESCAPE_MK4 = "FORD ESCAPE 4TH GEN" From 1fd7542eae10e78fb363548da428a9c7a907638e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sat, 10 Jun 2023 23:44:01 -0700 Subject: [PATCH 216/283] Encoderd: encoders just encode, no writing (#28482) Encoders dont write, they encode --- system/loggerd/encoder/encoder.cc | 41 ------------------------ system/loggerd/encoder/encoder.h | 21 ++---------- system/loggerd/encoder/ffmpeg_encoder.cc | 2 -- system/loggerd/encoder/ffmpeg_encoder.h | 4 +-- system/loggerd/encoder/v4l_encoder.cc | 2 -- system/loggerd/encoder/v4l_encoder.h | 4 +-- system/loggerd/encoderd.cc | 4 +-- 7 files changed, 8 insertions(+), 70 deletions(-) diff --git a/system/loggerd/encoder/encoder.cc b/system/loggerd/encoder/encoder.cc index 08eaf0ff01..417eec04d2 100644 --- a/system/loggerd/encoder/encoder.cc +++ b/system/loggerd/encoder/encoder.cc @@ -38,45 +38,4 @@ void VideoEncoder::publisher_publish(VideoEncoder *e, int segment_num, uint32_t auto words = new kj::Array(capnp::messageToFlatArray(msg)); auto bytes = words->asBytes(); e->pm->send(e->service_name, bytes.begin(), bytes.size()); - if (e->write) { - e->to_write.push(words); - } else { - delete words; - } -} - -// TODO: writing should be moved to loggerd -void VideoEncoder::write_handler(VideoEncoder *e, const char *path) { - VideoWriter writer(path, e->filename, e->codec != cereal::EncodeIndex::Type::FULL_H_E_V_C, e->out_width, e->out_height, e->fps, e->codec); - - bool first = true; - kj::Array* out_buf; - while ((out_buf = e->to_write.pop())) { - capnp::FlatArrayMessageReader cmsg(*out_buf); - cereal::Event::Reader event = cmsg.getRoot(); - - auto edata = (e->type == DriverCam) ? event.getDriverEncodeData() : - ((e->type == WideRoadCam) ? event.getWideRoadEncodeData() : - (e->in_width == e->out_width ? event.getRoadEncodeData() : event.getQRoadEncodeData())); - auto idx = edata.getIdx(); - auto flags = idx.getFlags(); - - if (first) { - assert(flags & V4L2_BUF_FLAG_KEYFRAME); - auto header = edata.getHeader(); - writer.write((uint8_t *)header.begin(), header.size(), idx.getTimestampEof()/1000, true, false); - first = false; - } - - // dangerous cast from const, but should be fine - auto data = edata.getData(); - if (data.size() > 0) { - writer.write((uint8_t *)data.begin(), data.size(), idx.getTimestampEof()/1000, false, flags & V4L2_BUF_FLAG_KEYFRAME); - } - - // free the data - delete out_buf; - } - - // VideoWriter is freed on out of scope } diff --git a/system/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h index 88dd5cee23..9fd2431567 100644 --- a/system/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -15,9 +15,9 @@ class VideoEncoder { public: VideoEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : filename(filename), type(type), in_width(in_width), in_height(in_height), fps(fps), - bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height), write(write) { } + bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height) { } virtual ~VideoEncoder(); virtual int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) = 0; virtual void encoder_open(const char* path) = 0; @@ -26,20 +26,8 @@ public: void publisher_init(); static void publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr header, kj::ArrayPtr dat); - void writer_open(const char* path) { - if (this->write) write_handler_thread = std::thread(VideoEncoder::write_handler, this, path); - } - - void writer_close() { - if (this->write) { - to_write.push(NULL); - write_handler_thread.join(); - } - assert(to_write.empty()); - } protected: - bool write; const char* filename; int in_width, in_height; int out_width, out_height, fps; @@ -54,9 +42,4 @@ private: // publishing std::unique_ptr pm; const char *service_name; - - // writing support - static void write_handler(VideoEncoder *e, const char *path); - std::thread write_handler_thread; - SafeQueue* > to_write; }; diff --git a/system/loggerd/encoder/ffmpeg_encoder.cc b/system/loggerd/encoder/ffmpeg_encoder.cc index 275da34f18..af05b5df97 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.cc +++ b/system/loggerd/encoder/ffmpeg_encoder.cc @@ -60,7 +60,6 @@ void FfmpegEncoder::encoder_open(const char* path) { int err = avcodec_open2(this->codec_ctx, codec, NULL); assert(err >= 0); - writer_open(path); is_open = true; segment_num++; counter = 0; @@ -69,7 +68,6 @@ void FfmpegEncoder::encoder_open(const char* path) { void FfmpegEncoder::encoder_close() { if (!is_open) return; - writer_close(); avcodec_free_context(&codec_ctx); is_open = false; } diff --git a/system/loggerd/encoder/ffmpeg_encoder.h b/system/loggerd/encoder/ffmpeg_encoder.h index 9095a6e815..1ba991f09b 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.h +++ b/system/loggerd/encoder/ffmpeg_encoder.h @@ -17,8 +17,8 @@ extern "C" { class FfmpegEncoder : public VideoEncoder { public: FfmpegEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height, write) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height) { encoder_init(); } ~FfmpegEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoder/v4l_encoder.cc b/system/loggerd/encoder/v4l_encoder.cc index 16e7246ff4..976839eef3 100644 --- a/system/loggerd/encoder/v4l_encoder.cc +++ b/system/loggerd/encoder/v4l_encoder.cc @@ -255,7 +255,6 @@ void V4LEncoder::encoder_init() { void V4LEncoder::encoder_open(const char* path) { dequeue_handler_thread = std::thread(V4LEncoder::dequeue_handler, this); - writer_open(path); this->is_open = true; this->counter = 0; } @@ -288,7 +287,6 @@ void V4LEncoder::encoder_close() { // join waits for V4L2_QCOM_BUF_FLAG_EOS dequeue_handler_thread.join(); assert(extras.empty()); - writer_close(); } this->is_open = false; } diff --git a/system/loggerd/encoder/v4l_encoder.h b/system/loggerd/encoder/v4l_encoder.h index d4b0a1211d..1016c0f5c6 100644 --- a/system/loggerd/encoder/v4l_encoder.h +++ b/system/loggerd/encoder/v4l_encoder.h @@ -9,8 +9,8 @@ class V4LEncoder : public VideoEncoder { public: V4LEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height, write) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height) { encoder_init(); } ~V4LEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoderd.cc b/system/loggerd/encoderd.cc index 12b58b6591..45120ec334 100644 --- a/system/loggerd/encoderd.cc +++ b/system/loggerd/encoderd.cc @@ -57,13 +57,13 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { encoders.push_back(new Encoder(cam_info.filename, cam_info.type, buf_info.width, buf_info.height, cam_info.fps, cam_info.bitrate, cam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - buf_info.width, buf_info.height, false)); + buf_info.width, buf_info.height)); // qcamera encoder if (cam_info.has_qcamera) { encoders.push_back(new Encoder(qcam_info.filename, cam_info.type, buf_info.width, buf_info.height, qcam_info.fps, qcam_info.bitrate, qcam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - qcam_info.frame_width, qcam_info.frame_height, false)); + qcam_info.frame_width, qcam_info.frame_height)); } } else { LOGE("not initting empty encoder"); From 96420555e5766f835ec9b7d8f6207d87d9493571 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sun, 11 Jun 2023 00:09:57 -0700 Subject: [PATCH 217/283] Ford: shiftByWire ECU not used for fingerprinting (#28493) --- selfdrive/car/ford/values.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 1807a26b17..81e35ed5f9 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -95,6 +95,9 @@ FW_QUERY_CONFIG = FwQueryConfig( whitelist_ecus=[Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.shiftByWire], ), ], + extra_ecus=[ + (Ecu.shiftByWire, 0x732, None), + ], ) FW_VERSIONS = { @@ -117,10 +120,6 @@ FW_VERSIONS = { b'M1PA-14C204-GF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'N1PA-14C204-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], - (Ecu.shiftByWire, 0x732, None): [ - b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'PZ1P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - ], }, CAR.ESCAPE_MK4: { (Ecu.eps, 0x730, None): [ @@ -147,11 +146,6 @@ FW_VERSIONS = { b'MX6A-14C204-BEJ\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NX6A-14C204-BLE\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], - (Ecu.shiftByWire, 0x732, None): [ - b'LX6P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'PZ1P-14G395-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - ], }, CAR.EXPLORER_MK6: { (Ecu.eps, 0x730, None): [ @@ -184,12 +178,6 @@ FW_VERSIONS = { b'MB5A-14C204-RC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NB5A-14C204-HB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], - (Ecu.shiftByWire, 0x732, None): [ - b'L1MP-14C561-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'L1MP-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'L1MP-14G395-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'L1MP-14G395-JB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - ], }, CAR.FOCUS_MK4: { (Ecu.eps, 0x730, None): [ @@ -228,8 +216,5 @@ FW_VERSIONS = { b'NZ6A-14C204-ZA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PZ6A-14C204-JC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], - (Ecu.shiftByWire, 0x732, None): [ - b'NZ6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - ], }, } From 5161c2364538236b51674fbc63c7f9666e95928b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 11 Jun 2023 08:27:09 -0700 Subject: [PATCH 218/283] Revert "Encoderd: encoders just encode, no writing (#28482)" This reverts commit 1fd7542eae10e78fb363548da428a9c7a907638e. --- system/loggerd/encoder/encoder.cc | 41 ++++++++++++++++++++++++ system/loggerd/encoder/encoder.h | 21 ++++++++++-- system/loggerd/encoder/ffmpeg_encoder.cc | 2 ++ system/loggerd/encoder/ffmpeg_encoder.h | 4 +-- system/loggerd/encoder/v4l_encoder.cc | 2 ++ system/loggerd/encoder/v4l_encoder.h | 4 +-- system/loggerd/encoderd.cc | 4 +-- 7 files changed, 70 insertions(+), 8 deletions(-) diff --git a/system/loggerd/encoder/encoder.cc b/system/loggerd/encoder/encoder.cc index 417eec04d2..08eaf0ff01 100644 --- a/system/loggerd/encoder/encoder.cc +++ b/system/loggerd/encoder/encoder.cc @@ -38,4 +38,45 @@ void VideoEncoder::publisher_publish(VideoEncoder *e, int segment_num, uint32_t auto words = new kj::Array(capnp::messageToFlatArray(msg)); auto bytes = words->asBytes(); e->pm->send(e->service_name, bytes.begin(), bytes.size()); + if (e->write) { + e->to_write.push(words); + } else { + delete words; + } +} + +// TODO: writing should be moved to loggerd +void VideoEncoder::write_handler(VideoEncoder *e, const char *path) { + VideoWriter writer(path, e->filename, e->codec != cereal::EncodeIndex::Type::FULL_H_E_V_C, e->out_width, e->out_height, e->fps, e->codec); + + bool first = true; + kj::Array* out_buf; + while ((out_buf = e->to_write.pop())) { + capnp::FlatArrayMessageReader cmsg(*out_buf); + cereal::Event::Reader event = cmsg.getRoot(); + + auto edata = (e->type == DriverCam) ? event.getDriverEncodeData() : + ((e->type == WideRoadCam) ? event.getWideRoadEncodeData() : + (e->in_width == e->out_width ? event.getRoadEncodeData() : event.getQRoadEncodeData())); + auto idx = edata.getIdx(); + auto flags = idx.getFlags(); + + if (first) { + assert(flags & V4L2_BUF_FLAG_KEYFRAME); + auto header = edata.getHeader(); + writer.write((uint8_t *)header.begin(), header.size(), idx.getTimestampEof()/1000, true, false); + first = false; + } + + // dangerous cast from const, but should be fine + auto data = edata.getData(); + if (data.size() > 0) { + writer.write((uint8_t *)data.begin(), data.size(), idx.getTimestampEof()/1000, false, flags & V4L2_BUF_FLAG_KEYFRAME); + } + + // free the data + delete out_buf; + } + + // VideoWriter is freed on out of scope } diff --git a/system/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h index 9fd2431567..88dd5cee23 100644 --- a/system/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -15,9 +15,9 @@ class VideoEncoder { public: VideoEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : filename(filename), type(type), in_width(in_width), in_height(in_height), fps(fps), - bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height) { } + bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height), write(write) { } virtual ~VideoEncoder(); virtual int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) = 0; virtual void encoder_open(const char* path) = 0; @@ -26,8 +26,20 @@ public: void publisher_init(); static void publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr header, kj::ArrayPtr dat); + void writer_open(const char* path) { + if (this->write) write_handler_thread = std::thread(VideoEncoder::write_handler, this, path); + } + + void writer_close() { + if (this->write) { + to_write.push(NULL); + write_handler_thread.join(); + } + assert(to_write.empty()); + } protected: + bool write; const char* filename; int in_width, in_height; int out_width, out_height, fps; @@ -42,4 +54,9 @@ private: // publishing std::unique_ptr pm; const char *service_name; + + // writing support + static void write_handler(VideoEncoder *e, const char *path); + std::thread write_handler_thread; + SafeQueue* > to_write; }; diff --git a/system/loggerd/encoder/ffmpeg_encoder.cc b/system/loggerd/encoder/ffmpeg_encoder.cc index af05b5df97..275da34f18 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.cc +++ b/system/loggerd/encoder/ffmpeg_encoder.cc @@ -60,6 +60,7 @@ void FfmpegEncoder::encoder_open(const char* path) { int err = avcodec_open2(this->codec_ctx, codec, NULL); assert(err >= 0); + writer_open(path); is_open = true; segment_num++; counter = 0; @@ -68,6 +69,7 @@ void FfmpegEncoder::encoder_open(const char* path) { void FfmpegEncoder::encoder_close() { if (!is_open) return; + writer_close(); avcodec_free_context(&codec_ctx); is_open = false; } diff --git a/system/loggerd/encoder/ffmpeg_encoder.h b/system/loggerd/encoder/ffmpeg_encoder.h index 1ba991f09b..9095a6e815 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.h +++ b/system/loggerd/encoder/ffmpeg_encoder.h @@ -17,8 +17,8 @@ extern "C" { class FfmpegEncoder : public VideoEncoder { public: FfmpegEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height, write) { encoder_init(); } ~FfmpegEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoder/v4l_encoder.cc b/system/loggerd/encoder/v4l_encoder.cc index 976839eef3..16e7246ff4 100644 --- a/system/loggerd/encoder/v4l_encoder.cc +++ b/system/loggerd/encoder/v4l_encoder.cc @@ -255,6 +255,7 @@ void V4LEncoder::encoder_init() { void V4LEncoder::encoder_open(const char* path) { dequeue_handler_thread = std::thread(V4LEncoder::dequeue_handler, this); + writer_open(path); this->is_open = true; this->counter = 0; } @@ -287,6 +288,7 @@ void V4LEncoder::encoder_close() { // join waits for V4L2_QCOM_BUF_FLAG_EOS dequeue_handler_thread.join(); assert(extras.empty()); + writer_close(); } this->is_open = false; } diff --git a/system/loggerd/encoder/v4l_encoder.h b/system/loggerd/encoder/v4l_encoder.h index 1016c0f5c6..d4b0a1211d 100644 --- a/system/loggerd/encoder/v4l_encoder.h +++ b/system/loggerd/encoder/v4l_encoder.h @@ -9,8 +9,8 @@ class V4LEncoder : public VideoEncoder { public: V4LEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height, write) { encoder_init(); } ~V4LEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoderd.cc b/system/loggerd/encoderd.cc index 45120ec334..12b58b6591 100644 --- a/system/loggerd/encoderd.cc +++ b/system/loggerd/encoderd.cc @@ -57,13 +57,13 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { encoders.push_back(new Encoder(cam_info.filename, cam_info.type, buf_info.width, buf_info.height, cam_info.fps, cam_info.bitrate, cam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - buf_info.width, buf_info.height)); + buf_info.width, buf_info.height, false)); // qcamera encoder if (cam_info.has_qcamera) { encoders.push_back(new Encoder(qcam_info.filename, cam_info.type, buf_info.width, buf_info.height, qcam_info.fps, qcam_info.bitrate, qcam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - qcam_info.frame_width, qcam_info.frame_height)); + qcam_info.frame_width, qcam_info.frame_height, false)); } } else { LOGE("not initting empty encoder"); From 3a3e38e42591457f8e4a97a8559b9274d057880a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 11 Jun 2023 23:28:30 +0800 Subject: [PATCH 219/283] replay: Improve the performance of the log parser (#28495) --- tools/replay/logreader.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tools/replay/logreader.cc b/tools/replay/logreader.cc index e3d5071412..3313e11d40 100644 --- a/tools/replay/logreader.cc +++ b/tools/replay/logreader.cc @@ -68,20 +68,16 @@ bool LogReader::parse(const std::set &allow, std::atomic words((const capnp::word *)raw_.data(), raw_.size() / sizeof(capnp::word)); while (words.size() > 0 && !(abort && *abort)) { - if (!allow.empty()) { - capnp::FlatArrayMessageReader reader(words); - auto which = reader.getRoot().which(); - if (allow.find(which) == allow.end()) { - words = kj::arrayPtr(reader.getEnd(), words.end()); - continue; - } - } - #ifdef HAS_MEMORY_RESOURCE Event *evt = new (mbr_) Event(words); #else Event *evt = new Event(words); #endif + if (!allow.empty() && allow.find(evt->which) == allow.end()) { + delete evt; + words = kj::arrayPtr(evt->reader.getEnd(), words.end()); + continue; + } // Add encodeIdx packet again as a frame packet for the video stream if (evt->which == cereal::Event::ROAD_ENCODE_IDX || From a5a0d734ba4f504d997cb19fe4ca21291ea7334f Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sun, 11 Jun 2023 12:57:22 -0700 Subject: [PATCH 220/283] add Lincoln Aviator 2020 FW (#28494) 0b91b433b9332780|2023-06-11--13-43-59 VIN: 5LM5J7XC9LGL15606 --- docs/CARS.md | 2 +- selfdrive/car/ford/values.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a4af5fc4c0..a7fb408644 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -152,7 +152,7 @@ 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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lincoln|Aviator 2021|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lincoln|Aviator 2020-21|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Mazda connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 81e35ed5f9..a2e9ea2442 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -75,7 +75,7 @@ CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { ], CAR.EXPLORER_MK6: [ FordCarInfo("Ford Explorer 2020-22"), - FordCarInfo("Lincoln Aviator 2021", "Co-Pilot360 Plus"), + FordCarInfo("Lincoln Aviator 2020-21", "Co-Pilot360 Plus"), ], CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2018", "Adaptive Cruise Control with Lane Centering"), CAR.MAVERICK_MK1: FordCarInfo("Ford Maverick 2022-23", "Co-Pilot360 Assist"), @@ -172,6 +172,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7E0, None): [ b'LB5A-14C204-ATJ\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LB5A-14C204-AZL\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5A-14C204-BUJ\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From 5250975fa32dbd5a5a3cc08cc0a9c15a36850b47 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 11 Jun 2023 13:07:46 -0700 Subject: [PATCH 221/283] VW MQB: Add FW for 2018 SEAT Leon (#28500) aef9c04d6ec5cd57|2023-06-11--17-40-14 --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 1529f4742c..0f211546bd 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1067,21 +1067,25 @@ FW_VERSIONS = { b'\xf1\x8704L906056CR\xf1\x892797', b'\xf1\x8705E906018AS\xf1\x899596', b'\xf1\x878V0906264H \xf1\x890005', + b'\xf1\x878V0907115E \xf1\x890002', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870CW300041D \xf1\x891004', b'\xf1\x870CW300041G \xf1\x891003', b'\xf1\x870CW300050J \xf1\x891908', b'\xf1\x870D9300042M \xf1\x895016', + b'\xf1\x870GC300043A \xf1\x892304', ], (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\x873Q0959655BH\xf1\x890712\xf1\x82\x0e1312001313001305171311052900', b'\xf1\x873Q0959655CM\xf1\x890720\xf1\x82\0161312001313001305171311052900', ], (Ecu.eps, 0x712, None): [ + b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\x0521N01842A1', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521N01342A1', b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00511N01805A0', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521N01309A1', From b22cadc04d569a6f3593fe32eaec3a3a0e21ef9b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 11 Jun 2023 13:26:41 -0700 Subject: [PATCH 222/283] thneed: cleanup duplicate GPU config (#28487) Co-authored-by: Comma Device --- selfdrive/modeld/thneed/thneed_qcom2.cc | 26 ------------------------- 1 file changed, 26 deletions(-) diff --git a/selfdrive/modeld/thneed/thneed_qcom2.cc b/selfdrive/modeld/thneed/thneed_qcom2.cc index eda037178a..a3bfb8a8c2 100644 --- a/selfdrive/modeld/thneed/thneed_qcom2.cc +++ b/selfdrive/modeld/thneed/thneed_qcom2.cc @@ -238,24 +238,6 @@ void Thneed::execute(float **finputs, float *foutput, bool slow) { // ****** copy inputs copy_inputs(finputs, true); - // ****** set power constraint - int ret; - struct kgsl_device_constraint_pwrlevel pwrlevel; - pwrlevel.level = KGSL_CONSTRAINT_PWR_MAX; - - struct kgsl_device_constraint constraint; - constraint.type = KGSL_CONSTRAINT_PWRLEVEL; - constraint.context_id = context_id; - constraint.data = (void*)&pwrlevel; - constraint.size = sizeof(pwrlevel); - - struct kgsl_device_getproperty prop; - prop.type = KGSL_PROP_PWR_CONSTRAINT; - prop.value = (void*)&constraint; - prop.sizebytes = sizeof(constraint); - ret = ioctl(fd, IOCTL_KGSL_SETPROPERTY, &prop); - assert(ret == 0); - // ****** run commands int i = 0; for (auto &it : cmds) { @@ -268,14 +250,6 @@ void Thneed::execute(float **finputs, float *foutput, bool slow) { // ****** copy outputs copy_output(foutput); - // ****** unset power constraint - constraint.type = KGSL_CONSTRAINT_NONE; - constraint.data = NULL; - constraint.size = 0; - - ret = ioctl(fd, IOCTL_KGSL_SETPROPERTY, &prop); - assert(ret == 0); - if (debug >= 1) { te = nanos_since_boot(); printf("model exec in %lu us\n", (te-tb)/1000); From bd34124a84e9d2b4fc370f2dc7dde9541d8d4b9e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 12 Jun 2023 04:41:23 +0800 Subject: [PATCH 223/283] replay: fix timeline issues (#28501) --- tools/replay/replay.cc | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index ad6ad4a43d..28adcffb92 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -137,8 +137,18 @@ void Replay::seekToFlag(FindFlag flag) { void Replay::buildTimeline() { uint64_t engaged_begin = 0; + bool engaged = false; + + auto alert_status = cereal::ControlsState::AlertStatus::NORMAL; + auto alert_size = cereal::ControlsState::AlertSize::NONE; uint64_t alert_begin = 0; - TimelineType alert_type = TimelineType::None; + std::string alert_type; + + const TimelineType timeline_types[] = { + [(int)cereal::ControlsState::AlertStatus::NORMAL] = TimelineType::AlertInfo, + [(int)cereal::ControlsState::AlertStatus::USER_PROMPT] = TimelineType::AlertWarning, + [(int)cereal::ControlsState::AlertStatus::CRITICAL] = TimelineType::AlertCritical, + }; for (auto it = segments_.cbegin(); it != segments_.cend() && !exit_; ++it) { LogReader log; @@ -150,26 +160,24 @@ void Replay::buildTimeline() { if (e->which == cereal::Event::Which::CONTROLS_STATE) { auto cs = e->event.getControlsState(); - if (!engaged_begin && cs.getEnabled()) { + if (engaged != cs.getEnabled()) { + if (engaged) { + std::lock_guard lk(timeline_lock); + timeline.push_back({toSeconds(engaged_begin), toSeconds(e->mono_time), TimelineType::Engaged}); + } engaged_begin = e->mono_time; - } else if (engaged_begin && !cs.getEnabled()) { - std::lock_guard lk(timeline_lock); - timeline.push_back({toSeconds(engaged_begin), toSeconds(e->mono_time), TimelineType::Engaged}); - engaged_begin = 0; + engaged = cs.getEnabled(); } - if (!alert_begin && cs.getAlertType().size() > 0) { - alert_begin = e->mono_time; - alert_type = TimelineType::AlertInfo; - if (cs.getAlertStatus() != cereal::ControlsState::AlertStatus::NORMAL) { - alert_type = cs.getAlertStatus() == cereal::ControlsState::AlertStatus::USER_PROMPT - ? TimelineType::AlertWarning - : TimelineType::AlertCritical; + if (alert_type != cs.getAlertType().cStr() || alert_status != cs.getAlertStatus()) { + if (!alert_type.empty() && alert_size != cereal::ControlsState::AlertSize::NONE) { + std::lock_guard lk(timeline_lock); + timeline.push_back({toSeconds(alert_begin), toSeconds(e->mono_time), timeline_types[(int)alert_status]}); } - } else if (alert_begin && cs.getAlertType().size() == 0) { - std::lock_guard lk(timeline_lock); - timeline.push_back({toSeconds(alert_begin), toSeconds(e->mono_time), alert_type}); - alert_begin = 0; + alert_begin = e->mono_time; + alert_type = cs.getAlertType().cStr(); + alert_size = cs.getAlertSize(); + alert_status = cs.getAlertStatus(); } } else if (e->which == cereal::Event::Which::USER_FLAG) { std::lock_guard lk(timeline_lock); From 2f117e88b775a0b53a3ae99ae943caaa66f952f2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 11 Jun 2023 14:43:25 -0700 Subject: [PATCH 224/283] test onroad: explicit memory leak check (#28502) --- selfdrive/controls/controlsd.py | 1 - selfdrive/test/test_onroad.py | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 82c66a20f9..4af1e65e5b 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -262,7 +262,6 @@ class Controls: if self.sm['deviceState'].freeSpacePercent < 7 and not SIMULATION: # under 7% of space free no enable allowed self.events.add(EventName.outOfSpace) - # TODO: make tici threshold the same if self.sm['deviceState'].memoryUsagePercent > 90 and not SIMULATION: self.events.add(EventName.lowMemory) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 12a3ef48ac..ef6ce65201 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -113,6 +113,7 @@ class TestOnroad(unittest.TestCase): os.environ['TESTING_CLOSET'] = '1' if os.path.exists(ROOT): shutil.rmtree(ROOT) + os.system("rm /dev/shm/*") # Make sure athena isn't running os.system("pkill -9 -f athena") @@ -256,6 +257,14 @@ class TestOnroad(unittest.TestCase): self.assertTrue(cpu_ok) + def test_memory_usage(self): + mems = [m.deviceState.memoryUsagePercent for m in self.service_msgs['deviceState']] + print("Memory usage: ", mems) + + # check for big leaks. note that memory usage is + # expected to go up while the MSGQ buffers fill up + self.assertLessEqual(max(mems) - min(mems), 3.0) + def test_camera_processing_time(self): result = "\n" result += "------------------------------------------------\n" From d8f677c5eb8c3e5e7e42042144680e5ac454fe52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 11 Jun 2023 15:02:42 -0700 Subject: [PATCH 225/283] Encoderd: encoders don't write, they only encode (#28499) * Encoders dont write, they encode * Delete words * unused --------- Co-authored-by: Harald Schaefer Co-authored-by: Adeeb Shihadeh --- system/loggerd/encoder/encoder.cc | 42 +----------------------- system/loggerd/encoder/encoder.h | 22 ++----------- system/loggerd/encoder/ffmpeg_encoder.cc | 2 -- system/loggerd/encoder/ffmpeg_encoder.h | 4 +-- system/loggerd/encoder/v4l_encoder.cc | 2 -- system/loggerd/encoder/v4l_encoder.h | 4 +-- system/loggerd/encoderd.cc | 4 +-- 7 files changed, 9 insertions(+), 71 deletions(-) diff --git a/system/loggerd/encoder/encoder.cc b/system/loggerd/encoder/encoder.cc index 08eaf0ff01..377e48d001 100644 --- a/system/loggerd/encoder/encoder.cc +++ b/system/loggerd/encoder/encoder.cc @@ -38,45 +38,5 @@ void VideoEncoder::publisher_publish(VideoEncoder *e, int segment_num, uint32_t auto words = new kj::Array(capnp::messageToFlatArray(msg)); auto bytes = words->asBytes(); e->pm->send(e->service_name, bytes.begin(), bytes.size()); - if (e->write) { - e->to_write.push(words); - } else { - delete words; - } -} - -// TODO: writing should be moved to loggerd -void VideoEncoder::write_handler(VideoEncoder *e, const char *path) { - VideoWriter writer(path, e->filename, e->codec != cereal::EncodeIndex::Type::FULL_H_E_V_C, e->out_width, e->out_height, e->fps, e->codec); - - bool first = true; - kj::Array* out_buf; - while ((out_buf = e->to_write.pop())) { - capnp::FlatArrayMessageReader cmsg(*out_buf); - cereal::Event::Reader event = cmsg.getRoot(); - - auto edata = (e->type == DriverCam) ? event.getDriverEncodeData() : - ((e->type == WideRoadCam) ? event.getWideRoadEncodeData() : - (e->in_width == e->out_width ? event.getRoadEncodeData() : event.getQRoadEncodeData())); - auto idx = edata.getIdx(); - auto flags = idx.getFlags(); - - if (first) { - assert(flags & V4L2_BUF_FLAG_KEYFRAME); - auto header = edata.getHeader(); - writer.write((uint8_t *)header.begin(), header.size(), idx.getTimestampEof()/1000, true, false); - first = false; - } - - // dangerous cast from const, but should be fine - auto data = edata.getData(); - if (data.size() > 0) { - writer.write((uint8_t *)data.begin(), data.size(), idx.getTimestampEof()/1000, false, flags & V4L2_BUF_FLAG_KEYFRAME); - } - - // free the data - delete out_buf; - } - - // VideoWriter is freed on out of scope + delete words; } diff --git a/system/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h index 88dd5cee23..564af625a1 100644 --- a/system/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -7,7 +7,6 @@ #include "cereal/messaging/messaging.h" #include "cereal/visionipc/visionipc.h" #include "common/queue.h" -#include "system/loggerd/video_writer.h" #include "system/camerad/cameras/camera_common.h" #define V4L2_BUF_FLAG_KEYFRAME 8 @@ -15,9 +14,9 @@ class VideoEncoder { public: VideoEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : filename(filename), type(type), in_width(in_width), in_height(in_height), fps(fps), - bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height), write(write) { } + bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height) { } virtual ~VideoEncoder(); virtual int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) = 0; virtual void encoder_open(const char* path) = 0; @@ -26,20 +25,8 @@ public: void publisher_init(); static void publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr header, kj::ArrayPtr dat); - void writer_open(const char* path) { - if (this->write) write_handler_thread = std::thread(VideoEncoder::write_handler, this, path); - } - - void writer_close() { - if (this->write) { - to_write.push(NULL); - write_handler_thread.join(); - } - assert(to_write.empty()); - } protected: - bool write; const char* filename; int in_width, in_height; int out_width, out_height, fps; @@ -54,9 +41,4 @@ private: // publishing std::unique_ptr pm; const char *service_name; - - // writing support - static void write_handler(VideoEncoder *e, const char *path); - std::thread write_handler_thread; - SafeQueue* > to_write; }; diff --git a/system/loggerd/encoder/ffmpeg_encoder.cc b/system/loggerd/encoder/ffmpeg_encoder.cc index 275da34f18..af05b5df97 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.cc +++ b/system/loggerd/encoder/ffmpeg_encoder.cc @@ -60,7 +60,6 @@ void FfmpegEncoder::encoder_open(const char* path) { int err = avcodec_open2(this->codec_ctx, codec, NULL); assert(err >= 0); - writer_open(path); is_open = true; segment_num++; counter = 0; @@ -69,7 +68,6 @@ void FfmpegEncoder::encoder_open(const char* path) { void FfmpegEncoder::encoder_close() { if (!is_open) return; - writer_close(); avcodec_free_context(&codec_ctx); is_open = false; } diff --git a/system/loggerd/encoder/ffmpeg_encoder.h b/system/loggerd/encoder/ffmpeg_encoder.h index 9095a6e815..1ba991f09b 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.h +++ b/system/loggerd/encoder/ffmpeg_encoder.h @@ -17,8 +17,8 @@ extern "C" { class FfmpegEncoder : public VideoEncoder { public: FfmpegEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height, write) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height) { encoder_init(); } ~FfmpegEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoder/v4l_encoder.cc b/system/loggerd/encoder/v4l_encoder.cc index 16e7246ff4..976839eef3 100644 --- a/system/loggerd/encoder/v4l_encoder.cc +++ b/system/loggerd/encoder/v4l_encoder.cc @@ -255,7 +255,6 @@ void V4LEncoder::encoder_init() { void V4LEncoder::encoder_open(const char* path) { dequeue_handler_thread = std::thread(V4LEncoder::dequeue_handler, this); - writer_open(path); this->is_open = true; this->counter = 0; } @@ -288,7 +287,6 @@ void V4LEncoder::encoder_close() { // join waits for V4L2_QCOM_BUF_FLAG_EOS dequeue_handler_thread.join(); assert(extras.empty()); - writer_close(); } this->is_open = false; } diff --git a/system/loggerd/encoder/v4l_encoder.h b/system/loggerd/encoder/v4l_encoder.h index d4b0a1211d..1016c0f5c6 100644 --- a/system/loggerd/encoder/v4l_encoder.h +++ b/system/loggerd/encoder/v4l_encoder.h @@ -9,8 +9,8 @@ class V4LEncoder : public VideoEncoder { public: V4LEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, bool write) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height, write) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height) { encoder_init(); } ~V4LEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoderd.cc b/system/loggerd/encoderd.cc index 12b58b6591..45120ec334 100644 --- a/system/loggerd/encoderd.cc +++ b/system/loggerd/encoderd.cc @@ -57,13 +57,13 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { encoders.push_back(new Encoder(cam_info.filename, cam_info.type, buf_info.width, buf_info.height, cam_info.fps, cam_info.bitrate, cam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - buf_info.width, buf_info.height, false)); + buf_info.width, buf_info.height)); // qcamera encoder if (cam_info.has_qcamera) { encoders.push_back(new Encoder(qcam_info.filename, cam_info.type, buf_info.width, buf_info.height, qcam_info.fps, qcam_info.bitrate, qcam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - qcam_info.frame_width, qcam_info.frame_height, false)); + qcam_info.frame_width, qcam_info.frame_height)); } } else { LOGE("not initting empty encoder"); From ac45b77d3bd86d7f6fc6fdb740bdfd28a5dea9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 11 Jun 2023 22:23:40 -0700 Subject: [PATCH 226/283] Encoderd: give every camera stream list of encoder streams (#28480) * Compiles * fixed something * CLEANUP * todo * More cleanup * Add TODO * Update loggerd.cc * remove write here too --- system/loggerd/encoder/encoder.cc | 4 +- system/loggerd/encoder/encoder.h | 7 +- system/loggerd/encoder/ffmpeg_encoder.h | 6 +- system/loggerd/encoder/v4l_encoder.h | 4 +- system/loggerd/encoderd.cc | 23 ++---- system/loggerd/loggerd.cc | 26 +++--- system/loggerd/loggerd.h | 105 +++++++++++++----------- 7 files changed, 89 insertions(+), 86 deletions(-) diff --git a/system/loggerd/encoder/encoder.cc b/system/loggerd/encoder/encoder.cc index 377e48d001..7ac2948861 100644 --- a/system/loggerd/encoder/encoder.cc +++ b/system/loggerd/encoder/encoder.cc @@ -5,9 +5,7 @@ VideoEncoder::~VideoEncoder() {} void VideoEncoder::publisher_init() { // publish - service_name = this->type == DriverCam ? "driverEncodeData" : - (this->type == WideRoadCam ? "wideRoadEncodeData" : - (this->in_width == this->out_width ? "roadEncodeData" : "qRoadEncodeData")); + service_name = this->publish_name; pm.reset(new PubMaster({service_name})); } diff --git a/system/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h index 564af625a1..9ea6b884cf 100644 --- a/system/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -14,9 +14,11 @@ class VideoEncoder { public: VideoEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, + const char* publish_name) : filename(filename), type(type), in_width(in_width), in_height(in_height), fps(fps), - bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height) { } + bitrate(bitrate), codec(codec), out_width(out_width), out_height(out_height), + publish_name(publish_name) { } virtual ~VideoEncoder(); virtual int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) = 0; virtual void encoder_open(const char* path) = 0; @@ -28,6 +30,7 @@ public: protected: const char* filename; + const char* publish_name; int in_width, in_height; int out_width, out_height, fps; int bitrate; diff --git a/system/loggerd/encoder/ffmpeg_encoder.h b/system/loggerd/encoder/ffmpeg_encoder.h index 1ba991f09b..6b4b6e104c 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.h +++ b/system/loggerd/encoder/ffmpeg_encoder.h @@ -17,8 +17,10 @@ extern "C" { class FfmpegEncoder : public VideoEncoder { public: FfmpegEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height) { encoder_init(); } + + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, + const char* publish_name) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, cereal::EncodeIndex::Type::BIG_BOX_LOSSLESS, out_width, out_height, publish_name) { encoder_init(); } ~FfmpegEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoder/v4l_encoder.h b/system/loggerd/encoder/v4l_encoder.h index 1016c0f5c6..b0af4039fe 100644 --- a/system/loggerd/encoder/v4l_encoder.h +++ b/system/loggerd/encoder/v4l_encoder.h @@ -9,8 +9,8 @@ class V4LEncoder : public VideoEncoder { public: V4LEncoder(const char* filename, CameraType type, int in_width, int in_height, int fps, - int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height) : - VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height) { encoder_init(); } + int bitrate, cereal::EncodeIndex::Type codec, int out_width, int out_height, const char* publish_name) : + VideoEncoder(filename, type, in_width, in_height, fps, bitrate, codec, out_width, out_height, publish_name) { encoder_init(); } ~V4LEncoder(); void encoder_init(); int encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra); diff --git a/system/loggerd/encoderd.cc b/system/loggerd/encoderd.cc index 45120ec334..24d4dad2d9 100644 --- a/system/loggerd/encoderd.cc +++ b/system/loggerd/encoderd.cc @@ -35,7 +35,7 @@ bool sync_encoders(EncoderdState *s, CameraType cam_type, uint32_t frame_id) { void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { - util::set_thread_name(cam_info.filename); + util::set_thread_name(cam_info.encoder_infos[0].filename); std::vector encoders; VisionIpcClient vipc_client = VisionIpcClient("camerad", cam_info.stream_type, false); @@ -50,20 +50,15 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { // init encoders if (encoders.empty()) { VisionBuf buf_info = vipc_client.buffers[0]; - LOGW("encoder %s init %dx%d", cam_info.filename, buf_info.width, buf_info.height); + LOGW("encoder %s init %dx%d", cam_info.encoder_infos[0].filename, buf_info.width, buf_info.height); if (buf_info.width > 0 && buf_info.height > 0) { - // main encoder - encoders.push_back(new Encoder(cam_info.filename, cam_info.type, buf_info.width, buf_info.height, - cam_info.fps, cam_info.bitrate, - cam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - buf_info.width, buf_info.height)); - // qcamera encoder - if (cam_info.has_qcamera) { - encoders.push_back(new Encoder(qcam_info.filename, cam_info.type, buf_info.width, buf_info.height, - qcam_info.fps, qcam_info.bitrate, - qcam_info.is_h265 ? cereal::EncodeIndex::Type::FULL_H_E_V_C : cereal::EncodeIndex::Type::QCAMERA_H264, - qcam_info.frame_width, qcam_info.frame_height)); + for (const auto &encoder_info: cam_info.encoder_infos){ + encoders.push_back(new Encoder(encoder_info.filename, cam_info.type, buf_info.width, buf_info.height, + encoder_info.fps, encoder_info.bitrate, + encoder_info.encode_type, + encoder_info.frame_width, encoder_info.frame_height, + encoder_info.publish_name)); } } else { LOGE("not initting empty encoder"); @@ -85,7 +80,7 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { // detect loop around and drop the frames if (buf->get_frame_id() != extra.frame_id) { if (!lagging) { - LOGE("encoder %s lag buffer id: %d extra id: %d", cam_info.filename, buf->get_frame_id(), extra.frame_id); + LOGE("encoder %s lag buffer id: %d extra id: %d", cam_info.encoder_infos[0].filename, buf->get_frame_id(), extra.frame_id); lagging = true; } continue; diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc index a7f7db4801..dbda432192 100644 --- a/system/loggerd/loggerd.cc +++ b/system/loggerd/loggerd.cc @@ -58,15 +58,13 @@ struct RemoteEncoder { bool seen_first_packet = false; }; -int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct RemoteEncoder &re) { - const LogCameraInfo &cam_info = (name == "driverEncodeData") ? cameras_logged[1] : - ((name == "wideRoadEncodeData") ? cameras_logged[2] : - ((name == "qRoadEncodeData") ? qcam_info : cameras_logged[0])); +int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct RemoteEncoder &re, EncoderInfo encoder_info) { int bytes_count = 0; // extract the message capnp::FlatArrayMessageReader cmsg(kj::ArrayPtr((capnp::word *)msg->getData(), msg->getSize() / sizeof(capnp::word))); auto event = cmsg.getRoot(); + // TODO this should be dealt with generically auto edata = (name == "driverEncodeData") ? event.getDriverEncodeData() : ((name == "wideRoadEncodeData") ? event.getWideRoadEncodeData() : ((name == "qRoadEncodeData") ? event.getQRoadEncodeData() : event.getRoadEncodeData())); @@ -95,7 +93,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct // we are in this segment now, process any queued messages before this one if (!re.q.empty()) { for (auto &qmsg: re.q) { - bytes_count += handle_encoder_msg(s, qmsg, name, re); + bytes_count += handle_encoder_msg(s, qmsg, name, re, encoder_info); } re.q.clear(); } @@ -111,10 +109,10 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct re.dropped_frames = 0; } // if we aren't actually recording, don't create the writer - if (cam_info.record) { + if (encoder_info.record) { re.writer.reset(new VideoWriter(s->segment_path, - cam_info.filename, idx.getType() != cereal::EncodeIndex::Type::FULL_H_E_V_C, - cam_info.frame_width, cam_info.frame_height, cam_info.fps, idx.getType())); + encoder_info.filename, idx.getType() != cereal::EncodeIndex::Type::FULL_H_E_V_C, + encoder_info.frame_width, encoder_info.frame_height, encoder_info.fps, idx.getType())); // write the header auto header = edata.getHeader(); re.writer->write((uint8_t *)header.begin(), header.size(), idx.getTimestampEof()/1000, true, false); @@ -142,6 +140,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct MessageBuilder bmsg; auto evt = bmsg.initEvent(event.getValid()); evt.setLogMonoTime(event.getLogMonoTime()); + // TODO this should be dealt with generically if (name == "driverEncodeData") { evt.setDriverEncodeIdx(idx); } if (name == "wideRoadEncodeData") { evt.setWideRoadEncodeIdx(idx); } if (name == "qRoadEncodeData") { evt.setQRoadEncodeIdx(idx); } @@ -211,11 +210,12 @@ void loggerd_thread() { logger_rotate(&s); Params().put("CurrentRoute", s.logger.route_name); - // init encoders - s.last_camera_seen_tms = millis_since_boot(); + std::map encoder_infos_dict; for (const auto &cam : cameras_logged) { - s.max_waiting++; - if (cam.has_qcamera) { s.max_waiting++; } + for (const auto &encoder_info: cam.encoder_infos) { + encoder_infos_dict[encoder_info.publish_name] = encoder_info; + s.max_waiting++; + } } uint64_t msg_count = 0, bytes_count = 0; @@ -234,7 +234,7 @@ void loggerd_thread() { if (qs.encoder) { s.last_camera_seen_tms = millis_since_boot(); - bytes_count += handle_encoder_msg(&s, msg, qs.name, remote_encoders[sock]); + bytes_count += handle_encoder_msg(&s, msg, qs.name, remote_encoders[sock], encoder_infos_dict[qs.name]); } else { logger_log(&s.logger, (uint8_t *)msg->getData(), msg->getSize(), in_qlog); bytes_count += msg->getSize(); diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h index 1b8f9e0d2a..01aa5b434c 100644 --- a/system/loggerd/loggerd.h +++ b/system/loggerd/loggerd.h @@ -42,62 +42,67 @@ const int DCAM_BITRATE = MAIN_BITRATE; const bool LOGGERD_TEST = getenv("LOGGERD_TEST"); const int SEGMENT_LENGTH = LOGGERD_TEST ? atoi(getenv("LOGGERD_SEGMENT_LENGTH")) : 60; -struct LogCameraInfo { - CameraType type; +class EncoderInfo { +public: + const char *publish_name; const char *filename; - VisionStreamType stream_type; - int frame_width, frame_height; - int fps; - int bitrate; - bool is_h265; - bool has_qcamera; - bool record; + bool record = true; + int frame_width = 1928; + int frame_height = 1208; + int fps = MAIN_FPS; + int bitrate = MAIN_BITRATE; + cereal::EncodeIndex::Type encode_type = cereal::EncodeIndex::Type::FULL_H_E_V_C; }; -const LogCameraInfo cameras_logged[] = { - { - .type = RoadCam, - .stream_type = VISION_STREAM_ROAD, - .filename = "fcamera.hevc", - .fps = MAIN_FPS, - .bitrate = MAIN_BITRATE, - .is_h265 = true, - .has_qcamera = true, - .record = true, - .frame_width = 1928, - .frame_height = 1208, - }, - { - .type = DriverCam, - .stream_type = VISION_STREAM_DRIVER, - .filename = "dcamera.hevc", - .fps = MAIN_FPS, - .bitrate = DCAM_BITRATE, - .is_h265 = true, - .has_qcamera = false, - .record = Params().getBool("RecordFront"), - .frame_width = 1928, - .frame_height = 1208, - }, - { - .type = WideRoadCam, - .stream_type = VISION_STREAM_WIDE_ROAD, - .filename = "ecamera.hevc", - .fps = MAIN_FPS, - .bitrate = MAIN_BITRATE, - .is_h265 = true, - .has_qcamera = false, - .record = true, - .frame_width = 1928, - .frame_height = 1208, - }, +class LogCameraInfo { +public: + int fps = MAIN_FPS; + CameraType type; + VisionStreamType stream_type; + std::vector encoder_infos; }; -const LogCameraInfo qcam_info = { + +const EncoderInfo main_road_encoder_info = { + .publish_name = "roadEncodeData", + .filename = "fcamera.hevc", +}; +const EncoderInfo main_wide_road_encoder_info = { + .publish_name = "wideRoadEncodeData", + .filename = "ecamera.hevc", +}; +const EncoderInfo main_driver_encoder_info = { + .publish_name = "driverEncodeData", + .filename = "dcamera.hevc", + .record = Params().getBool("RecordFront"), +}; + +const EncoderInfo qcam_encoder_info = { + .publish_name = "qRoadEncodeData", .filename = "qcamera.ts", - .fps = MAIN_FPS, .bitrate = 256000, - .is_h265 = false, - .record = true, + .encode_type = cereal::EncodeIndex::Type::QCAMERA_H264, .frame_width = 526, .frame_height = 330, }; + + +const LogCameraInfo road_camera_info{ + .type = RoadCam, + .stream_type = VISION_STREAM_ROAD, + .encoder_infos = {main_road_encoder_info, qcam_encoder_info} + }; + +const LogCameraInfo wide_road_camera_info{ + .type = WideRoadCam, + .stream_type = VISION_STREAM_WIDE_ROAD, + .encoder_infos = {main_wide_road_encoder_info} + }; + +const LogCameraInfo driver_camera_info{ + .type = DriverCam, + .stream_type = VISION_STREAM_DRIVER, + .encoder_infos = {main_driver_encoder_info} + }; + +const LogCameraInfo cameras_logged[] = {road_camera_info, wide_road_camera_info, driver_camera_info}; + From 5df4ac61d37334c568745d7b78e2853d48d481bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 11 Jun 2023 23:25:16 -0700 Subject: [PATCH 227/283] Encoderd: Give encoder threads good names (#28508) --- system/loggerd/encoderd.cc | 6 +++--- system/loggerd/loggerd.h | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/system/loggerd/encoderd.cc b/system/loggerd/encoderd.cc index 24d4dad2d9..b4f0b913e5 100644 --- a/system/loggerd/encoderd.cc +++ b/system/loggerd/encoderd.cc @@ -35,7 +35,7 @@ bool sync_encoders(EncoderdState *s, CameraType cam_type, uint32_t frame_id) { void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { - util::set_thread_name(cam_info.encoder_infos[0].filename); + util::set_thread_name(cam_info.thread_name); std::vector encoders; VisionIpcClient vipc_client = VisionIpcClient("camerad", cam_info.stream_type, false); @@ -50,7 +50,7 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { // init encoders if (encoders.empty()) { VisionBuf buf_info = vipc_client.buffers[0]; - LOGW("encoder %s init %dx%d", cam_info.encoder_infos[0].filename, buf_info.width, buf_info.height); + LOGW("encoder %s init %dx%d", cam_info.thread_name, buf_info.width, buf_info.height); if (buf_info.width > 0 && buf_info.height > 0) { for (const auto &encoder_info: cam_info.encoder_infos){ @@ -80,7 +80,7 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) { // detect loop around and drop the frames if (buf->get_frame_id() != extra.frame_id) { if (!lagging) { - LOGE("encoder %s lag buffer id: %d extra id: %d", cam_info.encoder_infos[0].filename, buf->get_frame_id(), extra.frame_id); + LOGE("encoder %s lag buffer id: %d extra id: %d", cam_info.thread_name, buf->get_frame_id(), extra.frame_id); lagging = true; } continue; diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h index 01aa5b434c..1333b72318 100644 --- a/system/loggerd/loggerd.h +++ b/system/loggerd/loggerd.h @@ -35,7 +35,6 @@ constexpr int MAIN_FPS = 20; const int MAIN_BITRATE = 10000000; -const int DCAM_BITRATE = MAIN_BITRATE; #define NO_CAMERA_PATIENCE 500 // fall back to time-based rotation if all cameras are dead @@ -56,6 +55,7 @@ public: class LogCameraInfo { public: + const char *thread_name; int fps = MAIN_FPS; CameraType type; VisionStreamType stream_type; @@ -87,18 +87,21 @@ const EncoderInfo qcam_encoder_info = { const LogCameraInfo road_camera_info{ + .thread_name = "road_cam_encoder", .type = RoadCam, .stream_type = VISION_STREAM_ROAD, .encoder_infos = {main_road_encoder_info, qcam_encoder_info} }; const LogCameraInfo wide_road_camera_info{ + .thread_name = "wide_road_cam_encoder", .type = WideRoadCam, .stream_type = VISION_STREAM_WIDE_ROAD, .encoder_infos = {main_wide_road_encoder_info} }; const LogCameraInfo driver_camera_info{ + .thread_name = "driver_cam_encoder", .type = DriverCam, .stream_type = VISION_STREAM_DRIVER, .encoder_infos = {main_driver_encoder_info} From 2453d3a04b38c59447184bde08e76aed66be3439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 12 Jun 2023 00:08:00 -0700 Subject: [PATCH 228/283] Encoderd: refactor msg getters and setters (#28509) * Encoderd: refactor msg getters and setters * whitespace * whitespace * whitespace --- system/loggerd/loggerd.cc | 11 ++--------- system/loggerd/loggerd.h | 10 ++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc index dbda432192..9ad3687613 100644 --- a/system/loggerd/loggerd.cc +++ b/system/loggerd/loggerd.cc @@ -64,10 +64,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct // extract the message capnp::FlatArrayMessageReader cmsg(kj::ArrayPtr((capnp::word *)msg->getData(), msg->getSize() / sizeof(capnp::word))); auto event = cmsg.getRoot(); - // TODO this should be dealt with generically - auto edata = (name == "driverEncodeData") ? event.getDriverEncodeData() : - ((name == "wideRoadEncodeData") ? event.getWideRoadEncodeData() : - ((name == "qRoadEncodeData") ? event.getQRoadEncodeData() : event.getRoadEncodeData())); + auto edata = (event.*(encoder_info.get_encode_data_func))(); auto idx = edata.getIdx(); auto flags = idx.getFlags(); @@ -140,11 +137,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct MessageBuilder bmsg; auto evt = bmsg.initEvent(event.getValid()); evt.setLogMonoTime(event.getLogMonoTime()); - // TODO this should be dealt with generically - if (name == "driverEncodeData") { evt.setDriverEncodeIdx(idx); } - if (name == "wideRoadEncodeData") { evt.setWideRoadEncodeIdx(idx); } - if (name == "qRoadEncodeData") { evt.setQRoadEncodeIdx(idx); } - if (name == "roadEncodeData") { evt.setRoadEncodeIdx(idx); } + (evt.*(encoder_info.set_encode_idx_func))(idx); auto new_msg = bmsg.toBytes(); logger_log(&s->logger, (uint8_t *)new_msg.begin(), new_msg.size(), true); // always in qlog? bytes_count += new_msg.size(); diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h index 1333b72318..579b079dbb 100644 --- a/system/loggerd/loggerd.h +++ b/system/loggerd/loggerd.h @@ -51,6 +51,8 @@ public: int fps = MAIN_FPS; int bitrate = MAIN_BITRATE; cereal::EncodeIndex::Type encode_type = cereal::EncodeIndex::Type::FULL_H_E_V_C; + ::cereal::EncodeData::Reader (cereal::Event::Reader::*get_encode_data_func)() const; + void (cereal::Event::Builder::*set_encode_idx_func)(::cereal::EncodeIndex::Reader); }; class LogCameraInfo { @@ -65,15 +67,21 @@ public: const EncoderInfo main_road_encoder_info = { .publish_name = "roadEncodeData", .filename = "fcamera.hevc", + .get_encode_data_func = &cereal::Event::Reader::getRoadEncodeData, + .set_encode_idx_func = &cereal::Event::Builder::setRoadEncodeIdx, }; const EncoderInfo main_wide_road_encoder_info = { .publish_name = "wideRoadEncodeData", .filename = "ecamera.hevc", + .get_encode_data_func = &cereal::Event::Reader::getWideRoadEncodeData, + .set_encode_idx_func = &cereal::Event::Builder::setWideRoadEncodeIdx, }; const EncoderInfo main_driver_encoder_info = { .publish_name = "driverEncodeData", .filename = "dcamera.hevc", .record = Params().getBool("RecordFront"), + .get_encode_data_func = &cereal::Event::Reader::getDriverEncodeData, + .set_encode_idx_func = &cereal::Event::Builder::setDriverEncodeIdx, }; const EncoderInfo qcam_encoder_info = { @@ -83,6 +91,8 @@ const EncoderInfo qcam_encoder_info = { .encode_type = cereal::EncodeIndex::Type::QCAMERA_H264, .frame_width = 526, .frame_height = 330, + .get_encode_data_func = &cereal::Event::Reader::getQRoadEncodeData, + .set_encode_idx_func = &cereal::Event::Builder::setQRoadEncodeIdx, }; From 4ae0378f639826df5cc1518574842b61b118f371 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Jun 2023 04:40:43 +0800 Subject: [PATCH 229/283] automatically detect available camera streams (#27640) * remove WideCameraOnly * check in set_initial_state * no block * remove try block * apply reviews --- common/params.cc | 1 - selfdrive/controls/controlsd.py | 7 +++-- selfdrive/modeld/modeld.cc | 15 ++++++++-- .../test/process_replay/process_replay.py | 1 - tools/sim/bridge.py | 29 +++++++------------ 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/common/params.cc b/common/params.cc index be285c6aa2..0e6b644023 100644 --- a/common/params.cc +++ b/common/params.cc @@ -186,7 +186,6 @@ std::unordered_map keys = { {"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START}, {"Version", PERSISTENT}, {"VisionRadarToggle", PERSISTENT}, - {"WideCameraOnly", PERSISTENT}, {"ApiCache_Device", PERSISTENT}, {"ApiCache_DriveStats", PERSISTENT}, {"ApiCache_NavDestinations", PERSISTENT}, diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 4af1e65e5b..0cdb6cd96f 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -9,6 +9,7 @@ from common.realtime import sec_since_boot, config_realtime_process, Priority, R from common.profiler import Profiler from common.params import Params, put_nonblocking import cereal.messaging as messaging +from cereal.visionipc import VisionIpcClient, VisionStreamType from common.conversions import Conversions as CV from panda import ALTERNATIVE_EXPERIENCE from system.swaglog import cloudlog @@ -82,8 +83,6 @@ class Controls: ignore = ['testJoystick'] if SIMULATION: ignore += ['driverCameraState', 'managerState'] - if self.params.get_bool('WideCameraOnly'): - ignore += ['roadCameraState'] self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'testJoystick'] + self.camera_packets, @@ -438,6 +437,10 @@ class Controls: all_valid = CS.canValid and self.sm.all_checks() timed_out = self.sm.frame * DT_CTRL > (6. if REPLAY else 3.5) if all_valid or timed_out or SIMULATION: + available_streams = VisionIpcClient.available_streams("camerad", block=False) + if VisionStreamType.VISION_STREAM_ROAD not in available_streams: + self.sm.ignore_alive.append('roadCameraState') + if not self.read_only: self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 0a8a8d6358..9c8412d70d 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -179,9 +179,6 @@ int main(int argc, char **argv) { assert(ret == 0); } - bool main_wide_camera = Params().getBool("WideCameraOnly"); - bool use_extra_client = !main_wide_camera; // set for single camera mode - // cl init cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); cl_context context = CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err)); @@ -191,6 +188,18 @@ int main(int argc, char **argv) { model_init(&model, device_id, context); LOGW("models loaded, modeld starting"); + bool main_wide_camera = false; + while (!do_exit) { + auto streams = VisionIpcClient::getAvailableStreams("camerad", false); + if (!streams.empty()) { + main_wide_camera = streams.count(VISION_STREAM_ROAD) == 0; + break; + } + + util::sleep_for(100); + } + + bool use_extra_client = !main_wide_camera; // set for single camera mode VisionIpcClient vipc_client_main = VisionIpcClient("camerad", main_wide_camera ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD, true, device_id, context); VisionIpcClient vipc_client_extra = VisionIpcClient("camerad", VISION_STREAM_WIDE_ROAD, false, device_id, context); diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 22d1516373..13dfb661b7 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -459,7 +459,6 @@ def setup_env(CP=None, cfg=None, controlsState=None, lr=None, fingerprint=None, params.put_bool("OpenpilotEnabledToggle", True) params.put_bool("Passive", False) params.put_bool("DisengageOnAccelerator", True) - params.put_bool("WideCameraOnly", False) params.put_bool("DisableLogging", False) os.environ["NO_RADAR_SLEEP"] = "1" diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index 7bb12badb2..adb477b664 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -254,7 +254,6 @@ class CarlaBridge: msg.liveCalibration.validBlocks = 20 msg.liveCalibration.rpyCalib = [0.0, 0.0, 0.0] self.params.put("CalibrationParams", msg.to_bytes()) - self.params.put_bool("WideCameraOnly", not arguments.dual_camera) self._args = arguments self._carla_objects = [] @@ -545,23 +544,17 @@ if __name__ == "__main__": q: Any = Queue() args = parse_args() - try: - carla_bridge = CarlaBridge(args) - p = carla_bridge.run(q) + carla_bridge = CarlaBridge(args) + p = carla_bridge.run(q) - if args.joystick: - # start input poll for joystick - from tools.sim.lib.manual_ctrl import wheel_poll_thread + if args.joystick: + # start input poll for joystick + from tools.sim.lib.manual_ctrl import wheel_poll_thread - wheel_poll_thread(q) - else: - # start input poll for keyboard - from tools.sim.lib.keyboard_ctrl import keyboard_poll_thread + wheel_poll_thread(q) + else: + # start input poll for keyboard + from tools.sim.lib.keyboard_ctrl import keyboard_poll_thread - keyboard_poll_thread(q) - p.join() - - finally: - # Try cleaning up the wide camera param - # in case users want to use replay after - Params().remove("WideCameraOnly") + keyboard_poll_thread(q) + p.join() From d96361970b32a76422dc1acc7a78e5bdd55a4bed Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Jun 2023 13:50:38 -0700 Subject: [PATCH 230/283] thermald: common min date (#28457) * thermald: common min date * add to release files --- common/time.py | 3 +++ common/util.cc | 2 +- release/files_common | 1 + selfdrive/boardd/set_time.py | 2 +- selfdrive/thermald/thermald.py | 3 ++- 5 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 common/time.py diff --git a/common/time.py b/common/time.py new file mode 100644 index 0000000000..8dac17815d --- /dev/null +++ b/common/time.py @@ -0,0 +1,3 @@ +import datetime + +MIN_DATE = datetime.datetime(year=2023, month=6, day=1) diff --git a/common/util.cc b/common/util.cc index a527adcbef..55a8b1fb3e 100644 --- a/common/util.cc +++ b/common/util.cc @@ -260,7 +260,7 @@ struct tm get_time() { bool time_valid(struct tm sys_time) { int year = 1900 + sys_time.tm_year; int month = 1 + sys_time.tm_mon; - return (year > 2021) || (year == 2021 && month >= 6); + return (year > 2023) || (year == 2023 && month >= 6); } } // namespace util diff --git a/release/files_common b/release/files_common index af1fca176f..e90a8e083b 100644 --- a/release/files_common +++ b/release/files_common @@ -35,6 +35,7 @@ common/filter_simple.py common/stat_live.py common/spinner.py common/text_window.py +common/time.py common/kalman/.gitignore common/kalman/* diff --git a/selfdrive/boardd/set_time.py b/selfdrive/boardd/set_time.py index 2159eba5eb..93453dcd97 100755 --- a/selfdrive/boardd/set_time.py +++ b/selfdrive/boardd/set_time.py @@ -3,7 +3,7 @@ import os import datetime from panda import Panda -MIN_DATE = datetime.datetime(year=2023, month=4, day=1) +from common.time import MIN_DATE def set_time(logger): sys_time = datetime.datetime.today() diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index aa78978619..b10e87d404 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -13,6 +13,7 @@ import psutil import cereal.messaging as messaging from cereal import log from common.dict_helpers import strip_deprecated_keys +from common.time import MIN_DATE from common.filter_simple import FirstOrderFilter from common.params import Params from common.realtime import DT_TRML, sec_since_boot @@ -272,7 +273,7 @@ def thermald_thread(end_event, hw_queue): # Ensure date/time are valid now = datetime.datetime.utcnow() - startup_conditions["time_valid"] = (now.year > 2020) or (now.year == 2020 and now.month >= 10) + startup_conditions["time_valid"] = now > MIN_DATE set_offroad_alert_if_changed("Offroad_InvalidTime", (not startup_conditions["time_valid"])) startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate") From 9632451d1d6a726d389a91bd47261c0acda1a6ae Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Jun 2023 04:58:41 +0800 Subject: [PATCH 231/283] cabana: display signal details in tooltip (#28471) * show details in tooltip * display tooltip in signalView * cleanup * setHeader before sortByColumn * more compact tooltip * move to util --- tools/cabana/binaryview.cc | 19 ++++++++++--------- tools/cabana/binaryview.h | 2 +- tools/cabana/messageswidget.cc | 2 +- tools/cabana/signalview.cc | 16 +--------------- tools/cabana/signalview.h | 1 - tools/cabana/util.cc | 10 ++++++++++ tools/cabana/util.h | 1 + 7 files changed, 24 insertions(+), 27 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 9865907069..ed93a07e40 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -127,15 +127,6 @@ void BinaryView::highlight(const cabana::Signal *sig) { } } - if (sig && underMouse()) { - QString tooltip = tr(R"(%1
- Size:%2 LE:%3 SGD:%4 - )").arg(sig->name).arg(sig->size).arg(sig->is_little_endian ? "Y" : "N").arg(sig->is_signed ? "Y" : "N"); - QToolTip::showText(QCursor::pos(), tooltip, this, rect()); - } else { - QToolTip::showText(QCursor::pos(), "", this, rect()); - } - hovered_sig = sig; emit signalHovered(hovered_sig); } @@ -349,6 +340,16 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i return {}; } +QVariant BinaryViewModel::data(const QModelIndex &index, int role) const { + if (role == Qt::ToolTipRole) { + auto item = (const BinaryViewModel::Item *)index.internalPointer(); + if (item && !item->sigs.empty()) { + return signalToolTip(item->sigs.back()); + } + } + return {}; +} + // BinaryItemDelegate BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index baeb79cba7..d9966c9110 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -28,7 +28,7 @@ public: void updateState(); void updateItem(int row, int col, const QString &val, const QColor &color); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return {}; } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_count; } int columnCount(const QModelIndex &parent = QModelIndex()) const override { return column_count; } inline QModelIndex bitIndex(int bit, bool is_lb) const { return index(bit / 8, is_lb ? (7 - bit % 8) : bit % 8); } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 94b539505c..2e2087dece 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -33,6 +33,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { view->setItemDelegate(delegate); view->setModel(model); + view->setHeader(header); view->setSortingEnabled(true); view->sortByColumn(MessageListModel::Column::NAME, Qt::AscendingOrder); view->setAllColumnsShowFocus(true); @@ -40,7 +41,6 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { view->setItemsExpandable(false); view->setIndentation(0); view->setRootIsDecorated(false); - view->setHeader(header); // Must be called before setting any header parameters to avoid overriding restoreHeaderState(settings.message_header_state); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 46dfef1004..71186bbdf1 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -146,7 +146,7 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { } else if (role == Qt::DecorationRole && index.column() == 0 && item->type == Item::ExtraInfo) { return utils::icon(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up"); } else if (role == Qt::ToolTipRole && item->type == Item::Sig) { - return (index.column() == 0) ? item->sig->name : item->sig_val; + return (index.column() == 0) ? signalToolTip(item->sig) : QString(); } } return {}; @@ -300,20 +300,6 @@ QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo return {width, QApplication::fontMetrics().height()}; } -bool SignalItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { - if (event && event->type() == QEvent::ToolTip && index.isValid()) { - auto item = (SignalModel::Item *)index.internalPointer(); - if (item->type == SignalModel::Item::Sig && index.column() == 1) { - QRect rc = option.rect.adjusted(0, 0, -option.rect.width() * 0.4, 0); - if (rc.contains(event->pos())) { - event->setAccepted(false); - return false; - } - } - } - return QStyledItemDelegate::helpEvent(event, view, option, index); -} - void SignalItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (SignalModel::Item *)index.internalPointer(); if (editor && item->type == SignalModel::Item::Sig && index.column() == 1) { diff --git a/tools/cabana/signalview.h b/tools/cabana/signalview.h index 02741234a6..f5924c1f5d 100644 --- a/tools/cabana/signalview.h +++ b/tools/cabana/signalview.h @@ -85,7 +85,6 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QValidator *name_validator, *double_validator; diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 7a606b133e..3cf328e1e0 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -230,3 +230,13 @@ int num_decimals(double num) { auto dot_pos = string.indexOf('.'); return dot_pos == -1 ? 0 : string.size() - dot_pos - 1; } + +QString signalToolTip(const cabana::Signal *sig) { + return QObject::tr(R"( + %1
+ Start Bit: %2 Size: %3
+ MSB: %4 LSB: %5
+ Little Endian: %6 Signed: %7
+ )").arg(sig->name).arg(sig->start_bit).arg(sig->size).arg(sig->msb).arg(sig->lsb) + .arg(sig->is_little_endian ? "Y" : "N").arg(sig->is_signed ? "Y" : "N"); +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 4358190bc3..74724dfb33 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -136,3 +136,4 @@ private: }; int num_decimals(double num); +QString signalToolTip(const cabana::Signal *sig); From 9444df4c80f553c5eeac1ceb8154cfb42dcaf2b8 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Tue, 13 Jun 2023 01:18:35 +0300 Subject: [PATCH 232/283] Add several missing RAM_1500 firmwares (#28515) `ProjectZ3d#8762` 2023 RAM 1500 DongleID|route 4e0a5220533d9a86|2023-06-11--19-45-36 --- selfdrive/car/chrysler/values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index b1390bee0b..e86807bf55 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -224,6 +224,7 @@ FW_VERSIONS = { b'68453511AC', b'68453513AD', b'68453514AD', + b'68510280AG', b'68510283AG', b'68527346AE', b'68527375AD', @@ -236,6 +237,7 @@ FW_VERSIONS = { b'68490898AA', b'68500728AA', b'68615033AA', + b'68615034AA', ], (Ecu.abs, 0x747, None): [ b'68292406AH', @@ -281,11 +283,13 @@ FW_VERSIONS = { b'68552788AA', b'68552789AA', b'68552790AA', + b'68585109AB', b'68585112AB', ], (Ecu.engine, 0x7e0, None): [ b'05036065AE ', b'05036066AE ', + b'05149591AD ', b'05149846AA ', b'05149848AA ', b'68378701AI ', @@ -298,6 +302,7 @@ FW_VERSIONS = { b'68539650AD', ], (Ecu.transmission, 0x7e1, None): [ + b'05149536AC', b'68360078AL', b'68360080AM', b'68360081AM', From 9bb9657c9cf052ea6a78cb201b6eda41beb457cc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Jun 2023 16:33:33 -0700 Subject: [PATCH 233/283] thermald: must be in yellow band to go onroad (#28517) --- selfdrive/thermald/thermald.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index b10e87d404..1d0609a5ba 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -287,8 +287,11 @@ def thermald_thread(end_event, hw_queue): params.get_bool("Passive") startup_conditions["not_driver_view"] = not params.get_bool("IsDriverViewEnabled") startup_conditions["not_taking_snapshot"] = not params.get_bool("IsTakingSnapshot") - # if any CPU gets above 107 or the battery gets above 63, kill all processes - # controls will warn with CPU above 95 or battery above 60 + + # must be at an engageable thermal band to go onroad + startup_conditions["device_temp_engageable"] = thermal_status < ThermalStatus.red + + # if the temperature enters the danger zone, go offroad to cool down onroad_conditions["device_temp_good"] = thermal_status < ThermalStatus.danger set_offroad_alert_if_changed("Offroad_TemperatureTooHigh", (not onroad_conditions["device_temp_good"])) From 825c5a87df1bc4ac4630c550697e19f048d05317 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Jun 2023 08:05:43 +0800 Subject: [PATCH 234/283] laikad: move 'from_qcom_source' into try block (#28510) fix not cached except --- selfdrive/locationd/laikad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 71b81cc307..0115d2581a 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -192,9 +192,9 @@ class Laikad: def is_good_report(self, gnss_msg): if gnss_msg.which() == 'drMeasurementReport' and self.use_qcom: - constellation_id = ConstellationId.from_qcom_source(gnss_msg.drMeasurementReport.source) # TODO: Understand and use remaining unknown constellations try: + constellation_id = ConstellationId.from_qcom_source(gnss_msg.drMeasurementReport.source) good_constellation = constellation_id in [ConstellationId.GPS, ConstellationId.SBAS, ConstellationId.GLONASS] except NotImplementedError: good_constellation = False From 33a1959d264537257ec29729be3bfe76b8cef467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 12 Jun 2023 19:31:56 -0700 Subject: [PATCH 235/283] bump cereal (#28519) * bump cereal * bump cereak --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 44c93ef17c..f319a83ab7 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 44c93ef17cd0973347935b93c67b65ddd5ace22c +Subproject commit f319a83ab7a902477c786a25aa34077b6f640990 From 4eb3d541492f7695227f4d8a83127cbd0d32ff79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Tue, 13 Jun 2023 05:13:56 +0200 Subject: [PATCH 236/283] modeld: use any available stream as main, if there's only one (#28514) * Use whatever stream is available as main, if there's only one * Move logw somewhere else * Add wideRoadCameraState to ignore_alive if its not available --- selfdrive/controls/controlsd.py | 2 ++ selfdrive/modeld/modeld.cc | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 0cdb6cd96f..f2f9cef862 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -440,6 +440,8 @@ class Controls: available_streams = VisionIpcClient.available_streams("camerad", block=False) if VisionStreamType.VISION_STREAM_ROAD not in available_streams: self.sm.ignore_alive.append('roadCameraState') + if VisionStreamType.VISION_STREAM_WIDE_ROAD not in available_streams: + self.sm.ignore_alive.append('wideRoadCameraState') if not self.read_only: self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 9c8412d70d..265bd4071b 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -189,9 +189,11 @@ int main(int argc, char **argv) { LOGW("models loaded, modeld starting"); bool main_wide_camera = false; + bool use_extra_client = true; // set to false to use single camera while (!do_exit) { auto streams = VisionIpcClient::getAvailableStreams("camerad", false); if (!streams.empty()) { + use_extra_client = streams.count(VISION_STREAM_WIDE_ROAD) > 0 && streams.count(VISION_STREAM_ROAD) > 0; main_wide_camera = streams.count(VISION_STREAM_ROAD) == 0; break; } @@ -199,9 +201,9 @@ int main(int argc, char **argv) { util::sleep_for(100); } - bool use_extra_client = !main_wide_camera; // set for single camera mode VisionIpcClient vipc_client_main = VisionIpcClient("camerad", main_wide_camera ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD, true, device_id, context); VisionIpcClient vipc_client_extra = VisionIpcClient("camerad", VISION_STREAM_WIDE_ROAD, false, device_id, context); + LOGW("vision stream set up, main_wide_camera: %d, use_extra_client: %d", main_wide_camera, use_extra_client); while (!do_exit && !vipc_client_main.connect(false)) { util::sleep_for(100); From 58d32a70d7c6cd8285a0bc2ae03926b71a2d004e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Jun 2023 21:46:20 -0700 Subject: [PATCH 237/283] manager: watchdog restart UI with SIGKILL (#28523) --- selfdrive/manager/process.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/manager/process.py b/selfdrive/manager/process.py index ce18073d9b..f4d2b39841 100644 --- a/selfdrive/manager/process.py +++ b/selfdrive/manager/process.py @@ -91,7 +91,7 @@ class ManagerProcess(ABC): pass def restart(self) -> None: - self.stop() + self.stop(sig=signal.SIGKILL) self.start() def check_watchdog(self, started: bool) -> None: @@ -108,21 +108,21 @@ class ManagerProcess(ABC): dt = sec_since_boot() - self.last_watchdog_time / 1e9 if dt > self.watchdog_max_dt: - # Only restart while offroad for now if self.watchdog_seen and ENABLE_WATCHDOG: cloudlog.error(f"Watchdog timeout for {self.name} (exitcode {self.proc.exitcode}) restarting ({started=})") self.restart() else: self.watchdog_seen = True - def stop(self, retry: bool=True, block: bool=True) -> Optional[int]: + def stop(self, retry: bool = True, block: bool = True, sig: Optional[signal.Signals] = None) -> Optional[int]: if self.proc is None: return None if self.proc.exitcode is None: if not self.shutting_down: cloudlog.info(f"killing {self.name}") - sig = signal.SIGKILL if self.sigkill else signal.SIGINT + if sig is None: + sig = signal.SIGKILL if self.sigkill else signal.SIGINT self.signal(sig) self.shutting_down = True @@ -285,7 +285,7 @@ class DaemonProcess(ManagerProcess): params.put(self.param_name, str(proc.pid)) - def stop(self, retry=True, block=True) -> None: + def stop(self, retry=True, block=True, sig=None) -> None: pass From bce19bf187ed9c444bca834f64460f1648abe587 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 12 Jun 2023 23:03:04 -0700 Subject: [PATCH 238/283] Subaru: use latActive for steer request bit (#28453) * subaru: use latactive * Update ref_commit --- selfdrive/car/subaru/carcontroller.py | 6 +++--- selfdrive/car/subaru/subarucan.py | 8 ++++---- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index ae3305fbe4..c6ef0f11da 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -36,9 +36,9 @@ class CarController: apply_steer = 0 if self.CP.carFingerprint in PREGLOBAL_CARS: - can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer)) + can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, CC.latActive)) else: - can_sends.append(subarucan.create_steering_control(self.packer, apply_steer)) + can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, CC.latActive)) self.apply_steer_last = apply_steer @@ -76,7 +76,7 @@ class CarController: can_sends.append(subarucan.create_es_lkas_state(self.packer, CS.es_lkas_state_msg, CC.enabled, hud_control.visualAlert, hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart)) - + if self.CP.flags & SubaruFlags.SEND_INFOTAINMENT: can_sends.append(subarucan.create_infotainmentstatus(self.packer, CS.es_infotainmentstatus_msg, hud_control.visualAlert)) diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index bc9bf4c0a0..033ba7f76b 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -3,10 +3,10 @@ from cereal import car VisualAlert = car.CarControl.HUDControl.VisualAlert -def create_steering_control(packer, apply_steer): +def create_steering_control(packer, apply_steer, steer_req): values = { "LKAS_Output": apply_steer, - "LKAS_Request": 1 if apply_steer != 0 else 0, + "LKAS_Request": steer_req, "SET_1": 1 } return packer.make_can_msg("ES_LKAS", 0, values) @@ -174,10 +174,10 @@ def subaru_preglobal_checksum(packer, values, addr): return (sum(dat[:7])) % 256 -def create_preglobal_steering_control(packer, apply_steer): +def create_preglobal_steering_control(packer, apply_steer, steer_req): values = { "LKAS_Command": apply_steer, - "LKAS_Active": 1 if apply_steer != 0 else 0 + "LKAS_Active": steer_req, } values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_LKAS") diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index f3a9408671..a7d5b333d2 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -67bcd498f0432252a3f11a9fd2b59b344ee214ba +05b4467181f826f934a7ee4aada003fb241bbdff From 8c784ae558a3f06375fd7960aff887532d3d10cc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 00:14:49 -0700 Subject: [PATCH 239/283] Hyundai: remove old Elantra FW (#28526) * Update values.py * don't see this fw last 2 years * add version from 3ea622c3c0ec3055 * Update selfdrive/car/hyundai/values.py --- selfdrive/car/hyundai/values.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 7852f389f3..6e24fb585d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1534,10 +1534,8 @@ FW_VERSIONS = { b'\xf1\x8799110AA000\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', ], (Ecu.eps, 0x7d4, None): [ - b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00CN7 MDPS C 1.00 1.06 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4CNDC106', - b'\xf1\x8756310/AA070\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106', - b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106\xf1\xa01.06', b'\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106', + b'\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-AB000 200819', From 7fffb892e43057895a425b0b79a8c1da4e5da24e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 00:26:02 -0700 Subject: [PATCH 240/283] Hyundai: remove old Sonata FW (#28527) * Update values.py * can't find last 2 years --- selfdrive/car/hyundai/values.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 6e24fb585d..6513792f7c 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -628,11 +628,9 @@ FW_VERSIONS = { b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', # modified firmware b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC102', b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', # modified firmware - b'\xf1\x00DN8 MDPS C 1.00 1.01 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4DNAC101', b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101', b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101', b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100', - b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00DN8 MDPS C 1.00 1.01 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4DNAC101', b'\xf1\x8756310-L0010\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101', b'\xf1\x8756310-L0210\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC101', b'\xf1\x8756310-L1010\xf1\x00DN8 MDPS C 1.00 1.03 56310-L1010 4DNDC103', From e54d05b42f9f3e161f168dcc352a6e95cc60ad28 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 02:01:40 -0700 Subject: [PATCH 241/283] HKG: FW part number test (#28525) * start on test * better regex * lookbehind * comments to choose from * i did not know that! * common patterns in values.py * messy messy * need to remove these * rmrmrm * clean up test * fixups * not used yet * none should be good enough * Update selfdrive/car/hyundai/values.py --- selfdrive/car/hyundai/tests/test_hyundai.py | 18 +++++++++++++++++- selfdrive/car/hyundai/values.py | 9 ++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index f2e27788a6..8bac256935 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -3,7 +3,7 @@ import unittest from cereal import car from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, FW_QUERY_CONFIG, \ - FW_VERSIONS, LEGACY_SAFETY_MODE_CAR + FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, PART_NUMBER_FW_PATTERN Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} @@ -39,6 +39,22 @@ class TestHyundaiFingerprint(unittest.TestCase): continue self.assertIn(fuzzy_ecu, [e[0] for e in ecus]) + def test_fw_part_number(self): + # Hyundai places the ECU part number in their FW versions, assert all parsable + # Some examples of valid formats: '56310-L0010', '56310L0010', '56310/M6300' + for car_model, ecus in FW_VERSIONS.items(): + with self.subTest(car_model=car_model): + if car_model == CAR.HYUNDAI_GENESIS: + raise unittest.SkipTest("No part numbers for car model") + + for ecu, fws in ecus.items(): + if ecu[0] not in FW_QUERY_CONFIG.platform_code_ecus: + continue + + for fw in fws: + match = PART_NUMBER_FW_PATTERN.search(fw) + self.assertIsNotNone(match, fw) + def test_fuzzy_fw_dates(self): # Some newer platforms have date codes in a different format we don't yet parse, # for now assert date format is consistent for all FW across each platform diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 6513792f7c..2a15925ebb 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -351,7 +351,7 @@ FINGERPRINTS = { def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]: codes: DefaultDict[bytes, Set[bytes]] = defaultdict(set) for fw in fw_versions: - match = PLATFORM_CODE_PATTERN.search(fw) + match = PLATFORM_CODE_FW_PATTERN.search(fw) if match is not None: code, date = match.groups() codes[code].add(date) @@ -390,8 +390,10 @@ HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER] HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) -PLATFORM_CODE_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] + - b')[A-Z]{2}[A-Za-z0-9]{0,2})(?:.*([0-9]{6}))?') +# Regex patterns for parsing platform code, FW date, and part number from FW versions +PLATFORM_CODE_FW_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] + + b')[A-Z]{2}[A-Za-z0-9]{0,2})(?:.*([0-9]{6}))?') +PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z][A-Z0-9]{3}[0-9])') FW_QUERY_CONFIG = FwQueryConfig( requests=[ @@ -451,6 +453,7 @@ FW_QUERY_CONFIG = FwQueryConfig( ], fuzzy_get_platform_codes=get_platform_codes, # Camera and radar should exist on all cars + # TODO: use abs, it has the platform code and part number on many platforms platform_code_ecus=[Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps], ) From 7128daebba7032d3a63f50b7875643e9905f52ae Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 14 Jun 2023 01:49:59 +0800 Subject: [PATCH 242/283] cabana: fix core dump when failed to connect to panda (#28529) --- tools/cabana/cabana.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 5dce53ba7d..d2c451be89 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -42,7 +42,12 @@ int main(int argc, char *argv[]) { if (cmd_parser.isSet("panda-serial")) { config.serial = cmd_parser.value("panda-serial"); } - stream = new PandaStream(&app, config); + try { + stream = new PandaStream(&app, config); + } catch (std::exception &e) { + qWarning() << e.what(); + return 0; + } } else { uint32_t replay_flags = REPLAY_FLAG_NONE; if (cmd_parser.isSet("ecam")) { From e08569b0f31953e185369eba9afb7fb20de714fa Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 14 Jun 2023 04:22:03 +0800 Subject: [PATCH 243/283] cabana: support multiplexed signals (#28309) * support muxed signals * write multiplexor in generateDBC * edit multiplex_switch_value in signalView * no overlapping warning for mux signals * group signals by multiplexer indicator * display freq for each multiplexed signals * remove all multiplexed signals after switch deleted * disable switch value * cleanup * historyView: use getValue * sort by switch value * check address * rename variables * rename signale type * parse multiplexed signals in dbcmanater * cache signal color in member variable * cleanup num_decimals * remove sources from dbcmanager and cleanup code * fix sort * check mltiplex in operator== * fix sizehint * convert multipledxed to normal after changing multiplxor to normal * throw error on multiple 'M' signals * add comment * parse multipled signals in test case * cleanup * change order * cleanup open * display multiplexed/overlapping signals in binaryview * sort overlapped signals by size * refactor dbcmanager * trimmed * parse multiplexed signals in test case * cleanup * merge master * space * use pointer for sigs * alldbcFiles * cleanup * cleanup sparkline * use std::vector * skip draw sparkline if isnull * bigger capacity --- tools/cabana/binaryview.cc | 9 ++- tools/cabana/chart/chart.cc | 16 ++-- tools/cabana/chart/sparkline.cc | 21 ++++-- tools/cabana/chart/sparkline.h | 3 + tools/cabana/commands.cc | 37 +++++++-- tools/cabana/commands.h | 5 +- tools/cabana/dbc/dbc.cc | 44 ++++++++--- tools/cabana/dbc/dbc.h | 20 ++++- tools/cabana/dbc/dbcfile.cc | 100 +++++++++++++++---------- tools/cabana/dbc/dbcfile.h | 4 +- tools/cabana/dbc/dbcmanager.h | 2 +- tools/cabana/detailwidget.cc | 3 +- tools/cabana/historylog.cc | 2 +- tools/cabana/mainwin.cc | 2 +- tools/cabana/messageswidget.cc | 5 +- tools/cabana/signalview.cc | 96 ++++++++++++++++++++---- tools/cabana/signalview.h | 8 +- tools/cabana/streams/abstractstream.cc | 2 +- tools/cabana/streams/abstractstream.h | 8 +- tools/cabana/streams/replaystream.cc | 11 +-- tools/cabana/streams/replaystream.h | 2 +- tools/cabana/tests/test_cabana.cc | 20 ++++- tools/cabana/tools/findsimilarbits.cc | 2 +- 23 files changed, 298 insertions(+), 124 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index ed93a07e40..cc5259136a 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -219,9 +219,12 @@ void BinaryView::refresh() { QSet BinaryView::getOverlappingSignals() const { QSet overlapping; - for (auto &item : model->items) { - if (item.sigs.size() > 1) - for (auto s : item.sigs) overlapping += s; + for (const auto &item : model->items) { + if (item.sigs.size() > 1) { + for (auto s : item.sigs) { + if (s->type == cabana::Signal::Type::Normal) overlapping += s; + } + } } return overlapping; } diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 622b79d806..da38054cb0 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -289,14 +289,16 @@ void ChartView::updateSeries(const cabana::Signal *sig, bool clear) { const double route_start_time = can->routeStartTime(); for (auto end = msgs.cend(); first != end; ++first) { const CanEvent *e = *first; - double value = get_raw_value(e->dat, e->size, *s.sig); - double ts = e->mono_time / 1e9 - route_start_time; // seconds - s.vals.append({ts, value}); - if (!s.step_vals.empty()) { - s.step_vals.append({ts, s.step_vals.back().y()}); + double value = 0; + if (s.sig->getValue(e->dat, e->size, &value)) { + double ts = e->mono_time / 1e9 - route_start_time; // seconds + s.vals.append({ts, value}); + if (!s.step_vals.empty()) { + s.step_vals.append({ts, s.step_vals.back().y()}); + } + s.step_vals.append({ts, value}); + s.last_value_mono_time = e->mono_time; } - s.step_vals.append({ts, value}); - s.last_value_mono_time = e->mono_time; } if (!can->liveStreaming()) { s.segment_tree.build(s.vals); diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index bac867bd20..baedee8bb2 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -22,21 +22,30 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, doubl if (first != last) { if (update_values) { values.clear(); - values.reserve(std::distance(first, last)); + if (values.capacity() < std::distance(first, last)) { + values.reserve(std::distance(first, last) * 2); + } min_val = std::numeric_limits::max(); max_val = std::numeric_limits::lowest(); for (auto it = first; it != last; ++it) { const CanEvent *e = *it; - double value = get_raw_value(e->dat, e->size, *sig); - values.emplace_back((e->mono_time - (*first)->mono_time) / 1e9, value); - if (min_val > value) min_val = value; - if (max_val < value) max_val = value; + double value = 0; + if (sig->getValue(e->dat, e->size, &value)) { + values.emplace_back((e->mono_time - (*first)->mono_time) / 1e9, value); + if (min_val > value) min_val = value; + if (max_val < value) max_val = value; + } } if (min_val == max_val) { min_val -= 1; max_val += 1; } } + } else { + values.clear(); + } + + if (!values.empty()) { render(sig->color, size); } else { pixmap = QPixmap(); @@ -49,7 +58,7 @@ void Sparkline::render(const QColor &color, QSize size) { const double xscale = (size.width() - 1) / (double)time_range; const double yscale = (size.height() - 3) / (max_val - min_val); points.clear(); - points.reserve(values.size()); + points.reserve(values.capacity()); for (auto &v : values) { points.emplace_back(v.x() * xscale, 1 + std::abs(v.y() - max_val) * yscale); } diff --git a/tools/cabana/chart/sparkline.h b/tools/cabana/chart/sparkline.h index 69d4f4bc55..2061966ebb 100644 --- a/tools/cabana/chart/sparkline.h +++ b/tools/cabana/chart/sparkline.h @@ -10,6 +10,9 @@ class Sparkline { public: void update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size); const QSize size() const { return pixmap.size() / pixmap.devicePixelRatio(); } + inline double freq() const { + return values.empty() ? 0 : values.size() / std::max(values.back().x() - values.front().x(), 1.0); + } QPixmap pixmap; double min_val = 0; diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index d64e173338..1ddec0ea93 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -62,22 +62,43 @@ void AddSigCommand::redo() { dbc()->addSignal(id, signal); } // RemoveSigCommand RemoveSigCommand::RemoveSigCommand(const MessageId &id, const cabana::Signal *sig, QUndoCommand *parent) - : id(id), signal(*sig), QUndoCommand(parent) { - setText(QObject::tr("remove signal %1 from %2:%3").arg(signal.name).arg(msgName(id)).arg(id.address)); + : id(id), QUndoCommand(parent) { + sigs.push_back(*sig); + if (sig->type == cabana::Signal::Type::Multiplexor) { + for (const auto &s : dbc()->msg(id)->sigs) { + if (s->type == cabana::Signal::Type::Multiplexed) { + sigs.push_back(*s); + } + } + } + setText(QObject::tr("remove signal %1 from %2:%3").arg(sig->name).arg(msgName(id)).arg(id.address)); } -void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } -void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name); } +void RemoveSigCommand::undo() { for (const auto &s : sigs) dbc()->addSignal(id, s); } +void RemoveSigCommand::redo() { for (const auto &s : sigs) dbc()->removeSignal(id, s.name); } // EditSignalCommand EditSignalCommand::EditSignalCommand(const MessageId &id, const cabana::Signal *sig, const cabana::Signal &new_sig, QUndoCommand *parent) - : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { - setText(QObject::tr("edit signal %1 in %2:%3").arg(old_signal.name).arg(msgName(id)).arg(id.address)); + : id(id), QUndoCommand(parent) { + sigs.push_back({*sig, new_sig}); + if (sig->type == cabana::Signal::Type::Multiplexor && new_sig.type == cabana::Signal::Type::Normal) { + // convert all multiplexed signals to normal signals + auto msg = dbc()->msg(id); + assert(msg); + for (const auto &s : msg->sigs) { + if (s->type == cabana::Signal::Type::Multiplexed) { + auto new_s = *s; + new_s.type = cabana::Signal::Type::Normal; + sigs.push_back({*s, new_s}); + } + } + } + setText(QObject::tr("edit signal %1 in %2:%3").arg(sig->name).arg(msgName(id)).arg(id.address)); } -void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name, old_signal); } -void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name, new_signal); } +void EditSignalCommand::undo() { for (const auto &s : sigs) dbc()->updateSignal(id, s.second.name, s.first); } +void EditSignalCommand::redo() { for (const auto &s : sigs) dbc()->updateSignal(id, s.first.name, s.second); } namespace UndoStack { diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 2552115229..4e2e2eac4b 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -48,7 +48,7 @@ public: private: const MessageId id; - cabana::Signal signal = {}; + QList sigs; }; class EditSignalCommand : public QUndoCommand { @@ -59,8 +59,7 @@ public: private: const MessageId id; - cabana::Signal old_signal = {}; - cabana::Signal new_signal = {}; + QList> sigs; // QList<{old_sig, new_sig}> }; namespace UndoStack { diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index 1ac99ad464..269aeb4247 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -77,12 +77,18 @@ QString cabana::Msg::newSignalName() { void cabana::Msg::update() { mask = QVector(size, 0x00).toList(); + multiplexor = nullptr; + // sort signals std::sort(sigs.begin(), sigs.end(), [](auto l, auto r) { - return std::tie(l->start_bit, l->name) < std::tie(r->start_bit, r->name); + return std::tie(r->type, l->multiplex_value, l->start_bit, l->name) < + std::tie(l->type, r->multiplex_value, r->start_bit, r->name); }); - for (auto &sig : sigs) { + for (auto sig : sigs) { + if (sig->type == cabana::Signal::Type::Multiplexor) { + multiplexor = sig; + } sig->update(); // update mask @@ -101,6 +107,13 @@ void cabana::Msg::update() { i = sig->is_little_endian ? i - 1 : i + 1; } } + + for (auto sig : sigs) { + sig->multiplexor = sig->type == cabana::Signal::Type::Multiplexed ? multiplexor : nullptr; + if (!sig->multiplexor) { + sig->multiplex_value = 0; + } + } } // cabana::Signal @@ -131,6 +144,24 @@ QString cabana::Signal::formatValue(double value) const { return val_str; } +bool cabana::Signal::getValue(const uint8_t *data, size_t data_size, double *val) const { + if (multiplexor && get_raw_value(data, data_size, *multiplexor) != multiplex_value) { + return false; + } + *val = get_raw_value(data, data_size, *this); + return true; +} + +bool cabana::Signal::operator==(const cabana::Signal &other) const { + return name == other.name && size == other.size && + start_bit == other.start_bit && + msb == other.msb && lsb == other.lsb && + is_signed == other.is_signed && is_little_endian == other.is_little_endian && + factor == other.factor && offset == other.offset && + min == other.min && max == other.max && comment == other.comment && unit == other.unit && val_desc == other.val_desc && + multiplex_value == other.multiplex_value && type == other.type; +} + // helper functions static QVector BIG_ENDIAN_START_BITS = []() { @@ -163,15 +194,6 @@ double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal return val * sig.factor + sig.offset; } -bool cabana::operator==(const cabana::Signal &l, const cabana::Signal &r) { - return l.name == r.name && l.size == r.size && - l.start_bit == r.start_bit && - l.msb == r.msb && l.lsb == r.lsb && - l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian && - l.factor == r.factor && l.offset == r.offset && - l.min == r.min && l.max == r.max && l.comment == r.comment && l.unit == r.unit && l.val_desc == r.val_desc; -} - int bigEndianStartBitsIndex(int start_bit) { return BIG_ENDIAN_START_BITS[start_bit]; } int bigEndianBitIndex(int index) { return BIG_ENDIAN_START_BITS.indexOf(index); } diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index 56a3ea9a65..d7439620a7 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -52,8 +52,18 @@ public: Signal() = default; Signal(const Signal &other) = default; void update(); + bool getValue(const uint8_t *data, size_t data_size, double *val) const; QString formatValue(double value) const; + bool operator==(const cabana::Signal &other) const; + inline bool operator!=(const cabana::Signal &other) const { return !(*this == other); } + enum class Type { + Normal = 0, + Multiplexed, + Multiplexor + }; + + Type type = Type::Normal; QString name; int start_bit, msb, lsb, size; double factor, offset; @@ -65,6 +75,10 @@ public: ValueDescription val_desc; int precision = 0; QColor color; + + // Multiplexed + int multiplex_value = 0; + Signal *multiplexor = nullptr; }; class Msg { @@ -79,6 +93,7 @@ public: int indexOf(const cabana::Signal *sig) const; cabana::Signal *sig(const QString &sig_name) const; QString newSignalName(); + void update(); inline const std::vector &getSignals() const { return sigs; } uint32_t address; @@ -88,12 +103,9 @@ public: std::vector sigs; QList mask; - void update(); + cabana::Signal *multiplexor = nullptr; }; -bool operator==(const cabana::Signal &l, const cabana::Signal &r); -inline bool operator!=(const cabana::Signal &l, const cabana::Signal &r) { return !(l == r); } - } // namespace cabana // Helper functions diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index 6de00fe77d..c7df7553ef 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -16,7 +16,7 @@ DBCFile::DBCFile(const QString &dbc_file_name, QObject *parent) : QObject(parent if (dbc_file_name.endsWith(AUTO_SAVE_EXTENSION)) { filename.chop(AUTO_SAVE_EXTENSION.length()); } - open(file.readAll()); + parse(file.readAll()); } else { throw std::runtime_error("Failed to open file."); } @@ -24,35 +24,7 @@ DBCFile::DBCFile(const QString &dbc_file_name, QObject *parent) : QObject(parent DBCFile::DBCFile(const QString &name, const QString &content, QObject *parent) : QObject(parent), name_(name), filename("") { // Open from clipboard - open(content); -} - -void DBCFile::open(const QString &content) { - std::istringstream stream(content.toStdString()); - auto dbc = const_cast(dbc_parse_from_stream(name_.toStdString(), stream)); - msgs.clear(); - for (auto &msg : dbc->msgs) { - auto &m = msgs[msg.address]; - m.address = msg.address; - m.name = msg.name.c_str(); - m.size = msg.size; - for (auto &s : msg.sigs) { - auto sig = m.sigs.emplace_back(new cabana::Signal); - sig->name = s.name.c_str(); - sig->start_bit = s.start_bit; - sig->msb = s.msb; - sig->lsb = s.lsb; - sig->size = s.size; - sig->is_signed = s.is_signed; - sig->factor = s.factor; - sig->offset = s.offset; - sig->is_little_endian = s.is_little_endian; - } - m.update(); - } - parseExtraInfo(content); - - delete dbc; + parse(content); } bool DBCFile::save() { @@ -110,7 +82,7 @@ int DBCFile::signalCount() { return std::accumulate(msgs.cbegin(), msgs.cend(), 0, [](int &n, const auto &m) { return n + m.second.sigs.size(); }); } -void DBCFile::parseExtraInfo(const QString &content) { +void DBCFile::parse(const QString &content) { static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); @@ -120,23 +92,31 @@ void DBCFile::parseExtraInfo(const QString &content) { int line_num = 0; QString line; - auto dbc_assert = [&line_num, &line, this](bool condition) { - if (!condition) throw std::runtime_error(QString("[%1:%2]: %3").arg(filename).arg(line_num).arg(line).toStdString()); + auto dbc_assert = [&line_num, &line, this](bool condition, const QString &msg = "") { + if (!condition) throw std::runtime_error(QString("[%1:%2]%3: %4").arg(filename).arg(line_num).arg(msg).arg(line).toStdString()); }; auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * { auto m = (cabana::Msg *)msg(address); return m ? (cabana::Signal *)m->sig(name) : nullptr; }; + msgs.clear(); QTextStream stream((QString *)&content); - uint32_t address = 0; + cabana::Msg *current_msg = nullptr; + int multiplexor_cnt = 0; while (!stream.atEnd()) { ++line_num; line = stream.readLine().trimmed(); if (line.startsWith("BO_ ")) { + multiplexor_cnt = 0; auto match = bo_regexp.match(line); dbc_assert(match.hasMatch()); - address = match.captured(1).toUInt(); + auto address = match.captured(1).toUInt(); + dbc_assert(msgs.count(address) == 0, QString("Duplicate message address: %1").arg(address)); + current_msg = &msgs[address]; + current_msg->address = address; + current_msg->name = match.captured(2); + current_msg->size = match.captured(3).toULong(); } else if (line.startsWith("SG_ ")) { int offset = 0; auto match = sg_regexp.match(line); @@ -145,11 +125,40 @@ void DBCFile::parseExtraInfo(const QString &content) { offset = 1; } dbc_assert(match.hasMatch()); - if (auto s = get_sig(address, match.captured(1))) { - s->min = match.captured(8 + offset).toDouble(); - s->max = match.captured(9 + offset).toDouble(); - s->unit = match.captured(10 + offset); + dbc_assert(current_msg, "No Message"); + auto name = match.captured(1); + dbc_assert(current_msg->sig(name) == nullptr, "Duplicate signal name"); + cabana::Signal s{}; + if (offset == 1) { + auto indicator = match.captured(2); + if (indicator == "M") { + // Only one signal within a single message can be the multiplexer switch. + dbc_assert(++multiplexor_cnt < 2, "Multiple multiplexor"); + s.type = cabana::Signal::Type::Multiplexor; + } else { + dbc_assert(multiplexor_cnt == 1, "No multiplexor"); + s.type = cabana::Signal::Type::Multiplexed; + s.multiplex_value = indicator.mid(1).toInt(); + } } + s.name = name; + s.start_bit = match.captured(offset + 2).toInt(); + s.size = match.captured(offset + 3).toInt(); + s.is_little_endian = match.captured(offset + 4).toInt() == 1; + s.is_signed = match.captured(offset + 5) == "-"; + s.factor = match.captured(offset + 6).toDouble(); + s.offset = match.captured(offset + 7).toDouble(); + if (s.is_little_endian) { + s.lsb = s.start_bit; + s.msb = s.start_bit + s.size - 1; + } else { + s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); + s.msb = s.start_bit; + } + s.min = match.captured(8 + offset).toDouble(); + s.max = match.captured(9 + offset).toDouble(); + s.unit = match.captured(10 + offset); + current_msg->sigs.push_back(new cabana::Signal(s)); } else if (line.startsWith("VAL_ ")) { auto match = val_regexp.match(line); dbc_assert(match.hasMatch()); @@ -185,6 +194,10 @@ void DBCFile::parseExtraInfo(const QString &content) { } } } + + for (auto &[_, m] : msgs) { + m.update(); + } } QString DBCFile::generateDBC() { @@ -195,8 +208,15 @@ QString DBCFile::generateDBC() { message_comment += QString("CM_ BO_ %1 \"%2\";\n").arg(address).arg(m.comment); } for (auto sig : m.getSignals()) { - dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") + QString multiplexer_indicator; + if (sig->type == cabana::Signal::Type::Multiplexor) { + multiplexer_indicator = "M "; + } else if (sig->type == cabana::Signal::Type::Multiplexed) { + multiplexer_indicator = QString("m%1 ").arg(sig->multiplex_value); + } + dbc_string += QString(" SG_ %1 %2: %3|%4@%5%6 (%7,%8) [%9|%10] \"%11\" XXX\n") .arg(sig->name) + .arg(multiplexer_indicator) .arg(sig->start_bit) .arg(sig->size) .arg(sig->is_little_endian ? '1' : '0') diff --git a/tools/cabana/dbc/dbcfile.h b/tools/cabana/dbc/dbcfile.h index 76e71e189e..78a73d58e4 100644 --- a/tools/cabana/dbc/dbcfile.h +++ b/tools/cabana/dbc/dbcfile.h @@ -15,8 +15,6 @@ public: DBCFile(const QString &name, const QString &content, QObject *parent=nullptr); ~DBCFile() {} - void open(const QString &content); - bool save(); bool saveAs(const QString &new_filename); bool autoSave(); @@ -40,7 +38,7 @@ public: QString filename; private: - void parseExtraInfo(const QString &content); + void parse(const QString &content); std::map msgs; QString name_; }; diff --git a/tools/cabana/dbc/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h index 9af4e0c1cc..659253b82a 100644 --- a/tools/cabana/dbc/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -15,7 +15,7 @@ class DBCManager : public QObject { Q_OBJECT public: - DBCManager(QObject *parent) {} + DBCManager(QObject *parent) : QObject(parent) {} ~DBCManager() {} bool open(const SourceSet &sources, const QString &dbc_file_name, QString *error = nullptr); bool open(const SourceSet &sources, const QString &name, const QString &content, QString *error = nullptr); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 92851761f9..47c5e4a62e 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -167,7 +167,8 @@ void DetailWidget::editMsg() { int size = msg ? msg->size : can->lastMessage(msg_id).dat.size(); EditMessageDialog dlg(msg_id, msgName(msg_id), size, this); if (dlg.exec()) { - UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text().trimmed(), dlg.size_spin->value(), dlg.comment_edit->toPlainText().trimmed())); + UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text().trimmed(), + dlg.size_spin->value(), dlg.comment_edit->toPlainText().trimmed())); } } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index eb8bada69e..f61a89b73c 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -125,7 +125,7 @@ std::deque HistoryLogModel::fetchData(InputIt first, I for (; first != last && (*first)->mono_time > min_time; ++first) { const CanEvent *e = *first; for (int i = 0; i < sigs.size(); ++i) { - values[i] = get_raw_value(e->dat, e->size, *sigs[i]); + sigs[i]->getValue(e->dat, e->size, &values[i]); } if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { auto &m = msgs.emplace_back(); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index f424a3eecf..2961d888ff 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -482,7 +482,7 @@ void MainWindow::updateLoadSaveMenus() { manage_dbcs_menu->clear(); manage_dbcs_menu->setEnabled(dynamic_cast(can) == nullptr); - for (uint8_t source : can->sources) { + for (int source : can->sources) { if (source >= 64) continue; // Sent and blocked buses are handled implicitly SourceSet ss = {source, uint8_t(source + 128), uint8_t(source + 192)}; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 2e2087dece..5982689bda 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -32,6 +32,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { auto delegate = new MessageBytesDelegate(view, settings.multiple_lines_bytes); view->setItemDelegate(delegate); + view->setHeader(header); view->setModel(model); view->setHeader(header); view->setSortingEnabled(true); @@ -130,7 +131,7 @@ void MessagesWidget::dbcModified() { void MessagesWidget::selectMessage(const MessageId &msg_id) { auto it = std::find(model->msgs.cbegin(), model->msgs.cend(), msg_id); if (it != model->msgs.cend()) { - view->selectionModel()->setCurrentIndex(model->index(std::distance(model->msgs.cbegin(), it), 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); + view->setCurrentIndex(model->index(std::distance(model->msgs.cbegin(), it), 0)); } } @@ -209,7 +210,7 @@ void MessageListModel::setFilterStrings(const QMap &filters) { void MessageListModel::dbcModified() { dbc_address.clear(); - for (const auto &[_, m] : dbc()->getMessages(0)) { + for (const auto &[_, m] : dbc()->getMessages(-1)) { dbc_address.insert(m.address); } fetchData(); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 71186bbdf1..a557aa57fb 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -18,6 +18,12 @@ // SignalModel +static QString signalTypeToString(cabana::Signal::Type type) { + if (type == cabana::Signal::Type::Multiplexor) return "Multiplexor Signal"; + else if (type == cabana::Signal::Type::Multiplexed) return "Multiplexed Signal"; + else return "Normal Signal"; +} + SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(parent) { QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &SignalModel::refresh); QObject::connect(dbc(), &DBCManager::msgUpdated, this, &SignalModel::handleMsgChanged); @@ -30,7 +36,8 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const cabana::Signal *sig) { Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name, .type = Item::Sig}; parent_item->children.insert(pos, item); - QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"}; + QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Type", "Multiplex Value", "Extra Info", + "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"}; for (int i = 0; i < std::size(titles); ++i) { item->children.push_back(new Item{.sig = sig, .parent = item, .title = titles[i], .type = (Item::Type)(i + Item::Name)}); } @@ -87,6 +94,9 @@ Qt::ItemFlags SignalModel::flags(const QModelIndex &index) const { if (index.column() == 1 && item->type != Item::Sig && item->type != Item::ExtraInfo) { flags |= (item->type == Item::Endian || item->type == Item::Signed) ? Qt::ItemIsUserCheckable : Qt::ItemIsEditable; } + if (item->type == Item::MultiplexValue && item->sig->type != cabana::Signal::Type::Multiplexed) { + flags &= ~Qt::ItemIsEnabled; + } return flags; } @@ -124,6 +134,8 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { case Item::Sig: return item->sig_val; case Item::Name: return item->sig->name; case Item::Size: return item->sig->size; + case Item::SignalType: return signalTypeToString(item->sig->type); + case Item::MultiplexValue: return item->sig->multiplex_value; case Item::Offset: return doubleToString(item->sig->offset); case Item::Factor: return doubleToString(item->sig->factor); case Item::Unit: return item->sig->unit; @@ -160,6 +172,8 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r switch (item->type) { case Item::Name: s.name = value.toString(); break; case Item::Size: s.size = value.toInt(); break; + case Item::SignalType: s.type = (cabana::Signal::Type)value.toInt(); break; + case Item::MultiplexValue: s.multiplex_value = value.toInt(); break; case Item::Endian: s.is_little_endian = value.toBool(); break; case Item::Signed: s.is_signed = value.toBool(); break; case Item::Offset: s.offset = value.toDouble(); break; @@ -265,6 +279,14 @@ void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) { void SignalModel::handleSignalUpdated(const cabana::Signal *sig) { if (int row = signalRow(sig); row != -1) { emit dataChanged(index(row, 0), index(row, 1), {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole}); + + // move row when the order changes. + int to = dbc()->msg(msg_id)->indexOf(sig); + if (to != row) { + beginMoveRows({}, row, row, {}, to > row ? to + 1 : to); + root->children.move(row, to); + endMoveRows(); + } } } @@ -289,13 +311,18 @@ SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(pa QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { int width = option.widget->size().width() / 2; if (index.column() == 0) { - auto text = index.data(Qt::DisplayRole).toString(); + int spacing = option.widget->style()->pixelMetric(QStyle::PM_TreeViewIndentation) + color_label_width + 8; + auto text = index.data(Qt::DisplayRole).toString();; + auto item = (SignalModel::Item *)index.internalPointer(); + if (item->type == SignalModel::Item::Sig && item->sig->type != cabana::Signal::Type::Normal) { + text += item->sig->type == cabana::Signal::Type::Multiplexor ? QString(" M ") : QString(" m%1 ").arg(item->sig->multiplex_value); + spacing += (option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2; + } auto it = width_cache.find(text); if (it == width_cache.end()) { - int spacing = option.widget->style()->pixelMetric(QStyle::PM_TreeViewIndentation) + color_label_width + 8; - it = width_cache.insert(text, option.fontMetrics.width(text) + spacing); + it = width_cache.insert(text, option.fontMetrics.width(text)); } - width = std::min(option.widget->size().width() / 3.0, it.value()); + width = std::min(option.widget->size().width() / 3.0, it.value() + spacing); } return {width, QApplication::fontMetrics().height()}; } @@ -334,11 +361,24 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->drawText(icon_rect, Qt::AlignCenter, QString::number(item->row() + 1)); r.setLeft(icon_rect.right() + h_margin * 2); + // multiplexer indicator + if (item->sig->type != cabana::Signal::Type::Normal) { + QString indicator = item->sig->type == cabana::Signal::Type::Multiplexor ? QString(" M ") : QString(" m%1 ").arg(item->sig->multiplex_value); + QRect indicator_rect{r.x(), r.y(), option.fontMetrics.width(indicator), r.height()}; + painter->setBrush(Qt::gray); + painter->setPen(Qt::NoPen); + painter->drawRoundedRect(indicator_rect, 3, 3); + painter->setPen(Qt::white); + painter->drawText(indicator_rect, Qt::AlignCenter, indicator); + r.setLeft(indicator_rect.right() + h_margin * 2); + } + + // name auto text = option.fontMetrics.elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, r.width()); painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); painter->setFont(option.font); painter->drawText(r, option.displayAlignment, text); - } else if (index.column() == 1) { + } else if (index.column() == 1 && !item->sparkline.pixmap.isNull()) { // sparkline QSize sparkline_size = item->sparkline.pixmap.size() / item->sparkline.pixmap.devicePixelRatio(); painter->drawPixmap(QRect(r.topLeft(), sparkline_size), item->sparkline.pixmap); @@ -356,8 +396,15 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->drawText(rect, Qt::AlignLeft | Qt::AlignBottom, min); QFontMetrics fm(minmax_font); value_adjust = std::max(fm.width(min), fm.width(max)) + 5; + } else if (item->sig->type == cabana::Signal::Type::Multiplexed) { + // display freq of multiplexed signal + painter->setFont(label_font); + QString freq = QString("%1 hz").arg(item->sparkline.freq(), 0, 'g', 2); + painter->drawText(rect.adjusted(5, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, freq); + QFontMetrics fm(label_font); + value_adjust = fm.width(freq) + 10; } - // value + // signal value painter->setFont(option.font); rect.adjust(value_adjust, 0, -button_size.width(), 0); auto text = option.fontMetrics.elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rect.width()); @@ -371,10 +418,11 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (SignalModel::Item *)index.internalPointer(); if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Offset || - item->type == SignalModel::Item::Factor || item->type == SignalModel::Item::Min || item->type == SignalModel::Item::Max) { + item->type == SignalModel::Item::Factor || item->type == SignalModel::Item::MultiplexValue || + item->type == SignalModel::Item::Min || item->type == SignalModel::Item::Max) { QLineEdit *e = new QLineEdit(parent); e->setFrame(false); - e->setValidator(index.row() == 0 ? name_validator : double_validator); + e->setValidator(item->type == SignalModel::Item::Name ? name_validator : double_validator); if (item->type == SignalModel::Item::Name) { QCompleter *completer = new QCompleter(dbc()->signalNames()); @@ -389,6 +437,15 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie spin->setFrame(false); spin->setRange(1, 64); return spin; + } else if (item->type == SignalModel::Item::SignalType) { + QComboBox *c = new QComboBox(parent); + c->addItem(signalTypeToString(cabana::Signal::Type::Normal), (int)cabana::Signal::Type::Normal); + if (!dbc()->msg(((SignalModel *)index.model())->msg_id)->multiplexor) { + c->addItem(signalTypeToString(cabana::Signal::Type::Multiplexor), (int)cabana::Signal::Type::Multiplexor); + } else if (item->sig->type != cabana::Signal::Type::Multiplexor) { + c->addItem(signalTypeToString(cabana::Signal::Type::Multiplexed), (int)cabana::Signal::Type::Multiplexed); + } + return c; } else if (item->type == SignalModel::Item::Desc) { ValueDescriptionDlg dlg(item->sig->val_desc, parent); dlg.setWindowTitle(item->sig->name); @@ -400,6 +457,15 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie return QStyledItemDelegate::createEditor(parent, option, index); } +void SignalItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { + auto item = (SignalModel::Item *)index.internalPointer(); + if (item->type == SignalModel::Item::SignalType) { + model->setData(index, ((QComboBox*)editor)->currentData().toInt()); + return; + } + QStyledItemDelegate::setModelData(editor, model, index); +} + // SignalView SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QFrame(parent) { @@ -438,6 +504,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), tree->setHeaderHidden(true); tree->setMouseTracking(true); tree->setExpandsOnDoubleClick(false); + tree->setEditTriggers(QAbstractItemView::AllEditTriggers); tree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); tree->header()->setStretchLastSection(true); tree->setMinimumHeight(300); @@ -579,8 +646,10 @@ void SignalView::updateState(const QHash *msgs) { if (model->rowCount() == 0 || (msgs && !msgs->contains(model->msg_id)) || last_msg.dat.size() == 0) return; for (auto item : model->root->children) { - double value = get_raw_value((uint8_t *)last_msg.dat.constData(), last_msg.dat.size(), *item->sig); - item->sig_val = item->sig->formatValue(value); + double value = 0; + if (item->sig->getValue((uint8_t *)last_msg.dat.constData(), last_msg.dat.size(), &value)) { + item->sig_val = item->sig->formatValue(value); + } max_value_width = std::max(max_value_width, fontMetrics().width(item->sig_val)); } @@ -620,11 +689,6 @@ void SignalView::resizeEvent(QResizeEvent* event) { QFrame::resizeEvent(event); } -void SignalView::leaveEvent(QEvent *event) { - emit highlight(nullptr); - QWidget::leaveEvent(event); -} - // ValueDescriptionDlg ValueDescriptionDlg::ValueDescriptionDlg(const ValueDescription &descriptions, QWidget *parent) : QDialog(parent) { diff --git a/tools/cabana/signalview.h b/tools/cabana/signalview.h index f5924c1f5d..eb268e517c 100644 --- a/tools/cabana/signalview.h +++ b/tools/cabana/signalview.h @@ -15,7 +15,7 @@ class SignalModel : public QAbstractItemModel { Q_OBJECT public: struct Item { - enum Type {Root, Sig, Name, Size, Endian, Signed, Offset, Factor, ExtraInfo, Unit, Comment, Min, Max, Desc }; + enum Type {Root, Sig, Name, Size, Endian, Signed, Offset, Factor, SignalType, MultiplexValue, ExtraInfo, Unit, Comment, Min, Max, Desc }; ~Item() { qDeleteAll(children); } inline int row() { return parent->children.indexOf(this); } @@ -86,6 +86,7 @@ public: QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; QValidator *name_validator, *double_validator; QFont label_font, minmax_font; @@ -112,7 +113,6 @@ signals: private: void rowsChanged(); - void leaveEvent(QEvent *event) override; void resizeEvent(QResizeEvent* event) override; void updateToolBar(); void setSparklineRange(int value); @@ -130,6 +130,10 @@ private: // Bypass the slow call to QTreeView::dataChanged. QAbstractItemView::dataChanged(topLeft, bottomRight, roles); } + void leaveEvent(QEvent *event) override { + emit ((SignalView *)parentWidget())->highlight(nullptr); + QTreeView::leaveEvent(event); + } }; int max_value_width = 0; TreeView *tree; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index dc23421a8c..059215b364 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -180,7 +180,7 @@ void CanData::compute(const char *can_data, const int size, double current_sec, dat.resize(size); bit_change_counts.resize(size); colors = QVector(size, QColor(0, 0, 0, 0)); - last_change_t = QVector(size, ts); + last_change_t.assign(size, ts); last_delta.resize(size); same_delta_counter.resize(size); } else { diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index cdb939b948..78610fc657 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -20,10 +20,10 @@ struct CanData { double freq = 0; QByteArray dat; QVector colors; - QVector last_change_t; - QVector> bit_change_counts; - QVector last_delta; - QVector same_delta_counter; + std::vector last_change_t; + std::vector> bit_change_counts; + std::vector last_delta; + std::vector same_delta_counter; }; struct CanEvent { diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index c7c79c8388..2e580c0f0d 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -55,11 +55,12 @@ bool ReplayStream::eventFilter(const Event *event) { const auto dat = c.getDat(); updateEvent(id, current_sec, (const uint8_t*)dat.begin(), dat.size()); } - double ts = millis_since_boot(); - if ((ts - prev_update_ts) > (1000.0 / settings.fps)) { - if (postEvents()) { - prev_update_ts = ts; - } + } + + double ts = millis_since_boot(); + if ((ts - prev_update_ts) > (1000.0 / settings.fps)) { + if (postEvents()) { + prev_update_ts = ts; } } return true; diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index a5705a14a6..5087de0329 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -11,7 +11,7 @@ public: void start() override; bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); bool eventFilter(const Event *event); - void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); }; + void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); } inline QString routeName() const override { return replay->route()->name(); } inline QString carFingerprint() const override { return replay->carFingerprint().c_str(); } double totalSeconds() const override { return replay->totalSeconds(); } diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 01b8dd7081..8b2a81e4b1 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -10,13 +10,13 @@ const std::string TEST_RLOG_URL = "https://commadata2.blob.core.windows.net/commadata2/4cf7a6ad03080c90/2021-09-29--13-46-36/0/rlog.bz2"; TEST_CASE("DBCFile::generateDBC") { - QString fn = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, "toyota_new_mc_pt_generated"); + QString fn = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, "tesla_can"); DBCFile dbc_origin(fn); DBCFile dbc_from_generated("", dbc_origin.generateDBC()); REQUIRE(dbc_origin.msgCount() == dbc_from_generated.msgCount()); - auto msgs = dbc_origin.getMessages(); - auto new_msgs = dbc_from_generated.getMessages(); + auto &msgs = dbc_origin.getMessages(); + auto &new_msgs = dbc_from_generated.getMessages(); for (auto &[id, m] : msgs) { auto &new_m = new_msgs.at(id); REQUIRE(m.name == new_m.name); @@ -76,6 +76,10 @@ BO_ 160 message_1: 8 XXX SG_ signal_1 : 0|12@1+ (1,0) [0|4095] "unit" XXX SG_ signal_2 : 12|1@1+ (1.0,0.0) [0.0|1] "" XXX +BO_ 162 message_1: 8 XXX + SG_ signal_1 M : 0|12@1+ (1,0) [0|4095] "unit" XXX + SG_ signal_2 M4 : 12|1@1+ (1.0,0.0) [0.0|1] "" XXX + VAL_ 160 signal_1 0 "disabled" 1.2 "initializing" 2 "fault"; CM_ BO_ 160 "message comment" ; @@ -109,4 +113,14 @@ CM_ SG_ 160 signal_2 "multiple line comment auto &sig_2 = msg->sigs[1]; REQUIRE(sig_2->comment == "multiple line comment\n1\n2"); + + // multiplexed signals + msg = file.msg(162); + REQUIRE(msg != nullptr); + REQUIRE(msg->sigs.size() == 2); + REQUIRE(msg->sigs[0]->type == cabana::Signal::Type::Multiplexor); + REQUIRE(msg->sigs[1]->type == cabana::Signal::Type::Multiplexed); + REQUIRE(msg->sigs[1]->multiplex_value == 4); + REQUIRE(msg->sigs[1]->start_bit == 12); + REQUIRE(msg->sigs[1]->size == 1); } diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 5eb4d7fb86..72429104a5 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -28,7 +28,7 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi msg_cb = new QComboBox(this); // TODO: update when src_bus_combo changes - for (auto &[address, msg] : dbc()->getMessages(0)) { + for (auto &[address, msg] : dbc()->getMessages(-1)) { msg_cb->addItem(msg.name, address); } msg_cb->model()->sort(0); From 55e489db7cfeed8585825dda90f2ec9e122381f2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 14:47:45 -0700 Subject: [PATCH 244/283] HKG: split up platform code parsing (#28532) * test diff * clean up * clean up * doesn't work :( * fix mypy --- selfdrive/car/hyundai/values.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 2a15925ebb..76284ce664 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -4,7 +4,7 @@ from dateutil import rrule from collections import defaultdict from dataclasses import dataclass from enum import Enum, IntFlag -from typing import DefaultDict, Dict, List, Optional, Set, Union +from typing import DefaultDict, Dict, List, Optional, Set, Union, cast from cereal import car from panda.python import uds @@ -349,11 +349,13 @@ FINGERPRINTS = { def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]: - codes: DefaultDict[bytes, Set[bytes]] = defaultdict(set) + codes: DefaultDict[bytes, Set[Optional[bytes]]] = defaultdict(set) for fw in fw_versions: - match = PLATFORM_CODE_FW_PATTERN.search(fw) - if match is not None: - code, date = match.groups() + code_match, date_match = (PLATFORM_CODE_FW_PATTERN.search(fw), + DATE_FW_PATTERN.search(fw)) + if code_match is not None: + code = code_match.group() + date = date_match.group() if date_match else None codes[code].add(date) # Create platform codes for all dates inclusive if ECU has FW dates @@ -365,14 +367,14 @@ def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]: continue try: - parsed = {datetime.strptime(date.decode()[:4], '%y%m') for date in dates} + parsed = {datetime.strptime(cast(bytes, date).decode()[:4], '%y%m') for date in dates} except ValueError: cloudlog.exception(f'Error parsing date in FW versions: {code!r}, {dates}') final_codes.add(code) continue - for date in rrule.rrule(rrule.MONTHLY, dtstart=min(parsed), until=max(parsed)): - final_codes.add(code + b'-' + date.strftime('%y%m').encode()) + for monthly in rrule.rrule(rrule.MONTHLY, dtstart=min(parsed), until=max(parsed)): + final_codes.add(code + b'-' + monthly.strftime('%y%m').encode()) return final_codes @@ -392,7 +394,8 @@ HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x4 # Regex patterns for parsing platform code, FW date, and part number from FW versions PLATFORM_CODE_FW_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] + - b')[A-Z]{2}[A-Za-z0-9]{0,2})(?:.*([0-9]{6}))?') + b')[A-Z]{2}[A-Za-z0-9]{0,2})') +DATE_FW_PATTERN = re.compile(b'(?<=[ -])([0-9]{6}$)') PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z][A-Z0-9]{3}[0-9])') FW_QUERY_CONFIG = FwQueryConfig( From 242e8d2ca879665a0dbbf49ea291b86d4f62461d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 14 Jun 2023 01:12:53 +0200 Subject: [PATCH 245/283] locationd: initial value for gps_std_factor (#28533) * setup_gps method * Add LocalizerGnssSource * slight refactor * make it more readable * Move gnss_source initialization to configure_gnss_souce * Add gps_variance_factor, gps_vertical_variance_factor and gps_time_offset * add header changes --- selfdrive/locationd/liblocationd.cc | 2 +- selfdrive/locationd/locationd.cc | 46 +++++++++++++++++------------ selfdrive/locationd/locationd.h | 14 +++++++-- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/selfdrive/locationd/liblocationd.cc b/selfdrive/locationd/liblocationd.cc index 32fec7724a..6f298deab6 100755 --- a/selfdrive/locationd/liblocationd.cc +++ b/selfdrive/locationd/liblocationd.cc @@ -4,7 +4,7 @@ extern "C" { typedef Localizer* Localizer_t; Localizer *localizer_init(bool has_ublox) { - return new Localizer(has_ublox); + return new Localizer(has_ublox ? LocalizerGnssSource::UBLOX : LocalizerGnssSource::QCOM); } void localizer_get_message_bytes(Localizer *localizer, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid, diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index af31218499..3616f0af85 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -70,7 +70,7 @@ static VectorXd rotate_std(const MatrixXdr& rot_matrix, const VectorXd& std_in) return rotate_cov(rot_matrix, std_in.array().square().matrix().asDiagonal()).diagonal().array().sqrt(); } -Localizer::Localizer() { +Localizer::Localizer(LocalizerGnssSource gnss_source) { this->kf = std::make_unique(); this->reset_kalman(); @@ -84,10 +84,9 @@ Localizer::Localizer() { VectorXd ecef_pos = this->kf->get_x().segment(STATE_ECEF_POS_START); this->converter = std::make_unique((ECEF) { .x = ecef_pos[0], .y = ecef_pos[1], .z = ecef_pos[2] }); + this->configure_gnss_source(gnss_source); } -Localizer::Localizer(bool has_ublox) : Localizer() { ublox_available = has_ublox; } - void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { VectorXd predicted_state = this->kf->get_x(); MatrixXdr predicted_cov = this->kf->get_P(); @@ -325,12 +324,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R VectorXd ecef_pos = this->converter->ned2ecef({ 0.0, 0.0, 0.0 }).to_vector(); VectorXd ecef_vel = this->converter->ned2ecef({ log.getVNED()[0], log.getVNED()[1], log.getVNED()[2] }).to_vector() - ecef_pos; - float ecef_pos_std; - if (ublox_available) { - ecef_pos_std = std::sqrt(std::pow(log.getAccuracy(), 2) + std::pow(log.getVerticalAccuracy(), 2)); - } else { - ecef_pos_std = std::sqrt(3 * std::pow(log.getVerticalAccuracy(), 2)); - } + float ecef_pos_std = std::sqrt(this->gps_variance_factor * std::pow(log.getAccuracy(), 2) + this->gps_vertical_variance_factor * std::pow(log.getVerticalAccuracy(), 2)); MatrixXdr ecef_pos_R = Vector3d::Constant(std::pow(this->gps_std_factor * ecef_pos_std, 2)).asDiagonal(); MatrixXdr ecef_vel_R = Vector3d::Constant(std::pow(this->gps_std_factor * log.getSpeedAccuracy(), 2)).asDiagonal(); @@ -372,10 +366,7 @@ void Localizer::handle_gnss(double current_time, const cereal::GnssMeasurements: } double sensor_time = log.getMeasTime() * 1e-9; - if (ublox_available) - sensor_time -= GPS_UBLOX_SENSOR_TIME_OFFSET; - else - sensor_time -= GPS_QUECTEL_SENSOR_TIME_OFFSET; + sensor_time -= this->gps_time_offset; auto ecef_pos_v = log.getPositionECEF().getValue(); VectorXd ecef_pos = Vector3d(ecef_pos_v[0], ecef_pos_v[1], ecef_pos_v[2]); @@ -664,16 +655,33 @@ void Localizer::determine_gps_mode(double current_time) { } } -int Localizer::locationd_thread() { - ublox_available = Params().getBool("UbloxAvailable", true); - const char* gps_location_socket; - if (ublox_available) { - gps_location_socket = "gpsLocationExternal"; +void Localizer::configure_gnss_source(LocalizerGnssSource source) { + this->gnss_source = source; + if (source == LocalizerGnssSource::UBLOX) { this->gps_std_factor = 10.0; + this->gps_variance_factor = 1.0; + this->gps_vertical_variance_factor = 1.0; + this->gps_time_offset = GPS_UBLOX_SENSOR_TIME_OFFSET; } else { - gps_location_socket = "gpsLocation"; this->gps_std_factor = 2.0; + this->gps_variance_factor = 0.0; + this->gps_vertical_variance_factor = 3.0; + this->gps_time_offset = GPS_QUECTEL_SENSOR_TIME_OFFSET; } +} + +int Localizer::locationd_thread() { + LocalizerGnssSource source; + const char* gps_location_socket; + if (Params().getBool("UbloxAvailable", true)) { + source = LocalizerGnssSource::UBLOX; + gps_location_socket = "gpsLocationExternal"; + } else { + source = LocalizerGnssSource::QCOM; + gps_location_socket = "gpsLocation"; + } + + this->configure_gnss_source(source); const std::initializer_list service_list = {gps_location_socket, "cameraOdometry", "liveCalibration", "carState", "carParams", "accelerometer", "gyroscope"}; diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index e2b2096afc..e8f2f04a2c 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -21,10 +21,13 @@ #define POSENET_STD_HIST_HALF 20 +enum LocalizerGnssSource { + UBLOX, QCOM +}; + class Localizer { public: - Localizer(); - Localizer(bool has_ublox); + Localizer(LocalizerGnssSource gnss_source = LocalizerGnssSource::UBLOX); int locationd_thread(); @@ -81,10 +84,15 @@ private: double first_valid_log_time = NAN; double ttff = NAN; double last_gps_msg = 0; - bool ublox_available = true; + LocalizerGnssSource gnss_source; bool observation_timings_invalid = false; std::map observation_values_invalid; bool standstill = true; int32_t orientation_reset_count = 0; float gps_std_factor; + float gps_variance_factor; + float gps_vertical_variance_factor; + double gps_time_offset; + + void configure_gnss_source(LocalizerGnssSource source); }; From 15fcd0d9d4f579265ac8c19c5fd5960c29c9074b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 14 Jun 2023 01:13:20 +0200 Subject: [PATCH 246/283] regen: remove support for fake extra vision client (#28520) * Remove extra client from camera replay * Fix another device type check --- selfdrive/test/process_replay/regen.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index 18c7e3a8dc..59f0fe703f 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -120,19 +120,17 @@ def replay_service(s, msgs): def replay_cameras(lr, frs, disable_tqdm=False): eon_cameras = [ - ("roadCameraState", DT_MDL, eon_f_frame_size, VisionStreamType.VISION_STREAM_ROAD, True), - ("driverCameraState", DT_DMON, eon_d_frame_size, VisionStreamType.VISION_STREAM_DRIVER, False), + ("roadCameraState", DT_MDL, eon_f_frame_size, VisionStreamType.VISION_STREAM_ROAD), + ("driverCameraState", DT_DMON, eon_d_frame_size, VisionStreamType.VISION_STREAM_DRIVER), ] tici_cameras = [ - ("roadCameraState", DT_MDL, tici_f_frame_size, VisionStreamType.VISION_STREAM_ROAD, False), - ("wideRoadCameraState", DT_MDL, tici_e_frame_size, VisionStreamType.VISION_STREAM_WIDE_ROAD, False), - ("driverCameraState", DT_DMON, tici_d_frame_size, VisionStreamType.VISION_STREAM_DRIVER, False), + ("roadCameraState", DT_MDL, tici_f_frame_size, VisionStreamType.VISION_STREAM_ROAD), + ("wideRoadCameraState", DT_MDL, tici_e_frame_size, VisionStreamType.VISION_STREAM_WIDE_ROAD), + ("driverCameraState", DT_DMON, tici_d_frame_size, VisionStreamType.VISION_STREAM_DRIVER), ] - def replay_camera(s, stream, dt, vipc_server, frames, size, use_extra_client): + def replay_camera(s, stream, dt, vipc_server, frames, size): services = [(s, stream)] - if use_extra_client: - services.append(("wideRoadCameraState", VisionStreamType.VISION_STREAM_WIDE_ROAD)) pm = messaging.PubMaster([s for s, _ in services]) rk = Ratekeeper(1 / dt, print_delay_threshold=None) @@ -154,12 +152,12 @@ def replay_cameras(lr, frs, disable_tqdm=False): vipc_server.send(stream, img, msg.frameId, msg.timestampSof, msg.timestampEof) init_data = [m for m in lr if m.which() == 'initData'][0] - cameras = tici_cameras if (init_data.initData.deviceType == 'tici') else eon_cameras + cameras = tici_cameras if (init_data.initData.deviceType in ['tici', 'tizi']) else eon_cameras # init vipc server and cameras p = [] vs = VisionIpcServer("camerad") - for (s, dt, size, stream, use_extra_client) in cameras: + for (s, dt, size, stream) in cameras: fr = frs.get(s, None) frames = None @@ -171,10 +169,8 @@ def replay_cameras(lr, frs, disable_tqdm=False): frames.append(img.flatten().tobytes()) vs.create_buffers(stream, 40, False, size[0], size[1]) - if use_extra_client: - vs.create_buffers(VisionStreamType.VISION_STREAM_WIDE_ROAD, 40, False, size[0], size[1]) p.append(multiprocessing.Process(target=replay_camera, - args=(s, stream, dt, vs, frames, size, use_extra_client))) + args=(s, stream, dt, vs, frames, size))) vs.start_listener() return vs, p @@ -307,7 +303,7 @@ def regen_and_save(route, sidx, daemons="all", upload=False, use_route_meta=Fals lr = LogReader(f"cd:/{route.replace('|', '/')}/{sidx}/rlog.bz2") fr = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/fcamera.hevc") device_type = next(iter(lr)).initData.deviceType - if device_type == 'tici': + if device_type in ['tici', 'tizi']: wfr = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/ecamera.hevc") else: wfr = None From fcc268b8be70e72654252e5424840ca37ad04196 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 20:00:54 -0700 Subject: [PATCH 247/283] exact matching: use set for invalid (#28537) use set --- selfdrive/car/fw_versions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index bfb65f7a12..ce7aeb3a1e 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -106,7 +106,7 @@ def match_fw_to_car_exact(fw_versions_dict, log=True) -> Set[str]: FW versions for a list of "essential" ECUs. If an ECU is not considered essential the FW version can be missing to get a fingerprint, but if it's present it needs to match the database.""" - invalid = [] + invalid = set() candidates = FW_VERSIONS for candidate, fws in candidates.items(): @@ -130,10 +130,10 @@ def match_fw_to_car_exact(fw_versions_dict, log=True) -> Set[str]: continue if not any([found_version in expected_versions for found_version in found_versions]): - invalid.append(candidate) + invalid.add(candidate) break - return set(candidates.keys()) - set(invalid) + return set(candidates.keys()) - invalid def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True, log=True): From 348df9c974f0ce83a228c988d1508170f8edec1a Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 13 Jun 2023 20:37:17 -0700 Subject: [PATCH 248/283] Fix index out of bound error for body carcontroller (#28539) --- selfdrive/car/body/carcontroller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index bcaf6f6f93..64c5617ef3 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -40,7 +40,7 @@ class CarController: torque_l = 0 torque_r = 0 - llk_valid = len(CC.orientationNED) > 0 and len(CC.angularVelocity) > 0 + llk_valid = len(CC.orientationNED) > 1 and len(CC.angularVelocity) > 1 if CC.enabled and llk_valid: # Read these from the joystick # TODO: this isn't acceleration, okay? From 572a221a86d8048baba3fe50d6a950e4775f6f9f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 20:41:03 -0700 Subject: [PATCH 249/283] FwQueryConfig: remove platform codes (#28538) * bring platform codes out of config for now (can re-introduce later) * clean that up * flake8 * comment * comments and better test names * typo * Update selfdrive/car/hyundai/tests/test_hyundai.py * Update selfdrive/car/hyundai/tests/test_hyundai.py --- selfdrive/car/fw_query_definitions.py | 8 +--- selfdrive/car/hyundai/tests/test_hyundai.py | 46 +++++++++++++-------- selfdrive/car/hyundai/values.py | 8 ++-- selfdrive/car/tests/test_fw_fingerprint.py | 15 ------- 4 files changed, 34 insertions(+), 43 deletions(-) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index b3fb8476e5..7ae9bee404 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -3,7 +3,7 @@ import capnp import copy from dataclasses import dataclass, field import struct -from typing import Callable, Dict, List, Optional, Set, Tuple +from typing import Dict, List, Optional, Tuple import panda.python.uds as uds @@ -75,12 +75,6 @@ class FwQueryConfig: # Ecus added for data collection, not to be fingerprinted on extra_ecus: List[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]]] = field(default_factory=list) - # Brand-specific fuzzy fingerprinting config options: - # A function to get unique, platform-specific identification codes for a set of versions - fuzzy_get_platform_codes: Optional[Callable[[List[bytes]], Set[bytes]]] = None - # List of ECUs expected to have platform codes - platform_code_ecus: List[capnp.lib.capnp._EnumModule] = field(default_factory=list) - def __post_init__(self): for i in range(len(self.requests)): if self.requests[i].auxiliary: diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index 8bac256935..3b82b59d03 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -3,7 +3,8 @@ import unittest from cereal import car from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, FW_QUERY_CONFIG, \ - FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, PART_NUMBER_FW_PATTERN + FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, PART_NUMBER_FW_PATTERN, PLATFORM_CODE_ECUS, \ + get_platform_codes Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} @@ -25,21 +26,24 @@ class TestHyundaiFingerprint(unittest.TestCase): ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist]) self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}') + # Tests for platform codes, part numbers, and FW dates which Hyundai will use to fuzzy + # fingerprint in the absence of full FW matches: def test_platform_code_ecus_available(self): + # TODO: add queries for these non-CAN FD cars to get EPS no_eps_platforms = CANFD_CAR | {CAR.KIA_SORENTO, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.TUCSON, CAR.GENESIS_G90, CAR.GENESIS_G80} # Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): - for fuzzy_ecu in FW_QUERY_CONFIG.platform_code_ecus: - if fuzzy_ecu in (Ecu.fwdRadar, Ecu.eps) and car_model == CAR.HYUNDAI_GENESIS: + for platform_code_ecu in PLATFORM_CODE_ECUS: + if platform_code_ecu in (Ecu.fwdRadar, Ecu.eps) and car_model == CAR.HYUNDAI_GENESIS: continue - if fuzzy_ecu == Ecu.eps and car_model in no_eps_platforms: + if platform_code_ecu == Ecu.eps and car_model in no_eps_platforms: continue - self.assertIn(fuzzy_ecu, [e[0] for e in ecus]) + self.assertIn(platform_code_ecu, [e[0] for e in ecus]) - def test_fw_part_number(self): + def test_fw_part_numbers(self): # Hyundai places the ECU part number in their FW versions, assert all parsable # Some examples of valid formats: '56310-L0010', '56310L0010', '56310/M6300' for car_model, ecus in FW_VERSIONS.items(): @@ -48,42 +52,50 @@ class TestHyundaiFingerprint(unittest.TestCase): raise unittest.SkipTest("No part numbers for car model") for ecu, fws in ecus.items(): - if ecu[0] not in FW_QUERY_CONFIG.platform_code_ecus: + if ecu[0] not in PLATFORM_CODE_ECUS: continue for fw in fws: match = PART_NUMBER_FW_PATTERN.search(fw) self.assertIsNotNone(match, fw) - def test_fuzzy_fw_dates(self): + def test_fw_dates(self): # Some newer platforms have date codes in a different format we don't yet parse, # for now assert date format is consistent for all FW across each platform for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): for ecu, fws in ecus.items(): - if ecu[0] not in FW_QUERY_CONFIG.platform_code_ecus: + if ecu[0] not in PLATFORM_CODE_ECUS: continue codes = set() for fw in fws: - codes |= FW_QUERY_CONFIG.fuzzy_get_platform_codes([fw]) + codes |= get_platform_codes([fw]) # Either no dates should be parsed or all dates should be parsed self.assertEqual(len({b'-' in code for code in codes}), 1) - def test_fuzzy_platform_codes(self): - # Asserts basic platform code parsing behavior - codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00DH LKAS 1.1 -150210']) + def test_platform_codes_all_parsable(self): + # Assert every supported ECU FW version returns one platform code + for fw_by_addr in FW_VERSIONS.values(): + for addr, fws in fw_by_addr.items(): + if addr[0] in PLATFORM_CODE_ECUS: + for f in fws: + self.assertEqual(1, len(get_platform_codes([f])), f"Unable to parse FW: {f}") + + def test_platform_codes_spot_check(self): + # Asserts basic platform code parsing behavior for a few cases + codes = get_platform_codes([b'\xf1\x00DH LKAS 1.1 -150210']) self.assertEqual(codes, {b"DH-1502"}) # Some cameras and all radars do not have dates - codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ']) + codes = get_platform_codes([b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ']) self.assertEqual(codes, {b"AEhe"}) - codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ']) + codes = get_platform_codes([b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ']) self.assertEqual(codes, {b"CV1"}) - codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([ + codes = get_platform_codes([ b'\xf1\x00DH LKAS 1.1 -150210', b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ', b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', @@ -91,7 +103,7 @@ class TestHyundaiFingerprint(unittest.TestCase): self.assertEqual(codes, {b"DH-1502", b"AEhe", b"CV1"}) # Returned platform codes must inclusively contain start/end dates - codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([ + codes = get_platform_codes([ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222', b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103', b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405', diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 76284ce664..c0a8f8fae6 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -398,6 +398,10 @@ PLATFORM_CODE_FW_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1: DATE_FW_PATTERN = re.compile(b'(?<=[ -])([0-9]{6}$)') PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z][A-Z0-9]{3}[0-9])') +# List of ECUs expected to have platform codes, camera and radar should exist on all cars +# TODO: use abs, it has the platform code and part number on many platforms +PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps] + FW_QUERY_CONFIG = FwQueryConfig( requests=[ # TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD @@ -454,10 +458,6 @@ FW_QUERY_CONFIG = FwQueryConfig( (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], - fuzzy_get_platform_codes=get_platform_codes, - # Camera and radar should exist on all cars - # TODO: use abs, it has the platform code and part number on many platforms - platform_code_ecus=[Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps], ) FW_VERSIONS = { diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index 97441f89af..b90120a1e2 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -123,21 +123,6 @@ class TestFwFingerprint(unittest.TestCase): with self.subTest(): self.fail(f"Brands do not implement FW_QUERY_CONFIG: {brand_versions - brand_configs}") - def test_fuzzy_fingerprint_config(self): - for brand, config in FW_QUERY_CONFIGS.items(): - with self.subTest(brand=brand): - if config.fuzzy_get_platform_codes is None: - self.assertEqual(len(config.platform_code_ecus), 0, "Cannot specify platform code ECUs without full config") - else: - self.assertGreater(len(config.platform_code_ecus), 0, "Need to specify platform code ECUs") - - # Assert every supported ECU FW version returns one platform code - for fw_by_addr in VERSIONS[brand].values(): - for addr, fws in fw_by_addr.items(): - if addr[0] in config.platform_code_ecus: - for f in fws: - self.assertEqual(1, len(config.fuzzy_get_platform_codes([f])), f"Unable to parse FW: {f}") - def test_fw_request_ecu_whitelist(self): for brand, config in FW_QUERY_CONFIGS.items(): with self.subTest(brand=brand): From 6c619561ee7fc45ba8abb10bc37ec027fab0ba88 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 21:26:31 -0700 Subject: [PATCH 250/283] FPv2 timing unit test: halve runs (#28540) Update test_fw_fingerprint.py --- selfdrive/car/tests/test_fw_fingerprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index b90120a1e2..0f52e12625 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -192,7 +192,7 @@ class TestFwFingerprintTiming(unittest.TestCase): if not len(multi_panda_requests) and num_pandas > 1: raise unittest.SkipTest("No multi-panda FW queries") - avg_time = self._benchmark(brand, num_pandas, 10) + avg_time = self._benchmark(brand, num_pandas, 5) total_time += avg_time self._assert_timing(avg_time, brand_ref_times[num_pandas][brand], tol) print(f'{brand=}, {num_pandas=}, {len(config.requests)=}, avg FW query time={avg_time} seconds') From d94c2a8ef7c0fd961c53ffb71ee79451eefa2d5f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Jun 2023 22:17:47 -0700 Subject: [PATCH 251/283] Hyundai FPv2 unit tests: clean up (#28542) * be consistent with quotes * combine tests * cmt --- selfdrive/car/hyundai/tests/test_hyundai.py | 77 ++++++++++----------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index 3b82b59d03..77aed9c979 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -23,8 +23,9 @@ class TestHyundaiFingerprint(unittest.TestCase): for car_model in CANFD_CAR: ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()} ecus_not_in_whitelist = ecus - whitelisted_ecus - ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist]) - self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}') + ecu_strings = ", ".join([f"Ecu.{ECU_NAME[ecu]}" for ecu in ecus_not_in_whitelist]) + self.assertEqual(len(ecus_not_in_whitelist), 0, + f"{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}") # Tests for platform codes, part numbers, and FW dates which Hyundai will use to fuzzy # fingerprint in the absence of full FW matches: @@ -43,25 +44,12 @@ class TestHyundaiFingerprint(unittest.TestCase): continue self.assertIn(platform_code_ecu, [e[0] for e in ecus]) - def test_fw_part_numbers(self): - # Hyundai places the ECU part number in their FW versions, assert all parsable - # Some examples of valid formats: '56310-L0010', '56310L0010', '56310/M6300' - for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model): - if car_model == CAR.HYUNDAI_GENESIS: - raise unittest.SkipTest("No part numbers for car model") + def test_fw_format(self): + # Asserts: + # - every supported ECU FW version returns one platform code + # - every supported ECU FW version has a part number + # - expected parsing of ECU FW dates - for ecu, fws in ecus.items(): - if ecu[0] not in PLATFORM_CODE_ECUS: - continue - - for fw in fws: - match = PART_NUMBER_FW_PATTERN.search(fw) - self.assertIsNotNone(match, fw) - - def test_fw_dates(self): - # Some newer platforms have date codes in a different format we don't yet parse, - # for now assert date format is consistent for all FW across each platform for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): for ecu, fws in ecus.items(): @@ -70,47 +58,52 @@ class TestHyundaiFingerprint(unittest.TestCase): codes = set() for fw in fws: - codes |= get_platform_codes([fw]) + result = get_platform_codes([fw]) + self.assertEqual(1, len(result), f"Unable to parse FW: {fw}") + codes |= result - # Either no dates should be parsed or all dates should be parsed - self.assertEqual(len({b'-' in code for code in codes}), 1) + # Some newer platforms have date codes in a different format we don't yet parse, + # for now assert we can parse all FW or none + self.assertEqual(len({b"-" in code for code in codes}), 1, + "Not all FW dates are parsable") - def test_platform_codes_all_parsable(self): - # Assert every supported ECU FW version returns one platform code - for fw_by_addr in FW_VERSIONS.values(): - for addr, fws in fw_by_addr.items(): - if addr[0] in PLATFORM_CODE_ECUS: - for f in fws: - self.assertEqual(1, len(get_platform_codes([f])), f"Unable to parse FW: {f}") + if car_model == CAR.HYUNDAI_GENESIS: + raise unittest.SkipTest("No part numbers for car model") + + # Hyundai places the ECU part number in their FW versions, assert all parsable + # Some examples of valid formats: b"56310-L0010", b"56310L0010", b"56310/M6300" + for fw in fws: + match = PART_NUMBER_FW_PATTERN.search(fw) + self.assertIsNotNone(match, fw) def test_platform_codes_spot_check(self): # Asserts basic platform code parsing behavior for a few cases - codes = get_platform_codes([b'\xf1\x00DH LKAS 1.1 -150210']) + codes = get_platform_codes([b"\xf1\x00DH LKAS 1.1 -150210"]) self.assertEqual(codes, {b"DH-1502"}) # Some cameras and all radars do not have dates - codes = get_platform_codes([b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ']) + codes = get_platform_codes([b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 "]) self.assertEqual(codes, {b"AEhe"}) - codes = get_platform_codes([b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ']) + codes = get_platform_codes([b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 "]) self.assertEqual(codes, {b"CV1"}) codes = get_platform_codes([ - b'\xf1\x00DH LKAS 1.1 -150210', - b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ', - b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', + b"\xf1\x00DH LKAS 1.1 -150210", + b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ", + b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ", ]) self.assertEqual(codes, {b"DH-1502", b"AEhe", b"CV1"}) # Returned platform codes must inclusively contain start/end dates codes = get_platform_codes([ - b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222', - b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103', - b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405', - b'\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 190720', + b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222", + b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103", + b"\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405", + b"\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 190720", ]) - self.assertEqual(codes, {b'LX2-2111', b'LX2-2112', b'LX2-2201', b'LX2-2202', - b'ON-1904', b'ON-1905', b'ON-1906', b'ON-1907'}) + self.assertEqual(codes, {b"LX2-2111", b"LX2-2112", b"LX2-2201", b"LX2-2202", + b"ON-1904", b"ON-1905", b"ON-1906", b"ON-1907"}) if __name__ == "__main__": From c5c9d5b92107ed59f3fb70a356f82b3cbe0b3da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 13 Jun 2023 22:54:37 -0700 Subject: [PATCH 252/283] Fix CARLA simulation (#28541) * logmessaged conflicts with onnxrunner * More fixes, now engages * Fix can properly * Otherwise it faults * Put check back * remove more hacks * remove more hacks * Not relevant anymore * Narrow camera default --- tools/sim/bridge.py | 17 +++++++++-------- tools/sim/launch_openpilot.sh | 2 +- tools/sim/lib/can.py | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index adb477b664..64446e1115 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -68,13 +68,14 @@ def steer_rate_limit(old, new): class Camerad: - def __init__(self): + def __init__(self, dual_camera): self.frame_road_id = 0 self.frame_wide_id = 0 self.vipc_server = VisionIpcServer("camerad") self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_ROAD, 5, False, W, H) - self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_WIDE_ROAD, 5, False, W, H) + if dual_camera: + self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_WIDE_ROAD, 5, False, W, H) self.vipc_server.start_listener() # set up for pyopencl rgb to yuv conversion @@ -254,6 +255,7 @@ class CarlaBridge: msg.liveCalibration.validBlocks = 20 msg.liveCalibration.rpyCalib = [0.0, 0.0, 0.0] self.params.put("CalibrationParams", msg.to_bytes()) + self.params.put_bool("DisengageOnAccelerator", True) self._args = arguments self._carla_objects = [] @@ -348,14 +350,13 @@ class CarlaBridge: camera.listen(callback) return camera - self._camerad = Camerad() + self._camerad = Camerad(self._args.dual_camera) if self._args.dual_camera: - road_camera = create_camera(fov=40, callback=self._camerad.cam_callback_road) - self._carla_objects.append(road_camera) - - road_wide_camera = create_camera(fov=120, callback=self._camerad.cam_callback_wide_road) # fov bigger than 120 shows unwanted artifacts - self._carla_objects.append(road_wide_camera) + road_wide_camera = create_camera(fov=120, callback=self._camerad.cam_callback_wide_road) # fov bigger than 120 shows unwanted artifacts + self._carla_objects.append(road_wide_camera) + road_camera = create_camera(fov=40, callback=self._camerad.cam_callback_road) + self._carla_objects.append(road_camera) vehicle_state = VehicleState() diff --git a/tools/sim/launch_openpilot.sh b/tools/sim/launch_openpilot.sh index 2100f05b67..d5922a4819 100755 --- a/tools/sim/launch_openpilot.sh +++ b/tools/sim/launch_openpilot.sh @@ -6,7 +6,7 @@ export SIMULATION="1" export SKIP_FW_QUERY="1" export FINGERPRINT="HONDA CIVIC 2016" -export BLOCK="camerad,loggerd,encoderd,micd" +export BLOCK="camerad,loggerd,encoderd,micd,logmessaged" if [[ "$CI" ]]; then # TODO: offscreen UI should work export BLOCK="${BLOCK},ui" diff --git a/tools/sim/lib/can.py b/tools/sim/lib/can.py index af4339b2e4..fba4dc0e58 100755 --- a/tools/sim/lib/can.py +++ b/tools/sim/lib/can.py @@ -68,6 +68,7 @@ def can_function(pm, speed, angle, idx, cruise_button, is_engaged): # *** cam bus *** msg.append(packer.make_can_msg("STEERING_CONTROL", 2, {})) msg.append(packer.make_can_msg("ACC_HUD", 2, {})) + msg.append(packer.make_can_msg("LKAS_HUD", 2, {})) msg.append(packer.make_can_msg("BRAKE_COMMAND", 2, {})) # *** radar bus *** From 155cab9ec4f75da43cf2f89c51651bf74d11b021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 13 Jun 2023 23:39:11 -0700 Subject: [PATCH 253/283] Disable internet in laikad.py, even in CI (#28535) * Limit OPENBLAS to 1 thread in manager * Restrict openblas threads when running openpilot * print in CI * Disable internet for laika, even in CI * update ref --- selfdrive/locationd/laikad.py | 4 +--- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 0115d2581a..836de1696d 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -457,12 +457,10 @@ def main(sm=None, pm=None): pm = messaging.PubMaster(['gnssMeasurements']) # disable until set as main gps source, to better analyze startup time + # TODO ensure low CPU usage before enabling use_internet = False # "LAIKAD_NO_INTERNET" not in os.environ replay = "REPLAY" in os.environ - if replay: - use_internet = True - laikad = Laikad(save_ephemeris=not replay, auto_fetch_navs=use_internet, use_qcom=use_qcom) while True: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a7d5b333d2..9e0fba3640 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -05b4467181f826f934a7ee4aada003fb241bbdff +72b5d91c92a72b2a708526dade78960950c5b595 From 7a5b0b97e1d030dc896a559c292f86965bb51193 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 14 Jun 2023 07:53:58 -0700 Subject: [PATCH 254/283] Ford Escape 2020 FW (#28545) --- selfdrive/car/ford/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index a2e9ea2442..d3a5951b79 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -141,6 +141,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7E0, None): [ b'LX6A-14C204-BJV\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6A-14C204-BJX\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6A-14C204-ESG\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MX6A-14C204-BEF\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MX6A-14C204-BEJ\x00\x00\x00\x00\x00\x00\x00\x00\x00', From c4537714925bed4b380c4a981669491f7a692031 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 14 Jun 2023 15:54:04 -0700 Subject: [PATCH 255/283] HKG: add script to view platform codes (#28549) add script --- .../car/hyundai/tests/print_platform_codes.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 selfdrive/car/hyundai/tests/print_platform_codes.py diff --git a/selfdrive/car/hyundai/tests/print_platform_codes.py b/selfdrive/car/hyundai/tests/print_platform_codes.py new file mode 100755 index 0000000000..3268bf620d --- /dev/null +++ b/selfdrive/car/hyundai/tests/print_platform_codes.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +from cereal import car +from selfdrive.car.hyundai.values import FW_VERSIONS, PLATFORM_CODE_ECUS, get_platform_codes + +Ecu = car.CarParams.Ecu +ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} + +if __name__ == "__main__": + for car_model, ecus in FW_VERSIONS.items(): + print() + print(car_model) + for ecu in sorted(ecus, key=lambda x: int(x[0])): + if ecu[0] not in PLATFORM_CODE_ECUS: + continue + + codes = set() + dates = set() + for fw in ecus[ecu]: + code = list(get_platform_codes([fw]))[0] + codes.add(code.split(b"-")[0]) + if b"-" in code: + dates.add(code.split(b"-")[1]) + + print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') + print(f' Codes: {codes}') + print(f' Dates: {dates}') From 6d25f66cf1cd8e3912719b79a44c4ff0fa013328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 14 Jun 2023 19:54:51 -0700 Subject: [PATCH 256/283] Laikad: Need to understand constellationId to understand clock (#28552) Need to understand constellationId to understand clock --- selfdrive/locationd/laikad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 836de1696d..ed922f89c3 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -196,11 +196,11 @@ class Laikad: try: constellation_id = ConstellationId.from_qcom_source(gnss_msg.drMeasurementReport.source) good_constellation = constellation_id in [ConstellationId.GPS, ConstellationId.SBAS, ConstellationId.GLONASS] + report_time = self.gps_time_from_qcom_report(gnss_msg) except NotImplementedError: - good_constellation = False + return False # Garbage timestamps with week > 32767 are sometimes sent by module. # This is an issue with gpsTime and GLONASS time. - report_time = self.gps_time_from_qcom_report(gnss_msg) good_week = report_time.week < np.iinfo(np.int16).max return good_constellation and good_week elif gnss_msg.which() == 'measurementReport' and not self.use_qcom: From 4a0b5dacbb40bc20a3583be795756b5c23f13b91 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 14 Jun 2023 21:42:33 -0700 Subject: [PATCH 257/283] pandad: update time from RTC (#28466) * pandad: update time from RTC * Update pandad.py --------- Co-authored-by: Comma Device --- selfdrive/boardd/pandad.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/selfdrive/boardd/pandad.py b/selfdrive/boardd/pandad.py index 859a30a1bc..6ab6d05b08 100755 --- a/selfdrive/boardd/pandad.py +++ b/selfdrive/boardd/pandad.py @@ -10,6 +10,7 @@ from functools import cmp_to_key from panda import Panda, PandaDFU, FW_PATH from common.basedir import BASEDIR from common.params import Params +from selfdrive.boardd.set_time import set_time from system.hardware import HARDWARE from system.swaglog import cloudlog @@ -133,6 +134,11 @@ def main() -> NoReturn: cloudlog.event("heartbeat lost", deviceState=health, serial=panda.get_usb_serial()) if first_run: + if panda.is_internal(): + # update time from RTC + set_time(cloudlog) + + # reset panda to ensure we're in a good state cloudlog.info(f"Resetting panda {panda.get_usb_serial()}") if panda.is_internal(): HARDWARE.reset_internal_panda() From da3003ee41eb5e80a78d7639ecfdf16536f0fab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 14 Jun 2023 21:51:55 -0700 Subject: [PATCH 258/283] Alpha long control no longer called experimental (#28437) * Fix words * vanish --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/translations/main_de.ts | 8 ++++---- selfdrive/ui/translations/main_ja.ts | 8 ++++---- selfdrive/ui/translations/main_ko.ts | 8 ++++---- selfdrive/ui/translations/main_pt-BR.ts | 8 ++++---- selfdrive/ui/translations/main_zh-CHS.ts | 8 ++++---- selfdrive/ui/translations/main_zh-CHT.ts | 8 ++++---- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index e37e5a9843..d9f200865f 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -174,7 +174,7 @@ void TogglesPanel::updateToggles() { tr("openpilot longitudinal control may come in a future update."); if (CP.getExperimentalLongitudinalAvailable()) { if (is_release) { - long_desc = unavailable + " " + tr("An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches."); + long_desc = unavailable + " " + tr("An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches."); } else { long_desc = tr("Enable experimental longitudinal control to allow Experimental mode."); } diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 447f66f016..55b66c132e 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1036,10 +1036,6 @@ This may take up to a minute. openpilot longitudinal control may come in a future update. - - An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - - Enable experimental longitudinal control to allow Experimental mode. Aktiviere den experimentellen Openpilot Tempomaten für experimentelle Funktionen. @@ -1076,6 +1072,10 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + +
Updater diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 6dc183d7f7..162c92c402 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1030,10 +1030,6 @@ This may take up to a minute. openpilot longitudinal control may come in a future update. - - An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - - Enable experimental longitudinal control to allow Experimental mode. 実験段階のopenpilotによるアクセル制御を有効にしてください。 @@ -1070,6 +1066,10 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 1936805aa5..ef5a89750d 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1031,10 +1031,6 @@ This may take up to a minute. openpilot longitudinal control may come in a future update. 오픈파일럿 롱컨트롤은 향후 업데이트에서 제공될 수 있습니다. - - An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 오픈파일럿 롱컨트롤의 실험 버전은 실험적 모드와 함께 릴리즈 되지 않은 브랜치에서 테스트할 수 있습니다. - Enable experimental longitudinal control to allow Experimental mode. 실험적 롱컨트롤을 사용하려면 실험적 모드를 활성화 하세요. @@ -1071,6 +1067,10 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. 표준 모드를 권장합니다. 공격적 모드에서는 openpilot은 앞차를 더 가까이 따라가며 가속과 감속을 더 공격적으로 사용합니다. 편안한 모드에서 openpilot은 선두 차량에서 더 멀리 떨어져 있습니다. + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 226416dca9..87a813111e 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1035,10 +1035,6 @@ Isso pode levar até um minuto. openpilot longitudinal control may come in a future update. O controle longitudinal openpilot pode vir em uma atualização futura. - - An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Uma versão experimental do controle longitudinal openpilot pode ser testada, juntamente com o modo Experimental, em branches de desenvolvimento. - Enable experimental longitudinal control to allow Experimental mode. Ative o controle longitudinal experimental para permitir o modo Experimental. @@ -1075,6 +1071,10 @@ Isso pode levar até um minuto. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. Neutro é o recomendado. No modo disputa o openpilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o openpilot se manterá mais longe do carro da frente. + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 1d7cdd9f60..4a92d963d2 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1028,10 +1028,6 @@ This may take up to a minute. openpilot longitudinal control may come in a future update. - - An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - - Enable experimental longitudinal control to allow Experimental mode. 启用试验性的纵向控制,以便允许使用试验模式。 @@ -1068,6 +1064,10 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index c6e2d22f5a..01fab62feb 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1030,10 +1030,6 @@ This may take up to a minute. openpilot longitudinal control may come in a future update. 未來可能會推出openpilot縱向控制 - - An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 在非發行分支中 可找到包含實驗模式的openpilot縱向控制測試版本 - Enable experimental longitudinal control to allow Experimental mode. 啟用實驗性縱向控制以使用實驗模式。 @@ -1070,6 +1066,10 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. 推薦使用標準模式。在積極模式中,openpilot 會更靠近前車並在加速和剎車方面更積極。在舒適模式中,openpilot 會與前車保持較遠的距離。 + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + Updater From a1b6697629912ed4432a222f2cdb451f1dbc576a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 14 Jun 2023 22:48:51 -0700 Subject: [PATCH 259/283] logmessaged: handle big cloudlogs (#28553) * logmessaged: handle big cloudlogs * revert * switch --- .github/workflows/selfdrive_tests.yaml | 1 + system/logmessaged.py | 37 ++++++++++------ system/tests/__init__.py | 0 system/tests/test_logmessaged.py | 60 ++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 system/tests/__init__.py create mode 100755 system/tests/test_logmessaged.py diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 9d92392b3a..ea20612c16 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -209,6 +209,7 @@ jobs: $UNIT_TEST system/loggerd && \ $UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/locationd && \ + $UNIT_TEST system/tests && \ $UNIT_TEST system/ubloxd && \ selfdrive/locationd/test/_test_locationd_lib.py && \ ./system/ubloxd/tests/test_glonass_runner && \ diff --git a/system/logmessaged.py b/system/logmessaged.py index 280a23cf1d..8f24471941 100755 --- a/system/logmessaged.py +++ b/system/logmessaged.py @@ -12,7 +12,7 @@ def main() -> NoReturn: log_handler.setFormatter(SwagLogFileFormatter(None)) log_level = 20 # logging.INFO - ctx = zmq.Context().instance() + ctx = zmq.Context.instance() sock = ctx.socket(zmq.PULL) sock.bind("ipc:///tmp/logmessage") @@ -20,23 +20,32 @@ def main() -> NoReturn: log_message_sock = messaging.pub_sock('logMessage') error_log_message_sock = messaging.pub_sock('errorLogMessage') - while True: - dat = b''.join(sock.recv_multipart()) - level = dat[0] - record = dat[1:].decode("utf-8") - if level >= log_level: - log_handler.emit(record) + try: + while True: + dat = b''.join(sock.recv_multipart()) + level = dat[0] + record = dat[1:].decode("utf-8") + if level >= log_level: + log_handler.emit(record) - # then we publish them - msg = messaging.new_message() - msg.logMessage = record - log_message_sock.send(msg.to_bytes()) + if len(record) > 2*1024*1024: + print("WARNING: log too big to publish", len(record)) + print(print(record[:100])) + continue - if level >= 40: # logging.ERROR + # then we publish them msg = messaging.new_message() - msg.errorLogMessage = record - error_log_message_sock.send(msg.to_bytes()) + msg.logMessage = record + log_message_sock.send(msg.to_bytes()) + if level >= 40: # logging.ERROR + msg = messaging.new_message() + msg.errorLogMessage = record + error_log_message_sock.send(msg.to_bytes()) + finally: + sock.close() + ctx.term() + log_handler.close() if __name__ == "__main__": main() diff --git a/system/tests/__init__.py b/system/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/system/tests/test_logmessaged.py b/system/tests/test_logmessaged.py new file mode 100755 index 0000000000..08335517ae --- /dev/null +++ b/system/tests/test_logmessaged.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import glob +import os +import shutil +import time +import unittest + +import cereal.messaging as messaging +from selfdrive.manager.process_config import managed_processes +from system.swaglog import cloudlog, SWAGLOG_DIR + + +class TestLogmessaged(unittest.TestCase): + + def setUp(self): + if os.path.exists(SWAGLOG_DIR): + shutil.rmtree(SWAGLOG_DIR) + + managed_processes['logmessaged'].start() + self.sock = messaging.sub_sock("logMessage", timeout=1000, conflate=False) + self.error_sock = messaging.sub_sock("logMessage", timeout=1000, conflate=False) + + # ensure sockets are connected + time.sleep(0.2) + messaging.drain_sock(self.sock) + messaging.drain_sock(self.error_sock) + + def tearDown(self): + del self.sock + del self.error_sock + managed_processes['logmessaged'].stop(block=True) + + def _get_log_files(self): + return list(glob.glob(os.path.join(SWAGLOG_DIR, "swaglog.*"))) + + def test_simple_log(self): + msgs = [f"abc {i}" for i in range(10)] + for m in msgs: + cloudlog.error(m) + time.sleep(3) + m = messaging.drain_sock(self.sock) + assert len(m) == len(msgs) + assert len(self._get_log_files()) >= 1 + + def test_big_log(self): + n = 10 + msg = "a"*3*1024*1024 + for _ in range(n): + cloudlog.info(msg) + time.sleep(3) + + msgs = messaging.drain_sock(self.sock) + assert len(msgs) == 0 + + logsize = sum([os.path.getsize(f) for f in self._get_log_files()]) + assert (n*len(msg)) < logsize < (n*(len(msg)+1024)) + + +if __name__ == "__main__": + unittest.main() From e771660fa331a34a111f1b5878c75adb50b216b8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Jun 2023 01:29:55 -0700 Subject: [PATCH 260/283] FPv2: rename live FW versions dict (#28550) rename --- selfdrive/car/fw_versions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index ce7aeb3a1e..37ddf94cad 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -54,7 +54,7 @@ def get_brand_addrs() -> Dict[str, Set[Tuple[int, Optional[int]]]]: return dict(brand_addrs) -def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): +def match_fw_to_car_fuzzy(live_fw_versions, log=True, exclude=None): """Do a fuzzy FW match. This function will return a match, and the number of firmware version that were matched uniquely to that specific car. If multiple ECUs uniquely match to different cars the match is rejected.""" @@ -77,7 +77,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): matched_ecus = set() candidate = None - for addr, versions in fw_versions_dict.items(): + for addr, versions in live_fw_versions.items(): ecu_key = (addr[0], addr[1]) for version in versions: # All cars that have this FW response on the specified address @@ -101,7 +101,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): return set() -def match_fw_to_car_exact(fw_versions_dict, log=True) -> Set[str]: +def match_fw_to_car_exact(live_fw_versions, log=True) -> Set[str]: """Do an exact FW match. Returns all cars that match the given FW versions for a list of "essential" ECUs. If an ECU is not considered essential the FW version can be missing to get a fingerprint, but if it's present it @@ -115,7 +115,7 @@ def match_fw_to_car_exact(fw_versions_dict, log=True) -> Set[str]: ecu_type = ecu[0] addr = ecu[1:] - found_versions = fw_versions_dict.get(addr, set()) + found_versions = live_fw_versions.get(addr, set()) if not len(found_versions): # Some models can sometimes miss an ecu, or show on two different addresses if candidate in config.non_essential_ecus.get(ecu_type, []): From 2166adda5f9c5a58c175c87d6e5f73e3d90d2e4f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Jun 2023 02:14:33 -0700 Subject: [PATCH 261/283] HKG: test list of platforms with no fwdCamera dates (#28555) * no dates test * sorted --- selfdrive/car/hyundai/tests/test_hyundai.py | 39 ++++++++++++++++----- selfdrive/car/hyundai/values.py | 2 ++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index 77aed9c979..906ae59606 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -2,13 +2,36 @@ import unittest from cereal import car -from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, FW_QUERY_CONFIG, \ - FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, PART_NUMBER_FW_PATTERN, PLATFORM_CODE_ECUS, \ - get_platform_codes - +from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \ + FW_QUERY_CONFIG, FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, \ + PART_NUMBER_FW_PATTERN, PLATFORM_CODE_ECUS, get_platform_codes Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} +# Some platforms have date codes in a different format we don't yet parse (or are missing). +# For now, assert list of expected missing date cars +NO_DATES_PLATFORMS = { + # CAN FD + CAR.KIA_SPORTAGE_5TH_GEN, + CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, + CAR.SANTA_CRUZ_1ST_GEN, + CAR.TUCSON_4TH_GEN, + CAR.TUCSON_HYBRID_4TH_GEN, + # CAN + CAR.ELANTRA, + CAR.KIA_CEED, + CAR.KIA_FORTE, + CAR.KIA_OPTIMA_G4, + CAR.KIA_OPTIMA_G4_FL, + CAR.KIA_SORENTO, + CAR.KONA, + CAR.KONA_EV, + CAR.KONA_EV_2022, + CAR.KONA_HEV, + CAR.SONATA_LF, + CAR.VELOSTER, +} + class TestHyundaiFingerprint(unittest.TestCase): def test_canfd_not_in_can_features(self): @@ -62,10 +85,10 @@ class TestHyundaiFingerprint(unittest.TestCase): self.assertEqual(1, len(result), f"Unable to parse FW: {fw}") codes |= result - # Some newer platforms have date codes in a different format we don't yet parse, - # for now assert we can parse all FW or none - self.assertEqual(len({b"-" in code for code in codes}), 1, - "Not all FW dates are parsable") + if ecu[0] not in DATE_FW_ECUS or car_model in NO_DATES_PLATFORMS: + self.assertTrue(all({b"-" not in code for code in codes})) + else: + self.assertTrue(all({b"-" in code for code in codes})) if car_model == CAR.HYUNDAI_GENESIS: raise unittest.SkipTest("No part numbers for car model") diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index c0a8f8fae6..f8aabbce3e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -401,6 +401,8 @@ PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z] # List of ECUs expected to have platform codes, camera and radar should exist on all cars # TODO: use abs, it has the platform code and part number on many platforms PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps] +# So far we've only seen dates in fwdCamera +DATE_FW_ECUS = [Ecu.fwdCamera] FW_QUERY_CONFIG = FwQueryConfig( requests=[ From f788edb6a5c8d3f516076f886fe0d831ee43b580 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Jun 2023 02:50:45 -0700 Subject: [PATCH 262/283] HKG: use platform codes to fuzzy fingerprint (#28531) * get gas/ev/hev from FW (not all correct, poc) * add test for essential ecus for fuzzy fingerprinting * kinda works * stash * clean up * add code * simpler * use the function * test it with our cars * no re no re no re * debugging * handle empty dict * simpl * this is promising start on making existing fingerprinting functions use the config, instead of entirely replacing them * needs to allow 1 match * lay out how this should look * changes * executable * some work * use config * fuzzy ecus * config test * comment and some clean up * test platform codes * use regex, simpler and fixes bug * in func * rm bad func * typing for new func and remove old from dc * todo done * tested! * remove fake platform codes * thought we needed this, but actually... * not needed * not applicable any more * use config for essential ecus * first draft of test to make adding/removing fuzzy FP platform intentional * compile * clean up test * even cleaner * fix default ecus type * temp fix * this is mostly in tests now * test every fuzzy ecu fw returns one platform code * experiment with dates * Revert "experiment with dates" This reverts commit 3251b9cc5c3ca41ca92c8b75ad9b2234b720aa0b. * clean that up * comment * test * work on all cars * fix fuzz_fw_fingerprint * comment * get first by search * bit more clean up * and more * use compiled pattern for nicer syntax * default * flip dat around, much cleaner * clean up hyundai test a bit * flip order same here * rename test and flip subTest * fix pylint * revert fw changes revert fw changes * line * add original functions to test * needs to be a list * cmt * draft (need to count one ecu as a match) * tiny clean up * todo: date range * only in notebook * remove comment (still can be either list or set) * same, only notebook * more consistent signature * copilot inspired * copilot no good * test for date parsing * better name * good, now we don't have to worry about the dates mismatching in another test/logic * comment up+ * some stuff * clean up fix test fix test * test * comment * use utils * clean up (utils are cleaner and less buggy) * clean up (utils are cleaner and less buggy) * fixup test * use a dash (prettier) and remove some platforms that can fingerprint now! * compile global pattern * same as what we do in values * remove comments * fuzzy_get_platform_codes is one or none here * more clean up * sort imports * woah woah woah * add comment * fix reassigning different types * add types * adapt fuzzy test recently added (nice it caught this!) * update lock * options comments * stash * comments and fixes * better comments * better * test: run on exact fuzzy matching logic, same results! * use match_fw_to_car * test all fw * ex * unused random * this is a possibility * this is more clear * fix * revert * revert to needing both ECUs to match to reduce false positives, test * fix excluded platform test :( but it's ok * add comment * we actually want to only test fuzzy ecus to make it explicit * fix mypy * comment for tomorrow * just add matches with fuzzy FP * add comment * this was the cleanest I could think of, but still working on it. not very easy to understand * think this is better, but also worse... * comment: reframing how this works * revert back to what we did before * was swapped * else set * remove old comment * fixes from merge * remove fuzzy_min_match_count from this pr * fix static analysis * also unused * different method first draft * copy existing fuzzy func * check all possible ecus exist, only platform codes, slightly refactor main loop * fix * Revert recent Revert "fix" This reverts commit 5cdb7bda835f1e48e750ab4195e891afe08e11ea. Revert "check all possible ecus exist, only platform codes, slightly refactor main loop" This reverts commit d3e918fa20fa4ce881445850f5f7428a3c11adf8. Revert "copy existing fuzzy func" This reverts commit 34c8c0545097c84f55f4b4f61907606c93760ddd. Revert "different method first draft" This reverts commit b91139055d7d1802c1eb726504798c156a183c9c. * new func * fixup test * remove changes from v1 from fw_versions.py * clean up a bit * return part as part of code * fix test * add original fuzzy function * add an ecu match if the date is within range (or date doesn't exist) * add format for what we're going to do * not working stash * the exact matching function does more of what we want with less code and less custom logic * we don't care about found versions, only codes and dates * actually we do have an exception * this works pretty nicely now * up here * this is better * some minor clean up * old function=now junk * fix platform code test * remove old platform code function * now rename _new to * use FW_QUERY_CONFIG * clean up imports * rename that too * one line * correct typing correct typing * draft tests * so that works * fixup excluded platform test now too * this is tested by excluded platform test * test parts and dates * remove old comment * old import * take platform code stuff out of FwQueryConfig * fix test * revert debug script * flip order * make this a set by default * revert this part * correct typing * clean up comments * clean that test up too/pylint * combine these three tests ina clean way * not right * more general * be consistent with quotes * comment * comment * comment in fw_versions * flip order * this is more readable * could test all this, but it's tested in test_hyundai and doesn't do a lot here * only assert brands which use this * invalidate all CAN FD ICE and hybrid * tuple * can get away without filtering * add comment reasons * fix * some review suggestions * this works (first draft) * this is better * script to print platform codes and dates * sanity check for dates are in correct ecus and platforms * mypy * better variable name and comment * rename * same * slightly better name * subset * exclude platforms and live car without dates * consistent * self explan * better name * test to make sure the functions agree * clean that up * comment * we get other responses from queries not in DB, only check any * not used or typed --- selfdrive/car/fw_query_definitions.py | 5 +- selfdrive/car/fw_versions.py | 5 ++ .../car/hyundai/tests/print_platform_codes.py | 11 +-- selfdrive/car/hyundai/tests/test_hyundai.py | 68 ++++++++++---- selfdrive/car/hyundai/values.py | 90 +++++++++++++------ selfdrive/car/tests/test_fw_fingerprint.py | 24 ++++- 6 files changed, 147 insertions(+), 56 deletions(-) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index 7ae9bee404..f9f8e30a68 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -3,7 +3,7 @@ import capnp import copy from dataclasses import dataclass, field import struct -from typing import Dict, List, Optional, Tuple +from typing import Callable, Dict, List, Optional, Set, Tuple import panda.python.uds as uds @@ -74,6 +74,9 @@ class FwQueryConfig: non_essential_ecus: Dict[capnp.lib.capnp._EnumModule, List[str]] = field(default_factory=dict) # Ecus added for data collection, not to be fingerprinted on extra_ecus: List[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]]] = field(default_factory=list) + # Function a brand can implement to provide better fuzzy matching. Takes in FW versions, + # returns set of candidates. Only will match if one candidate is returned + match_fw_to_car_fuzzy: Optional[Callable[[Dict[Tuple[int, Optional[int]], Set[bytes]]], Set[str]]] = None def __post_init__(self): for i in range(len(self.requests)): diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 37ddf94cad..5c07134d82 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -151,6 +151,11 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True, log=True): fw_versions_dict = build_fw_dict(fw_versions, filter_brand=brand) matches |= match_func(fw_versions_dict, log=log) + # If specified and no matches so far, fall back to brand's fuzzy fingerprinting function + config = FW_QUERY_CONFIGS[brand] + if not exact_match and not len(matches) and config.match_fw_to_car_fuzzy is not None: + matches |= config.match_fw_to_car_fuzzy(fw_versions_dict) + if len(matches): return exact_match, matches diff --git a/selfdrive/car/hyundai/tests/print_platform_codes.py b/selfdrive/car/hyundai/tests/print_platform_codes.py index 3268bf620d..1bc8a4e366 100755 --- a/selfdrive/car/hyundai/tests/print_platform_codes.py +++ b/selfdrive/car/hyundai/tests/print_platform_codes.py @@ -13,14 +13,9 @@ if __name__ == "__main__": if ecu[0] not in PLATFORM_CODE_ECUS: continue - codes = set() - dates = set() - for fw in ecus[ecu]: - code = list(get_platform_codes([fw]))[0] - codes.add(code.split(b"-")[0]) - if b"-" in code: - dates.add(code.split(b"-")[1]) - + platform_codes = get_platform_codes(ecus[ecu]) + codes = {code for code, _ in platform_codes} + dates = {date for _, date in platform_codes if date is not None} print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') print(f' Codes: {codes}') print(f' Dates: {dates}') diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index 906ae59606..36d2b3dc4c 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -2,9 +2,11 @@ import unittest from cereal import car +from selfdrive.car.fw_versions import build_fw_dict from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \ - FW_QUERY_CONFIG, FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, \ - PART_NUMBER_FW_PATTERN, PLATFORM_CODE_ECUS, get_platform_codes + EV_CAR, FW_QUERY_CONFIG, FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, \ + PLATFORM_CODE_ECUS, get_platform_codes + Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} @@ -86,47 +88,75 @@ class TestHyundaiFingerprint(unittest.TestCase): codes |= result if ecu[0] not in DATE_FW_ECUS or car_model in NO_DATES_PLATFORMS: - self.assertTrue(all({b"-" not in code for code in codes})) + self.assertTrue(all({date is None for _, date in codes})) else: - self.assertTrue(all({b"-" in code for code in codes})) + self.assertTrue(all({date is not None for _, date in codes})) if car_model == CAR.HYUNDAI_GENESIS: raise unittest.SkipTest("No part numbers for car model") # Hyundai places the ECU part number in their FW versions, assert all parsable # Some examples of valid formats: b"56310-L0010", b"56310L0010", b"56310/M6300" - for fw in fws: - match = PART_NUMBER_FW_PATTERN.search(fw) - self.assertIsNotNone(match, fw) + self.assertTrue(all({b"-" in code for code, _ in codes}), + f"FW does not have part number: {fw}") def test_platform_codes_spot_check(self): # Asserts basic platform code parsing behavior for a few cases - codes = get_platform_codes([b"\xf1\x00DH LKAS 1.1 -150210"]) - self.assertEqual(codes, {b"DH-1502"}) + results = get_platform_codes([b"\xf1\x00DH LKAS 1.1 -150210"]) + self.assertEqual(results, {(b"DH", b"150210")}) # Some cameras and all radars do not have dates - codes = get_platform_codes([b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 "]) - self.assertEqual(codes, {b"AEhe"}) + results = get_platform_codes([b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 "]) + self.assertEqual(results, {(b"AEhe-G2000", None)}) - codes = get_platform_codes([b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 "]) - self.assertEqual(codes, {b"CV1"}) + results = get_platform_codes([b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 "]) + self.assertEqual(results, {(b"CV1-CV000", None)}) - codes = get_platform_codes([ + results = get_platform_codes([ b"\xf1\x00DH LKAS 1.1 -150210", b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ", b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ", ]) - self.assertEqual(codes, {b"DH-1502", b"AEhe", b"CV1"}) + self.assertEqual(results, {(b"DH", b"150210"), (b"AEhe-G2000", None), (b"CV1-CV000", None)}) - # Returned platform codes must inclusively contain start/end dates - codes = get_platform_codes([ + results = get_platform_codes([ b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222", b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103", b"\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405", b"\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 190720", ]) - self.assertEqual(codes, {b"LX2-2111", b"LX2-2112", b"LX2-2201", b"LX2-2202", - b"ON-1904", b"ON-1905", b"ON-1906", b"ON-1907"}) + self.assertEqual(results, {(b"LX2-S8100", b"220222"), (b"LX2-S8100", b"211103"), + (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, + CAR.TUCSON_4TH_GEN, # shared platform code and part number + CAR.TUCSON_HYBRID_4TH_GEN, + } + excluded_platforms |= CANFD_CAR - EV_CAR # 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 = [] + for ecu, fw_versions in fw_by_addr.items(): + ecu_name, addr, sub_addr = ecu + for fw in fw_versions: + car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr, + "subAddress": 0 if sub_addr is None else sub_addr}) + + CP = car.CarParams.new_message(carFw=car_fw) + matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw)) + if len(matches) == 1: + self.assertEqual(list(matches)[0], platform) + else: + platforms_with_shared_codes.add(platform) + + self.assertEqual(platforms_with_shared_codes, excluded_platforms) if __name__ == "__main__": diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index f8aabbce3e..1d05730853 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1,10 +1,7 @@ import re -from datetime import datetime -from dateutil import rrule -from collections import defaultdict from dataclasses import dataclass from enum import Enum, IntFlag -from typing import DefaultDict, Dict, List, Optional, Set, Union, cast +from typing import Dict, List, Optional, Set, Tuple, Union from cereal import car from panda.python import uds @@ -12,7 +9,6 @@ from common.conversions import Conversions as CV from selfdrive.car import dbc_dict from selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 -from system.swaglog import cloudlog Ecu = car.CarParams.Ecu @@ -348,35 +344,73 @@ FINGERPRINTS = { } -def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]: - codes: DefaultDict[bytes, Set[Optional[bytes]]] = defaultdict(set) +def get_platform_codes(fw_versions: List[bytes]) -> Set[Tuple[bytes, Optional[bytes]]]: + # Returns unique, platform-specific identification codes for a set of versions + codes = set() # (code-Optional[part], date) for fw in fw_versions: - code_match, date_match = (PLATFORM_CODE_FW_PATTERN.search(fw), - DATE_FW_PATTERN.search(fw)) + code_match = PLATFORM_CODE_FW_PATTERN.search(fw) + part_match = PART_NUMBER_FW_PATTERN.search(fw) + date_match = DATE_FW_PATTERN.search(fw) if code_match is not None: - code = code_match.group() + code: bytes = code_match.group() + part = part_match.group() if part_match else None date = date_match.group() if date_match else None - codes[code].add(date) + if part is not None: + # part number starts with generic ECU part type, add what is specific to platform + code += b"-" + part[-5:] - # Create platform codes for all dates inclusive if ECU has FW dates - final_codes = set() - for code, dates in codes.items(): - # Radar and some cameras don't have FW dates - if None in dates: - final_codes.add(code) - continue + codes.add((code, date)) + return codes - try: - parsed = {datetime.strptime(cast(bytes, date).decode()[:4], '%y%m') for date in dates} - except ValueError: - cloudlog.exception(f'Error parsing date in FW versions: {code!r}, {dates}') - final_codes.add(code) - continue - for monthly in rrule.rrule(rrule.MONTHLY, dtstart=min(parsed), until=max(parsed)): - final_codes.add(code + b'-' + monthly.strftime('%y%m').encode()) +def match_fw_to_car_fuzzy(live_fw_versions) -> Set[str]: + # Non-electric CAN FD platforms often do not have platform code specifiers needed + # to distinguish between hybrid and ICE. All EVs so far are either exclusively + # electric or specify electric in the platform code. + fuzzy_platform_blacklist = set(CANFD_CAR - EV_CAR) + candidates = set() - return final_codes + for candidate, fws in FW_VERSIONS.items(): + # Keep track of ECUs which pass all checks (platform codes, within date range) + valid_found_ecus = set() + valid_expected_ecus = {ecu[1:] for ecu in fws if ecu[0] in PLATFORM_CODE_ECUS} + for ecu, expected_versions in fws.items(): + addr = ecu[1:] + # Only check ECUs expected to have platform codes + if ecu[0] not in PLATFORM_CODE_ECUS: + continue + + # Expected platform codes & dates + codes = get_platform_codes(expected_versions) + expected_platform_codes = {code for code, _ in codes} + expected_dates = {date for _, date in codes if date is not None} + + # Found platform codes & dates + codes = get_platform_codes(live_fw_versions.get(addr, set())) + found_platform_codes = {code for code, _ in codes} + found_dates = {date for _, date in codes if date is not None} + + # Check platform code + part number matches for any found versions + if not any(found_platform_code in expected_platform_codes for found_platform_code in found_platform_codes): + break + + if ecu[0] in DATE_FW_ECUS: + # If ECU can have a FW date, require it to exist + # (this excludes candidates in the database without dates) + if not len(expected_dates) or not len(found_dates): + break + + # Check any date within range in the database, format is %y%m%d + if not any(min(expected_dates) <= found_date <= max(expected_dates) for found_date in found_dates): + break + + valid_found_ecus.add(addr) + + # If all live ECUs pass all checks for candidate, add it as a match + if valid_expected_ecus.issubset(valid_found_ecus): + candidates.add(candidate) + + return candidates - fuzzy_platform_blacklist HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ @@ -460,6 +494,8 @@ FW_QUERY_CONFIG = FwQueryConfig( (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], + # Custom fuzzy fingerprinting function using platform codes, part numbers + FW dates: + match_fw_to_car_fuzzy=match_fw_to_car_fuzzy, ) FW_VERSIONS = { diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index 0f52e12625..883c4e34a0 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -10,7 +10,7 @@ from cereal import car from common.params import Params from selfdrive.car.car_helpers import interfaces from selfdrive.car.fingerprints import FW_VERSIONS -from selfdrive.car.fw_versions import FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, match_fw_to_car, get_fw_versions +from selfdrive.car.fw_versions import FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, build_fw_dict, match_fw_to_car, get_fw_versions CarFw = car.CarParams.CarFw Ecu = car.CarParams.Ecu @@ -45,6 +45,28 @@ class TestFwFingerprint(unittest.TestCase): _, matches = match_fw_to_car(CP.carFw, allow_fuzzy=False) self.assertFingerprints(matches, car_model) + @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) + def test_custom_fuzzy_match(self, brand, car_model, ecus): + # Assert brand-specific fuzzy fingerprinting function doesn't disagree with standard fuzzy function + config = FW_QUERY_CONFIGS[brand] + if config.match_fw_to_car_fuzzy is None: + raise unittest.SkipTest("Brand does not implement custom fuzzy fingerprinting function") + + CP = car.CarParams.new_message() + for _ in range(5): + fw = [] + for ecu, fw_versions in ecus.items(): + ecu_name, addr, sub_addr = ecu + fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, + "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) + CP.carFw = fw + _, matches = match_fw_to_car(CP.carFw, allow_exact=False, log=False) + brand_matches = config.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw)) + + # If both have matches, they must agree + if len(matches) == 1 and len(brand_matches) == 1: + self.assertEqual(matches, brand_matches) + @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) def test_fuzzy_match_ecu_count(self, brand, car_model, ecus): # Asserts that fuzzy matching does not count matching FW, but ECU address keys From 6f54ebe1103c7960afcd2f3f550e56ba9a7e4667 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 15 Jun 2023 18:50:14 +0800 Subject: [PATCH 263/283] cabana: use raw signal value to match value descriptions (#28554) --- tools/cabana/dbc/dbc.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index 269aeb4247..e0c89823c6 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -131,8 +131,9 @@ void cabana::Signal::update() { QString cabana::Signal::formatValue(double value) const { // Show enum string + int64_t raw_value = (value - offset) / factor; for (const auto &[val, desc] : val_desc) { - if (std::abs(value - val) < 1e-6) { + if (std::abs(raw_value - val) < 1e-6) { return desc; } } From f1bf4f903fe61d5f12aec1d16c73838fb23caa28 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Jun 2023 04:04:48 -0700 Subject: [PATCH 264/283] bump opendbc (#28556) bump --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index 49b31858a3..87b821e0e5 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 49b31858a36275dc16f768781297e443e57d16ab +Subproject commit 87b821e0e5cfead12b0f01c16d6a87b592859cb2 From e57f3ab4daeb18ac1c8786b3b5c7d0ad7b000646 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 15 Jun 2023 12:46:08 +0100 Subject: [PATCH 265/283] cabana: round signal raw value for value description --- tools/cabana/dbc/dbc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index e0c89823c6..402d807b8b 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -131,7 +131,7 @@ void cabana::Signal::update() { QString cabana::Signal::formatValue(double value) const { // Show enum string - int64_t raw_value = (value - offset) / factor; + int64_t raw_value = round((value - offset) / factor); for (const auto &[val, desc] : val_desc) { if (std::abs(raw_value - val) < 1e-6) { return desc; From 4891a234e2ccca943998387cb3f0246e98b63667 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 16 Jun 2023 01:35:30 +0800 Subject: [PATCH 266/283] cabana: Prevent dialog that load autosaved file from blocking replay->start() (#28558) --- tools/cabana/mainwin.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 2961d888ff..87066bf9e6 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -373,7 +373,8 @@ void MainWindow::eventsMerged() { if (!dbc()->msgCount() && !car_fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[car_fingerprint]; if (dbc_name != QJsonValue::Undefined) { - loadDBCFromOpendbc(dbc_name.toString()); + // Prevent dialog that load autosaved file from blocking replay->start(). + QTimer::singleShot(0, [dbc_name, this]() { loadDBCFromOpendbc(dbc_name.toString()); }); } } } From 4b63feddeccbd14f2147f130a8f1bdd90cc73841 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:18:35 -0400 Subject: [PATCH 267/283] VW MQB: Add FW for 2017 Volkswagen Golf (#28559) --- selfdrive/car/volkswagen/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 0f211546bd..3d0379f992 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -404,6 +404,7 @@ FW_VERSIONS = { CAR.GOLF_MK7: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906016A \xf1\x897697', + b'\xf1\x8704E906016N \xf1\x899105', b'\xf1\x8704E906016AD\xf1\x895758', b'\xf1\x8704E906016CE\xf1\x899096', b'\xf1\x8704E906016CH\xf1\x899226', @@ -546,6 +547,7 @@ FW_VERSIONS = { b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A00504A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A00604A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A07A02A1', + b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521A00407A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521A00507A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521A07B04A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521A20B03A1', From 7d6897fa38be4bc6f82f35b902052b12efd47af3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 15:04:22 -0700 Subject: [PATCH 268/283] thermald: save last offroad status packet on onroad transition (#28563) * thermald: save last offroad status packet on onroad transition * update param * write every time --------- Co-authored-by: Comma Device --- common/params.cc | 1 + selfdrive/thermald/thermald.py | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/common/params.cc b/common/params.cc index 0e6b644023..d880db2788 100644 --- a/common/params.cc +++ b/common/params.cc @@ -151,6 +151,7 @@ std::unordered_map keys = { {"LiveParameters", PERSISTENT}, {"LiveTorqueCarParams", PERSISTENT}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG}, + {"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavSettingTime24h", PERSISTENT}, diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 1d0609a5ba..b0214b6351 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import datetime import os +import json import queue import threading import time @@ -375,8 +376,6 @@ def thermald_thread(end_event, hw_queue): msg.deviceState.thermalStatus = thermal_status pm.send("deviceState", msg) - should_start_prev = should_start - # Log to statsd statlog.gauge("free_space_percent", msg.deviceState.freeSpacePercent) statlog.gauge("gpu_usage_percent", msg.deviceState.gpuUsagePercent) @@ -399,15 +398,26 @@ def thermald_thread(end_event, hw_queue): statlog.gauge("screen_brightness_percent", msg.deviceState.screenBrightnessPercent) # report to server once every 10 minutes - if (count % int(600. / DT_TRML)) == 0: - cloudlog.event("STATUS_PACKET", - count=count, - pandaStates=[strip_deprecated_keys(p.to_dict()) for p in pandaStates], - peripheralState=strip_deprecated_keys(peripheralState.to_dict()), - location=(strip_deprecated_keys(sm["gpsLocationExternal"].to_dict()) if sm.alive["gpsLocationExternal"] else None), - deviceState=strip_deprecated_keys(msg.to_dict())) + rising_edge_started = should_start and not should_start_prev + if rising_edge_started or (count % int(600. / DT_TRML)) == 0: + dat = { + 'count': count, + 'pandaStates': [strip_deprecated_keys(p.to_dict()) for p in pandaStates], + 'peripheralState': strip_deprecated_keys(peripheralState.to_dict()), + 'location': (strip_deprecated_keys(sm["gpsLocationExternal"].to_dict()) if sm.alive["gpsLocationExternal"] else None), + 'deviceState': strip_deprecated_keys(msg.to_dict()) + } + cloudlog.event("STATUS_PACKET", **dat) + + # save last one before going onroad + if rising_edge_started: + try: + params.put("LastOffroadStatusPacket", json.dumps(dat)) + except Exception: + cloudlog.exception("failed to save offroad status") count += 1 + should_start_prev = should_start def main(): From 56614124f0f3e927caadf9bb66fa68e9532fe247 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Jun 2023 16:32:32 -0700 Subject: [PATCH 269/283] FPv2: don't add debug candidates to versions globally (#28562) * debugging * this test works, but find a better place * make test more generic to start testing more than timings no need to run again in another test function. eventually we can simulate ECUs and have IsoTpParallelQuery work properly * Revert "make test more generic to start testing more than timings" This reverts commit 58e8536b1d8b138902d373e1e1194e70c9eb4b24. * 2nd try * clean up * not even MappingProxyType works * works * test that too * clean up * refactor to avoid modification online * revert tests * more revert * no longer needed * clean up --- selfdrive/car/fw_versions.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 5c07134d82..5a7a2174c7 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -255,10 +255,6 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, versions = VERSIONS.copy() params = Params() - # Each brand can define extra ECUs to query for data collection - for brand, config in FW_QUERY_CONFIGS.items(): - versions[brand]["debug"] = {ecu: [] for ecu in config.extra_ecus} - if query_brand is not None: versions = {query_brand: versions[query_brand]} @@ -272,8 +268,10 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, ecu_types = {} for brand, brand_versions in versions.items(): + config = FW_QUERY_CONFIGS[brand] for ecu in brand_versions.values(): - for ecu_type, addr, sub_addr in ecu.keys(): + # Each brand can define extra ECUs to query for data collection + for ecu_type, addr, sub_addr in list(ecu) + config.extra_ecus: a = (brand, addr, sub_addr) if a not in ecu_types: ecu_types[a] = ecu_type From 150cda68c25feebc15fc3d47eb61e8ea7b5c8dea Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 15 Jun 2023 19:46:25 -0400 Subject: [PATCH 270/283] VW MQB: Add FW for 2016 SEAT Leon (#28561) --- selfdrive/car/volkswagen/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 3d0379f992..5081ebd3a1 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1066,6 +1066,7 @@ FW_VERSIONS = { b'\xf1\x8704L906021EL\xf1\x897542', b'\xf1\x8704L906026BP\xf1\x891198', b'\xf1\x8704L906026BP\xf1\x897608', + b'\xf1\x8704L906056CR\xf1\x892181', b'\xf1\x8704L906056CR\xf1\x892797', b'\xf1\x8705E906018AS\xf1\x899596', b'\xf1\x878V0906264H \xf1\x890005', @@ -1098,6 +1099,7 @@ FW_VERSIONS = { b'\xf1\x875Q0907572H \xf1\x890620', b'\xf1\x875Q0907572K \xf1\x890402\xf1\x82\x0101', b'\xf1\x875Q0907572P \xf1\x890682', + b'\xf1\x875Q0907572R \xf1\x890771', ], }, CAR.SKODA_FABIA_MK4: { From 3fc104fb6d9db5f4853b61c4c525b581e0caad72 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 15 Jun 2023 17:01:13 -0700 Subject: [PATCH 271/283] test: car interface fuzzy testing + generating capnp structs (#28530) * random car control * format * struct generation * math * staying real * really staying real * move * split this * format * Revert "format" This reverts commit a70a73952ee3833c4ae839d7b2729ee2a1e1a85b. * Revert "split this" This reverts commit ae96be63cbfbee230101e69a0f84c874f321fafa. * space --- release/files_common | 1 + selfdrive/car/tests/test_car_interfaces.py | 10 +++- selfdrive/test/fuzzy_generation.py | 69 ++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 selfdrive/test/fuzzy_generation.py diff --git a/release/files_common b/release/files_common index e90a8e083b..18596a4e79 100644 --- a/release/files_common +++ b/release/files_common @@ -290,6 +290,7 @@ selfdrive/thermald/power_monitoring.py selfdrive/thermald/fan_controller.py selfdrive/test/__init__.py +selfdrive/test/fuzzy_generation.py selfdrive/test/helpers.py selfdrive/test/setup_device_ci.sh selfdrive/test/test_onroad.py diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 7198218d6a..918d2cf873 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import math import unittest +from hypothesis import given, settings import importlib from parameterized import parameterized @@ -8,12 +9,15 @@ from cereal import car from selfdrive.car import gen_empty_fingerprint from selfdrive.car.car_helpers import interfaces from selfdrive.car.fingerprints import _FINGERPRINTS as FINGERPRINTS, all_known_cars +from selfdrive.test.fuzzy_generation import get_random_msg class TestCarInterfaces(unittest.TestCase): @parameterized.expand([(car,) for car in all_known_cars()]) - def test_car_interfaces(self, car_name): + @settings(max_examples=5) + @given(cc_msg=get_random_msg(car.CarControl, real_floats=True)) + def test_car_interfaces(self, car_name, cc_msg): if car_name in FINGERPRINTS: fingerprint = FINGERPRINTS[car_name][0] else: @@ -57,13 +61,13 @@ class TestCarInterfaces(unittest.TestCase): self.assertTrue(len(tune.indi.outerLoopGainV)) # Run car interface - CC = car.CarControl.new_message() + CC = car.CarControl.new_message(**cc_msg) for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC, 0) car_interface.apply(CC, 0) - CC = car.CarControl.new_message() + CC = car.CarControl.new_message(**cc_msg) CC.enabled = True for _ in range(10): car_interface.update(CC, []) diff --git a/selfdrive/test/fuzzy_generation.py b/selfdrive/test/fuzzy_generation.py new file mode 100644 index 0000000000..3dc43e7347 --- /dev/null +++ b/selfdrive/test/fuzzy_generation.py @@ -0,0 +1,69 @@ +import hypothesis.strategies as st +import random + +class FuzzyGenerator: + def __init__(self, real_floats): + self.real_floats=real_floats + + def generate_native_type(self, field): + def floats(**kwargs): + allow_nan = not self.real_floats + allow_infinity = not self.real_floats + return st.floats(**kwargs, allow_nan=allow_nan, allow_infinity=allow_infinity) + + if field == 'bool': + return st.booleans() + elif field == 'int8': + return st.integers(min_value=-2**7, max_value=2**7-1) + elif field == 'int16': + return st.integers(min_value=-2**15, max_value=2**15-1) + elif field == 'int32': + return st.integers(min_value=-2**31, max_value=2**31-1) + elif field == 'int64': + return st.integers(min_value=-2**63, max_value=2**63-1) + elif field == 'uint8': + return st.integers(min_value=0, max_value=2**8-1) + elif field == 'uint16': + return st.integers(min_value=0, max_value=2**16-1) + elif field == 'uint32': + return st.integers(min_value=0, max_value=2**32-1) + elif field == 'uint64': + return st.integers(min_value=0, max_value=2**64-1) + elif field == 'float32': + return floats(width=32) + elif field == 'float64': + return floats(width=64) + elif field == 'text': + return st.text(max_size=1000) + elif field == 'data': + return st.text(max_size=1000) + elif field == 'anyPointer': + return st.text() + else: + raise NotImplementedError(f'Invalid type : {field}') + + def generate_field(self, field): + def rec(field_type): + if field_type.which() == 'struct': + return self.generate_struct(field.schema.elementType if base_type == 'list' else field.schema) + elif field_type.which() == 'list': + return st.lists(rec(field_type.list.elementType)) + elif field_type.which() == 'enum': + schema = field.schema.elementType if base_type == 'list' else field.schema + return st.sampled_from(list(schema.enumerants.keys())) + else: + return self.generate_native_type(field_type.which()) + + if 'slot' in field.proto.to_dict(): + base_type = field.proto.slot.type.which() + return rec(field.proto.slot.type) + else: + return self.generate_struct(field.schema) + + def generate_struct(self, schema): + full_fill = list(schema.non_union_fields) if schema.non_union_fields else [] + single_fill = [random.choice(schema.union_fields)] if schema.union_fields else [] + return st.fixed_dictionaries(dict((field, self.generate_field(schema.fields[field])) for field in full_fill + single_fill)) + +def get_random_msg(struct, real_floats=False): + return FuzzyGenerator(real_floats=real_floats).generate_struct(struct.schema) From cb4c7118a54dc4e3e135dfdc38122e4ef1b2d826 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 17:08:47 -0700 Subject: [PATCH 272/283] thermald: log filtered max temp (#28564) --- cereal | 2 +- selfdrive/thermald/thermald.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index f319a83ab7..3a8e4c9d04 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit f319a83ab7a902477c786a25aa34077b6f640990 +Subproject commit 3a8e4c9d04b050c057f41d9288ab5ff3f3b02669 diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index b0214b6351..955bbe8d5b 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -253,6 +253,7 @@ def thermald_thread(end_event, hw_queue): # this drives the thermal status while onroad temp_sources.append(max(msg.deviceState.pmicTempC)) all_comp_temp = all_temp_filter.update(max(temp_sources)) + msg.deviceState.maxTempC = all_comp_temp if fan_controller is not None: msg.deviceState.fanSpeedPercentDesired = fan_controller.update(all_comp_temp, onroad_conditions["ignition"]) From 3072643363f3b48f9a3846c37e1da5e5d61cd93b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 17:34:01 -0700 Subject: [PATCH 273/283] thermald: fix temperature filter init (#28565) --- selfdrive/thermald/thermald.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 955bbe8d5b..f9000becf4 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -167,7 +167,7 @@ def thermald_thread(end_event, hw_queue): off_ts = None started_ts = None started_seen = False - thermal_status = ThermalStatus.green + thermal_status = ThermalStatus.yellow last_hw_state = HardwareState( network_type=NetworkType.none, @@ -179,8 +179,8 @@ def thermald_thread(end_event, hw_queue): modem_temps=[], ) - all_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML) - offroad_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML) + all_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML, initialized=False) + offroad_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML, initialized=False) should_start_prev = False in_car = False engaged_prev = False @@ -242,7 +242,7 @@ def thermald_thread(end_event, hw_queue): msg.deviceState.screenBrightnessPercent = HARDWARE.get_screen_brightness() - # this one is only used for offroad + # this subset is only used for offroad temp_sources = [ msg.deviceState.memoryTempC, max(msg.deviceState.cpuTempC), From 411cf094f3867a8789329197a63e3bcf9f3aba77 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 18:16:59 -0700 Subject: [PATCH 274/283] thermald: log duration of startup block (#28566) --- selfdrive/thermald/thermald.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index f9000becf4..aab8020818 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -167,6 +167,7 @@ def thermald_thread(end_event, hw_queue): off_ts = None started_ts = None started_seen = False + startup_blocked_ts = None thermal_status = ThermalStatus.yellow last_hw_state = HardwareState( @@ -340,10 +341,16 @@ def thermald_thread(end_event, hw_queue): if started_ts is None: started_ts = sec_since_boot() started_seen = True + if startup_blocked_ts is not None: + cloudlog.event("Startup after block", block_duration=(sec_since_boot() - startup_blocked_ts), + startup_conditions=startup_conditions, onroad_conditions=onroad_conditions, + startup_conditions_prev=startup_conditions_prev, error=True) + startup_blocked_ts = None else: if onroad_conditions["ignition"] and (startup_conditions != startup_conditions_prev): cloudlog.event("Startup blocked", startup_conditions=startup_conditions, onroad_conditions=onroad_conditions, error=True) startup_conditions_prev = startup_conditions.copy() + startup_blocked_ts = sec_since_boot() started_ts = None if off_ts is None: From 10a392a7f188743b3234a16d22bf9800af392c00 Mon Sep 17 00:00:00 2001 From: wilderko Date: Fri, 16 Jun 2023 03:48:15 +0200 Subject: [PATCH 275/283] Added new fingerprint of VW California 2021 (#28504) * Added new VW California 2021 * duplicate eps * hex --------- Co-authored-by: Pavol Luptak Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 5081ebd3a1..5159d5a378 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -878,24 +878,28 @@ FW_VERSIONS = { b'\xf1\x8704L906056AL\xf1\x899970', b'\xf1\x8704L906057AP\xf1\x891186', b'\xf1\x8704L906057N \xf1\x890413', + b'\xf1\x8705L906023E \xf1\x891352', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870BT300012G \xf1\x893102', b'\xf1\x870BT300012E \xf1\x893105', b'\xf1\x870BT300046R \xf1\x893102', + b'\xf1\x870DV300012B \xf1\x893701', ], (Ecu.srs, 0x715, None): [ b'\xf1\x872Q0959655AE\xf1\x890506\xf1\x82\x1316170411110411--04041704161611152S1411', b'\xf1\x872Q0959655AE\xf1\x890506\xf1\x82\x1316170411110411--04041704171711152S1411', b'\xf1\x872Q0959655AF\xf1\x890506\xf1\x82\x1316171111110411--04041711121211152S1413', + b'\xf1\x872Q0959655AQ\xf1\x890511\xf1\x82\x1316170411110411--0404170426261215391421', ], (Ecu.eps, 0x712, None): [ b'\xf1\x877LA909144F \xf1\x897150\xf1\x82\x0532380518A2', b'\xf1\x877LA909144G \xf1\x897160\xf1\x82\x05333A5519A2', - b'\xf1\x877LA909144F \xf1\x897150\xf1\x82\005323A5519A2', + b'\xf1\x877LA909144F \xf1\x897150\xf1\x82\x05323A5519A2', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572R \xf1\x890372', + b'\xf1\x872Q0907572AA\xf1\x890396', ], }, CAR.TROC_MK1: { From 77c9d65a71069d88f1c49e75b82c52febc8edc63 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 18:50:59 -0700 Subject: [PATCH 276/283] thermald: remove offroad min time condition (#28567) Co-authored-by: Comma Device --- selfdrive/thermald/thermald.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index aab8020818..968196ddf7 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -282,7 +282,6 @@ def thermald_thread(end_event, hw_queue): startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate") startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall") startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version - startup_conditions["offroad_min_time"] = (not started_seen) or ((off_ts is not None) and (sec_since_boot() - off_ts) > 5.) # with 2% left, we killall, otherwise the phone will take a long time to boot startup_conditions["free_space"] = msg.deviceState.freeSpacePercent > 2 From 692bfa55c9b066f3ed5adc0c65012c8154308be3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 20:12:24 -0700 Subject: [PATCH 277/283] thermald: adjust offroad danger temp (#28524) --- selfdrive/thermald/thermald.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 968196ddf7..d3d53b7d89 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -48,7 +48,7 @@ THERMAL_BANDS = OrderedDict({ }) # Override to highest thermal band when offroad and above this temp -OFFROAD_DANGER_TEMP = 79.5 +OFFROAD_DANGER_TEMP = 77 prev_offroad_states: Dict[str, Tuple[bool, Optional[str]]] = {} @@ -261,8 +261,8 @@ def thermald_thread(end_event, hw_queue): is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (sec_since_boot() - off_ts > 60 * 5)) if is_offroad_for_5_min and offroad_comp_temp > OFFROAD_DANGER_TEMP: - # If device is offroad we want to cool down before going onroad - # since going onroad increases load and can make temps go over 107 + # if device is offroad and already hot without the extra onroad load, + # we want to cool down first before increasing load thermal_status = ThermalStatus.danger else: current_band = THERMAL_BANDS[thermal_status] From dfbdcbad730fd987e388957f26918041f6066122 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Thu, 15 Jun 2023 20:17:06 -0700 Subject: [PATCH 278/283] [paramsd] Add a hysteresis band for valid checks where applicable (#28546) * add a hysteresis band for the slow offset valid check * add hysteresis to total_ofset and roll valid cases * bugfix: roll is in radians, offsets are in degs * remove defaults * remove kwarg * remove slow offset check while loading params --- selfdrive/locationd/paramsd.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index 7e30b1e3a7..830f0df6e5 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -16,8 +16,11 @@ from system.swaglog import cloudlog MAX_ANGLE_OFFSET_DELTA = 20 * DT_MDL # Max 20 deg/s ROLL_MAX_DELTA = math.radians(20.0) * DT_MDL # 20deg in 1 second is well within curvature limits ROLL_MIN, ROLL_MAX = math.radians(-10), math.radians(10) +ROLL_LOWERED_MAX = math.radians(8) ROLL_STD_MAX = math.radians(1.5) LATERAL_ACC_SENSOR_THRESHOLD = 4.0 +OFFSET_MAX = 10.0 +OFFSET_LOWERED_MAX = 8.0 class ParamsLearner: @@ -102,6 +105,14 @@ class ParamsLearner: self.kf.filter.reset_rewind() +def check_valid_with_hysteresis(current_valid: bool, val: float, threshold: float, lowered_threshold: float): + if current_valid: + current_valid = abs(val) < threshold + else: + current_valid = abs(val) < lowered_threshold + return current_valid + + def main(sm=None, pm=None): config_realtime_process([0, 1, 2, 3], 5) @@ -130,10 +141,8 @@ def main(sm=None, pm=None): # Check if starting values are sane if params is not None: try: - angle_offset_sane = abs(params.get('angleOffsetAverageDeg')) < 10.0 steer_ratio_sane = min_sr <= params['steerRatio'] <= max_sr - params_sane = angle_offset_sane and steer_ratio_sane - if not params_sane: + if not steer_ratio_sane: cloudlog.info(f"Invalid starting values found {params}") params = None except Exception as e: @@ -157,6 +166,9 @@ def main(sm=None, pm=None): angle_offset_average = params['angleOffsetAverageDeg'] angle_offset = angle_offset_average roll = 0.0 + avg_offset_valid = True + total_offset_valid = True + roll_valid = True while True: sm.update() @@ -180,6 +192,9 @@ def main(sm=None, pm=None): roll_std = float(P[States.ROAD_ROLL]) # Account for the opposite signs of the yaw rates sensors_valid = bool(abs(learner.speed * (x[States.YAW_RATE] + learner.yaw_rate)) < LATERAL_ACC_SENSOR_THRESHOLD) + avg_offset_valid = check_valid_with_hysteresis(avg_offset_valid, angle_offset_average, OFFSET_MAX, OFFSET_LOWERED_MAX) + total_offset_valid = check_valid_with_hysteresis(total_offset_valid, angle_offset, OFFSET_MAX, OFFSET_LOWERED_MAX) + roll_valid = check_valid_with_hysteresis(roll_valid, roll, ROLL_MAX, ROLL_LOWERED_MAX) msg = messaging.new_message('liveParameters') @@ -192,9 +207,9 @@ def main(sm=None, pm=None): liveParameters.angleOffsetAverageDeg = angle_offset_average liveParameters.angleOffsetDeg = angle_offset liveParameters.valid = all(( - abs(liveParameters.angleOffsetAverageDeg) < 10.0, - abs(liveParameters.angleOffsetDeg) < 10.0, - abs(liveParameters.roll) < ROLL_MAX, + avg_offset_valid, + total_offset_valid, + roll_valid, roll_std < ROLL_STD_MAX, 0.2 <= liveParameters.stiffnessFactor <= 5.0, min_sr <= liveParameters.steerRatio <= max_sr, From f375289aa7d981f96cd218f34da2197cd104d65a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 20:20:32 -0700 Subject: [PATCH 279/283] update release notes --- RELEASES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 482e959d9b..50ae2714ea 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -Version 0.9.3 (2023-06-XX) +Version 0.9.3 (2023-06-20) ======================== * New driving model * New driving personality setting @@ -6,6 +6,8 @@ Version 0.9.3 (2023-06-XX) * Standard is recommended and the default * In aggressive mode lead follow distance is shorter and quicker gas/brake response * In relaxed mode lead follow distance is longer +* Improved fuzzy fingerprinting for Hyundai, Kia, and Genesis +* Improved thermal management logic Version 0.9.2 (2023-05-22) ======================== From 90c0edcd6ade4405aa4e4c685c8b4e4700c0990c Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 15 Jun 2023 20:29:50 -0700 Subject: [PATCH 280/283] update release notes --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 50ae2714ea..fb0a46053b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,8 @@ Version 0.9.3 (2023-06-20) ======================== * New driving model + * Improved height estimation and added height tracking in liveCalibration + * Model inputs refactor * New driving personality setting * Three settings: aggressive, standard, and relaxed * Standard is recommended and the default From 354b5be9c38b142dd06f457db6c299d7cf2a4276 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Thu, 15 Jun 2023 22:50:21 -0500 Subject: [PATCH 281/283] Mazda: Fix BSM detection with blinkers (#27919) * Mazda: Fix BSM detection Submitted-by: Samuel Signed-off-by: Jafar Al-Gharaibeh * bump opendbc * use new signals --------- Signed-off-by: Jafar Al-Gharaibeh Co-authored-by: Shane Smiskol --- opendbc | 2 +- selfdrive/car/mazda/carstate.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opendbc b/opendbc index 87b821e0e5..d03ae519e9 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 87b821e0e5cfead12b0f01c16d6a87b592859cb2 +Subproject commit d03ae519e9bcc516e127593a4274b4212c70b732 diff --git a/selfdrive/car/mazda/carstate.py b/selfdrive/car/mazda/carstate.py index 944d79809b..af88308954 100644 --- a/selfdrive/car/mazda/carstate.py +++ b/selfdrive/car/mazda/carstate.py @@ -38,8 +38,8 @@ class CarState(CarStateBase): ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) ret.genericToggle = bool(cp.vl["BLINK_INFO"]["HIGH_BEAMS"]) - ret.leftBlindspot = cp.vl["BSM"]["LEFT_BS1"] == 1 - ret.rightBlindspot = cp.vl["BSM"]["RIGHT_BS1"] == 1 + ret.leftBlindspot = cp.vl["BSM"]["LEFT_BS_STATUS"] != 0 + ret.rightBlindspot = cp.vl["BSM"]["RIGHT_BS_STATUS"] != 0 ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(40, cp.vl["BLINK_INFO"]["LEFT_BLINK"] == 1, cp.vl["BLINK_INFO"]["RIGHT_BLINK"] == 1) @@ -151,8 +151,8 @@ class CarState(CarStateBase): ("PEDAL_GAS", "ENGINE_DATA"), ("SPEED", "ENGINE_DATA"), ("CTR", "CRZ_BTNS"), - ("LEFT_BS1", "BSM"), - ("RIGHT_BS1", "BSM"), + ("LEFT_BS_STATUS", "BSM"), + ("RIGHT_BS_STATUS", "BSM"), ] checks += [ From 51d71c0182e26197635129c078db137153230302 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 21:23:43 -0700 Subject: [PATCH 282/283] more release notes --- RELEASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index fb0a46053b..8e5deddd7e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,8 +6,8 @@ Version 0.9.3 (2023-06-20) * New driving personality setting * Three settings: aggressive, standard, and relaxed * Standard is recommended and the default - * In aggressive mode lead follow distance is shorter and quicker gas/brake response - * In relaxed mode lead follow distance is longer + * In aggressive mode, lead follow distance is shorter and acceleration response is quicker + * In relaxed mode, lead follow distance is longer * Improved fuzzy fingerprinting for Hyundai, Kia, and Genesis * Improved thermal management logic From 8704c1ff952b5c85a44f50143bbd1a4f7b4887e2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Jun 2023 22:05:44 -0700 Subject: [PATCH 283/283] logmessaged: handle interrupted rollover (#28572) --- system/logmessaged.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/system/logmessaged.py b/system/logmessaged.py index 8f24471941..04101d042b 100755 --- a/system/logmessaged.py +++ b/system/logmessaged.py @@ -45,7 +45,12 @@ def main() -> NoReturn: finally: sock.close() ctx.term() - log_handler.close() + + # can hit this if interrupted during a rollover + try: + log_handler.close() + except ValueError: + pass if __name__ == "__main__": main()