From 2749205b4a8d87b18051d3fa8c680b2e9a849a33 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 14 Mar 2023 20:55:41 -0700 Subject: [PATCH 001/143] allow running amp config script standalone (#27587) Co-authored-by: Comma Device --- system/hardware/tici/amplifier.py | 9 +++++++++ 1 file changed, 9 insertions(+) mode change 100644 => 100755 system/hardware/tici/amplifier.py diff --git a/system/hardware/tici/amplifier.py b/system/hardware/tici/amplifier.py old mode 100644 new mode 100755 index 840d575fdf..9725cd689c --- a/system/hardware/tici/amplifier.py +++ b/system/hardware/tici/amplifier.py @@ -129,3 +129,12 @@ class Amplifier: self.set_config(config) self.set_global_shutdown(amp_disabled=False) + + +if __name__ == "__main__": + with open("/sys/firmware/devicetree/base/model") as f: + model = f.read().strip('\x00') + model = model.split('comma ')[-1] + + amp = Amplifier() + amp.initialize_configuration(model) From 5c704827619e774c9877b4598af06d1c6bca80d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 00:02:56 -0700 Subject: [PATCH 002/143] Use structs in laika (#27585) * doesnt crash * New cacher * unused import * help linter * Annotate list * print error * fix caching bugs * wrong name * small fixes * fix sum * wrong brackets * fix tests * update ref * bump submodules --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 84 ++++++++++-------------- selfdrive/locationd/test/test_laikad.py | 57 ++++++++++++---- selfdrive/test/process_replay/ref_commit | 2 +- system/ubloxd/ublox_msg.cc | 66 ++++++++----------- system/ubloxd/ublox_msg.h | 6 +- 7 files changed, 116 insertions(+), 103 deletions(-) diff --git a/cereal b/cereal index 9888e0476c..c579889f39 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 9888e0476c05069d46f273569467e4371b2d8690 +Subproject commit c579889f396cd754048c7b1a51c6f33b1988762a diff --git a/laika_repo b/laika_repo index b740b71c82..b896cdbbd1 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit b740b71c82a748e3520b1599487d9a7aaf728670 +Subproject commit b896cdbbd1e8f85df25a1afa0c9a2ec150b72f92 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2b18dcf152..53fbf36066 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import json import math import os import time @@ -17,7 +16,7 @@ from common.params import Params, put_nonblocking from laika import AstroDog from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed -from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_gps_ephem, convert_ublox_glonass_ephem, parse_qcom_ephem +from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom @@ -51,10 +50,11 @@ class Laikad: self.auto_fetch_navs = auto_fetch_navs self.orbit_fetch_executor: Optional[ProcessPoolExecutor] = None self.orbit_fetch_future: Optional[Future] = None - - self.last_fetch_navs_t = None self.got_first_gnss_msg = False - self.last_cached_t = None + + self.last_report_time = GPSTime(0, 0) + self.last_fetch_navs_t = GPSTime(0, 0) + self.last_cached_t = GPSTime(0, 0) self.save_ephemeris = save_ephemeris self.load_cache() @@ -69,31 +69,34 @@ class Laikad: if not self.save_ephemeris: return - cache = Params().get(EPHEMERIS_CACHE) - if not cache: + cache_bytes = Params().get(EPHEMERIS_CACHE) + if not cache_bytes: return + nav_dict = {} try: - cache = json.loads(cache, object_hook=deserialize_hook) - if cache['version'] == CACHE_VERSION: - self.astro_dog.add_navs(cache['navs']) - self.last_fetch_navs_t = cache['last_fetch_navs_t'] - else: - cache['navs'] = {} - except json.decoder.JSONDecodeError: + ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) + glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] + for e in sum([glonass_navs, gps_navs], []): + if e.prn not in nav_dict: + nav_dict[e.prn] = [] + nav_dict[e.prn].append(e) + self.astro_dog.add_navs(nav_dict) + except Exception: cloudlog.exception("Error parsing cache") - timestamp = self.last_fetch_navs_t.as_datetime() if self.last_fetch_navs_t is not None else 'Nan' cloudlog.debug( - f"Loaded navs ({sum([len(v) for v in cache['navs']])}) cache with timestamp: {timestamp}. Unique orbit and nav sats: {list(cache['navs'].keys())} " + - f"With time range: {[f'{start.as_datetime()}, {end.as_datetime()}' for (start,end) in self.astro_dog.navs_fetched_times._ranges]}") - - def cache_ephemeris(self, t: GPSTime): - if self.save_ephemeris and (self.last_cached_t is None or t - self.last_cached_t > SECS_IN_MIN): - put_nonblocking(EPHEMERIS_CACHE, json.dumps( - {'version': CACHE_VERSION, 'last_fetch_navs_t': self.last_fetch_navs_t, 'navs': self.astro_dog.navs}, - cls=CacheSerializer)) + f"Loaded navs ({sum([len(nav_dict[prn]) for prn in nav_dict.keys()])}). Unique orbit and nav sats: {list(nav_dict.keys())} ") + + def cache_ephemeris(self): + + if self.save_ephemeris and (self.last_report_time - self.last_cached_t > SECS_IN_MIN): + nav_list: List = sum([v for k,v in self.astro_dog.navs.items()], []) + ephem_cache = ephemeris_structs.EphemerisCache(**{'glonassEphemerides': [e.data for e in nav_list if e.prn[0]=='R'], + 'gpsEphemerides': [e.data for e in nav_list if e.prn[0]=='G']}) + put_nonblocking(EPHEMERIS_CACHE, ephem_cache.to_bytes()) cloudlog.debug("Cache saved") - self.last_cached_t = t + self.last_cached_t = self.last_report_time def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: @@ -139,6 +142,7 @@ class Laikad: week = report.gpsWeek tow = report.rcvTow new_meas = read_raw_ublox(report) + self.last_report_time = GPSTime(week, tow) return week, tow, new_meas def is_ephemeris(self, gnss_msg): @@ -155,14 +159,16 @@ class Laikad: ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) else: if gnss_msg.which() == 'ephemeris': - ephem = convert_ublox_gps_ephem(gnss_msg.ephemeris) + data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) + ephem = GPSEphemeris(data_struct) elif gnss_msg.which() == 'glonassEphemeris': - ephem = convert_ublox_glonass_ephem(gnss_msg.glonassEphemeris) + data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) + ephem = GLONASSEphemeris(data_struct) else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return self.astro_dog.add_navs({ephem.prn: [ephem]}) - self.cache_ephemeris(t=ephem.epoch) + self.cache_ephemeris() def process_report(self, new_meas, t): # Filter measurements with unexpected pseudoranges for GPS and GLONASS satellites @@ -272,7 +278,7 @@ class Laikad: def fetch_navs(self, t: GPSTime, block): # Download new navs if 1 hour of navs data left - if t + SECS_IN_HR not in self.astro_dog.navs_fetched_times and (self.last_fetch_navs_t is None or abs(t - self.last_fetch_navs_t) > SECS_IN_MIN): + if t + SECS_IN_HR not in self.astro_dog.navs_fetched_times and (abs(t - self.last_fetch_navs_t) > SECS_IN_MIN): astro_dog_vars = self.astro_dog.valid_const, self.astro_dog.auto_update, self.astro_dog.valid_ephem_types, self.astro_dog.cache_dir ret = None @@ -290,7 +296,7 @@ class Laikad: self.last_fetch_navs_t = ret[2] else: self.astro_dog.navs, self.astro_dog.navs_fetched_times, self.last_fetch_navs_t = ret - self.cache_ephemeris(t=t) + self.cache_ephemeris() def get_orbit_data(t: GPSTime, valid_const, auto_update, valid_ephem_types, cache_dir): @@ -360,26 +366,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) -class CacheSerializer(json.JSONEncoder): - - def default(self, o): - if isinstance(o, Ephemeris): - return o.to_json() - if isinstance(o, GPSTime): - return o.__dict__ - if isinstance(o, np.ndarray): - return o.tolist() - return json.JSONEncoder.default(self, o) - - -def deserialize_hook(dct): - if 'ephemeris' in dct: - return Ephemeris.from_json(dct) - if 'week' in dct: - return GPSTime(dct['week'], dct['tow']) - return dct - - class EphemerisSourceType(IntEnum): nav = 0 nasaUltraRapid = 1 diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 10ac7790b6..be79ff16bc 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -1,21 +1,51 @@ #!/usr/bin/env python3 import time import unittest -from collections import defaultdict +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 common.params import Params from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType, GPSEphemeris +from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime from laika.helpers import ConstellationId, TimeRangeHolder from laika.raw_gnss import GNSSMeasurement, read_raw_ublox from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg 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 + + +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)): @@ -23,7 +53,8 @@ def get_log(segs=range(0)): for i in segs: logs.extend(LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", i))) - all_logs = [m for m in logs if m.which() == 'ubloxGnss'] + raw_logs = [m for m in logs if m.which() == 'ubloxRaw'] + all_logs = get_ublox_gnss(raw_logs)[1] low_gnss = [] for m in all_logs: if m.ubloxGnss.which() != 'measurementReport': @@ -31,7 +62,8 @@ def get_log(segs=range(0)): MAX_MEAS = 7 if m.ubloxGnss.measurementReport.numMeas > MAX_MEAS: - mb = m.as_builder() + mb = log.Event.new_message(ubloxGnss=m.ubloxGnss.to_dict()) + mb.logMonoTime = m.logMonoTime mb.ubloxGnss.measurementReport.numMeas = MAX_MEAS mb.ubloxGnss.measurementReport.measurements = list(m.ubloxGnss.measurementReport.measurements)[:MAX_MEAS] mb.ubloxGnss.measurementReport.measurements[0].pseudorange += 1000 @@ -128,8 +160,8 @@ class TestLaikad(unittest.TestCase): self.assertEqual(laikad.last_fetch_navs_t, real_current_time) def test_ephemeris_source_in_msg(self): - data_mock = defaultdict(str) - data_mock['sv_id'] = 1 + dicto = {'svId': 1} + data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC laikad = Laikad() @@ -151,7 +183,7 @@ class TestLaikad(unittest.TestCase): self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) # Test nav source type - ephem = GPSEphemeris(data_mock, gpstime) + ephem = GPSEphemeris(data_mock) meas = get_measurement_mock(gpstime, ephem) msg = create_measurement_msg(meas) self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) @@ -195,8 +227,8 @@ class TestLaikad(unittest.TestCase): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(255, len(correct_msgs)) - self.assertEqual(255, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(375, len(correct_msgs)) + self.assertEqual(375, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) @@ -241,11 +273,13 @@ class TestLaikad(unittest.TestCase): self.fail("Cache has not been written after 2 seconds") # Test cache with no ephemeris - laikad.cache_ephemeris(t=GPSTime(0, 0)) + laikad.last_report_time = GPSTime(1,0) + laikad.cache_ephemeris() wait_for_cache() Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) + laikad.last_report_time = GPSTime(2,0) laikad.fetch_navs(self.first_gps_time, block=True) # Wait for cache to save @@ -272,6 +306,7 @@ class TestLaikad(unittest.TestCase): # Verify orbit data is not downloaded mock_method.assert_not_called() + def test_low_gnss_meas(self): cnt = 0 laikad = Laikad() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a8896884e1..dae7ceab1a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3c5ebb007f76ba0de710ff7a8cf5910ad2edf22f \ No newline at end of file +b79fa775682401c25aa9ce38b5542b4206d0c56b diff --git a/system/ubloxd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc index 83e64b7ddc..811492ba9b 100644 --- a/system/ubloxd/ublox_msg.cc +++ b/system/ubloxd/ublox_msg.cc @@ -65,22 +65,6 @@ inline bool UbloxMsgParser::valid_so_far() { return true; } -inline uint16_t UbloxMsgParser::get_glonass_year(uint8_t N4, uint16_t Nt) { - // convert time to year (conversion from A3.1.3) - int J = 0; - if (1 <= Nt && Nt <= 366) { - J = 1; - } else if (367 <= Nt && Nt <= 731) { - J = 2; - } else if (732 <= Nt && Nt <= 1096) { - J = 3; - } else if (1097 <= Nt && Nt <= 1461) { - J = 4; - } - uint16_t year = 1996 + 4*(N4 -1) + (J - 1); - return year; -} - bool UbloxMsgParser::add_data(float log_time, const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed) { last_log_time = log_time; int needed = needed_bytes(); @@ -203,6 +187,7 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m int iode_s2 = 0; int iode_s3 = 0; int iodc_lsb = 0; + int week; // Subframe 1 { @@ -210,7 +195,14 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m gps_t subframe(&stream); gps_t::subframe_1_t* subframe_1 = static_cast(subframe.body()); - eph.setGpsWeek(subframe_1->week_no()); + // Each message is incremented to be greater or equal than week 1877 (2015-12-27). + // To skip this use the current_time argument + week = subframe_1->week_no(); + week += 1024; + if (week < 1877) { + week += 1024; + } + //eph.setGpsWeek(subframe_1->week_no()); eph.setTgd(subframe_1->t_gd() * pow(2, -31)); eph.setToc(subframe_1->t_oc() * pow(2, 4)); eph.setAf2(subframe_1->af_2() * pow(2, -55)); @@ -227,6 +219,12 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m gps_t subframe(&stream); gps_t::subframe_2_t* subframe_2 = static_cast(subframe.body()); + // GPS week refers to current week, the ephemeris can be valid for the next + // if toe equals 0, this can be verified by the TOW count if it is within the + // last 2 hours of the week (gps ephemeris valid for 4hours) + if (subframe_2->t_oe() == 0 and subframe.how()->tow_count()*6 >= (SECS_IN_WEEK - 2*SECS_IN_HR)){ + week += 1; + } eph.setCrs(subframe_2->c_rs() * pow(2, -5)); eph.setDeltaN(subframe_2->delta_n() * pow(2, -43) * gpsPi); eph.setM0(subframe_2->m_0() * pow(2, -31) * gpsPi); @@ -256,6 +254,9 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m iode_s3 = subframe_3->iode(); } + eph.setToeWeek(week); + eph.setTocWeek(week); + gps_subframes[msg->sv_id()].clear(); if (iodc_lsb != iode_s2 || iodc_lsb != iode_s3) { // data set cutover, reject ephemeris @@ -329,7 +330,10 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ MessageBuilder msg_builder; auto eph = msg_builder.initEvent().initUbloxGnss().initGlonassEphemeris(); eph.setSvId(msg->sv_id()); + eph.setFreqNum(msg->freq_id() - 7); + uint16_t current_day = 0; + uint16_t tk = 0; // string number 1 { @@ -338,7 +342,8 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ glonass_t::string_1_t* data = static_cast(gl_stream.data()); eph.setP1(data->p1()); - eph.setTk(data->t_k()); + tk = data->t_k(); + eph.setTkDEPRECATED(tk); eph.setXVel(data->x_vel() * pow(2, -20)); eph.setXAccel(data->x_accel() * pow(2, -30)); eph.setX(data->x() * pow(2, -11)); @@ -379,6 +384,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ glonass_t::string_4_t* data = static_cast(gl_stream.data()); current_day = data->n_t(); + eph.setNt(current_day); eph.setTauN(data->tau_n() * pow(2, -30)); eph.setDeltaTauN(data->delta_tau_n() * pow(2, -30)); eph.setAge(data->e_n()); @@ -398,27 +404,9 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string5 parsing is only needed to get the year, this can be removed and // the year can be fetched later in laika (note rollovers and leap year) - uint8_t n_4 = data->n_4(); - uint16_t year = get_glonass_year(n_4, current_day); - if (current_day > 1461) { - // impossible day within last 4 year, reject ephemeris - // TODO: check if this can be detected via hamming code - LOGE("INVALID DATA: current day out of range: %d, %d", current_day, n_4); - glonass_strings[msg->sv_id()].clear(); - return kj::Array(); - } - - uint16_t last_leap_year = 1996 + 4*(n_4-1); - uint16_t days_till_this_year = (year - last_leap_year)*365; - if (days_till_this_year != 0) { - days_till_this_year++; - } - - eph.setYear(year); - eph.setDayInYear(current_day - days_till_this_year); - eph.setHour((eph.getTk()>>7) & 0x1F); - eph.setMinute((eph.getTk()>>1) & 0x3F); - eph.setSecond((eph.getTk() & 0x1) * 30); + eph.setN4(data->n_4()); + int tk_seconds = SECS_IN_HR * ((tk>>7) & 0x1F) + SECS_IN_MIN * ((tk>>1) & 0x3F) + (tk & 0x1) * 30; + eph.setTkSeconds(tk_seconds); } glonass_strings[msg->freq_id()].clear(); diff --git a/system/ubloxd/ublox_msg.h b/system/ubloxd/ublox_msg.h index 06877cc50d..a6e0623aa0 100644 --- a/system/ubloxd/ublox_msg.h +++ b/system/ubloxd/ublox_msg.h @@ -15,6 +15,11 @@ using namespace std::string_literals; +const int SECS_IN_MIN = 60; +const int SECS_IN_HR = 60 * SECS_IN_MIN; +const int SECS_IN_DAY = 24 * SECS_IN_HR; +const int SECS_IN_WEEK = 7 * SECS_IN_DAY; + // protocol constants namespace ublox { const uint8_t PREAMBLE1 = 0xb5; @@ -102,7 +107,6 @@ class UbloxMsgParser { inline bool valid_cheksum(); inline bool valid(); inline bool valid_so_far(); - inline uint16_t get_glonass_year(uint8_t N4, uint16_t Nt); kj::Array parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg); kj::Array parse_glonass_ephemeris(ubx_t::rxm_sfrbx_t *msg); From 153ffa3f68bc316d17b46a94327bdc5777f39b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 01:21:18 -0700 Subject: [PATCH 003/143] Sat info from ublox (#27526) * squashed * bump cereal --- cereal | 2 +- system/ubloxd/generated/ubx.cpp | 136 ++++++++++++++++++++++++++------ system/ubloxd/generated/ubx.h | 94 +++++++++++++++++++--- system/ubloxd/tests/ublox.py | 1 + system/ubloxd/ublox_msg.cc | 18 ++++- system/ubloxd/ublox_msg.h | 1 + system/ubloxd/ubx.ksy | 40 +++++++++- 7 files changed, 253 insertions(+), 39 deletions(-) diff --git a/cereal b/cereal index c579889f39..80a8eb8459 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit c579889f396cd754048c7b1a51c6f33b1988762a +Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 diff --git a/system/ubloxd/generated/ubx.cpp b/system/ubloxd/generated/ubx.cpp index 34fe1e52ca..81b82ccafc 100644 --- a/system/ubloxd/generated/ubx.cpp +++ b/system/ubloxd/generated/ubx.cpp @@ -40,6 +40,11 @@ void ubx_t::_read() { m_body = new rxm_sfrbx_t(m__io, this, m__root); break; } + case 309: { + n_body = false; + m_body = new nav_sat_t(m__io, this, m__root); + break; + } case 2571: { n_body = false; m_body = new mon_hw2_t(m__io, this, m__root); @@ -70,9 +75,9 @@ void ubx_t::_clean_up() { ubx_t::rxm_rawx_t::rxm_rawx_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - m_measurements = 0; - m__raw_measurements = 0; - m__io__raw_measurements = 0; + m_meas = 0; + m__raw_meas = 0; + m__io__raw_meas = 0; try { _read(); @@ -89,15 +94,15 @@ void ubx_t::rxm_rawx_t::_read() { m_num_meas = m__io->read_u1(); m_rec_stat = m__io->read_u1(); m_reserved1 = m__io->read_bytes(3); - m__raw_measurements = new std::vector(); - m__io__raw_measurements = new std::vector(); - m_measurements = new std::vector(); - const int l_measurements = num_meas(); - for (int i = 0; i < l_measurements; i++) { - m__raw_measurements->push_back(m__io->read_bytes(32)); - kaitai::kstream* io__raw_measurements = new kaitai::kstream(m__raw_measurements->at(m__raw_measurements->size() - 1)); - m__io__raw_measurements->push_back(io__raw_measurements); - m_measurements->push_back(new meas_t(io__raw_measurements, this, m__root)); + m__raw_meas = new std::vector(); + m__io__raw_meas = new std::vector(); + m_meas = new std::vector(); + const int l_meas = num_meas(); + for (int i = 0; i < l_meas; i++) { + m__raw_meas->push_back(m__io->read_bytes(32)); + kaitai::kstream* io__raw_meas = new kaitai::kstream(m__raw_meas->at(m__raw_meas->size() - 1)); + m__io__raw_meas->push_back(io__raw_meas); + m_meas->push_back(new measurement_t(io__raw_meas, this, m__root)); } } @@ -106,24 +111,24 @@ ubx_t::rxm_rawx_t::~rxm_rawx_t() { } void ubx_t::rxm_rawx_t::_clean_up() { - if (m__raw_measurements) { - delete m__raw_measurements; m__raw_measurements = 0; + if (m__raw_meas) { + delete m__raw_meas; m__raw_meas = 0; } - if (m__io__raw_measurements) { - for (std::vector::iterator it = m__io__raw_measurements->begin(); it != m__io__raw_measurements->end(); ++it) { + if (m__io__raw_meas) { + for (std::vector::iterator it = m__io__raw_meas->begin(); it != m__io__raw_meas->end(); ++it) { delete *it; } - delete m__io__raw_measurements; m__io__raw_measurements = 0; + delete m__io__raw_meas; m__io__raw_meas = 0; } - if (m_measurements) { - for (std::vector::iterator it = m_measurements->begin(); it != m_measurements->end(); ++it) { + if (m_meas) { + for (std::vector::iterator it = m_meas->begin(); it != m_meas->end(); ++it) { delete *it; } - delete m_measurements; m_measurements = 0; + delete m_meas; m_meas = 0; } } -ubx_t::rxm_rawx_t::meas_t::meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { +ubx_t::rxm_rawx_t::measurement_t::measurement_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; @@ -135,7 +140,7 @@ ubx_t::rxm_rawx_t::meas_t::meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__ } } -void ubx_t::rxm_rawx_t::meas_t::_read() { +void ubx_t::rxm_rawx_t::measurement_t::_read() { m_pr_mes = m__io->read_f8le(); m_cp_mes = m__io->read_f8le(); m_do_mes = m__io->read_f4le(); @@ -152,11 +157,11 @@ void ubx_t::rxm_rawx_t::meas_t::_read() { m_reserved3 = m__io->read_bytes(1); } -ubx_t::rxm_rawx_t::meas_t::~meas_t() { +ubx_t::rxm_rawx_t::measurement_t::~measurement_t() { _clean_up(); } -void ubx_t::rxm_rawx_t::meas_t::_clean_up() { +void ubx_t::rxm_rawx_t::measurement_t::_clean_up() { } ubx_t::rxm_sfrbx_t::rxm_sfrbx_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { @@ -198,6 +203,89 @@ void ubx_t::rxm_sfrbx_t::_clean_up() { } } +ubx_t::nav_sat_t::nav_sat_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_svs = 0; + m__raw_svs = 0; + m__io__raw_svs = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::nav_sat_t::_read() { + m_itow = m__io->read_u4le(); + m_version = m__io->read_u1(); + m_num_svs = m__io->read_u1(); + m_reserved = m__io->read_bytes(2); + m__raw_svs = new std::vector(); + m__io__raw_svs = new std::vector(); + m_svs = new std::vector(); + const int l_svs = num_svs(); + for (int i = 0; i < l_svs; i++) { + m__raw_svs->push_back(m__io->read_bytes(12)); + kaitai::kstream* io__raw_svs = new kaitai::kstream(m__raw_svs->at(m__raw_svs->size() - 1)); + m__io__raw_svs->push_back(io__raw_svs); + m_svs->push_back(new nav_t(io__raw_svs, this, m__root)); + } +} + +ubx_t::nav_sat_t::~nav_sat_t() { + _clean_up(); +} + +void ubx_t::nav_sat_t::_clean_up() { + if (m__raw_svs) { + delete m__raw_svs; m__raw_svs = 0; + } + if (m__io__raw_svs) { + for (std::vector::iterator it = m__io__raw_svs->begin(); it != m__io__raw_svs->end(); ++it) { + delete *it; + } + delete m__io__raw_svs; m__io__raw_svs = 0; + } + if (m_svs) { + for (std::vector::iterator it = m_svs->begin(); it != m_svs->end(); ++it) { + delete *it; + } + delete m_svs; m_svs = 0; + } +} + +ubx_t::nav_sat_t::nav_t::nav_t(kaitai::kstream* p__io, ubx_t::nav_sat_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::nav_sat_t::nav_t::_read() { + m_gnss_id = static_cast(m__io->read_u1()); + m_sv_id = m__io->read_u1(); + m_cno = m__io->read_u1(); + m_elev = m__io->read_s1(); + m_azim = m__io->read_s2le(); + m_pr_res = m__io->read_s2le(); + m_flags = m__io->read_u4le(); +} + +ubx_t::nav_sat_t::nav_t::~nav_t() { + _clean_up(); +} + +void ubx_t::nav_sat_t::nav_t::_clean_up() { +} + ubx_t::nav_pvt_t::nav_pvt_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; diff --git a/system/ubloxd/generated/ubx.h b/system/ubloxd/generated/ubx.h index 6be4ce8c4b..022108489f 100644 --- a/system/ubloxd/generated/ubx.h +++ b/system/ubloxd/generated/ubx.h @@ -16,6 +16,7 @@ class ubx_t : public kaitai::kstruct { public: class rxm_rawx_t; class rxm_sfrbx_t; + class nav_sat_t; class nav_pvt_t; class mon_hw2_t; class mon_hw_t; @@ -42,7 +43,7 @@ public: class rxm_rawx_t : public kaitai::kstruct { public: - class meas_t; + class measurement_t; rxm_rawx_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); @@ -53,18 +54,18 @@ public: public: ~rxm_rawx_t(); - class meas_t : public kaitai::kstruct { + class measurement_t : public kaitai::kstruct { public: - meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent = 0, ubx_t* p__root = 0); + measurement_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent = 0, ubx_t* p__root = 0); private: void _read(); void _clean_up(); public: - ~meas_t(); + ~measurement_t(); private: double m_pr_mes; @@ -110,11 +111,11 @@ public: uint8_t m_num_meas; uint8_t m_rec_stat; std::string m_reserved1; - std::vector* m_measurements; + std::vector* m_meas; ubx_t* m__root; ubx_t* m__parent; - std::vector* m__raw_measurements; - std::vector* m__io__raw_measurements; + std::vector* m__raw_meas; + std::vector* m__io__raw_meas; public: double rcv_tow() const { return m_rcv_tow; } @@ -123,11 +124,11 @@ public: uint8_t num_meas() const { return m_num_meas; } uint8_t rec_stat() const { return m_rec_stat; } std::string reserved1() const { return m_reserved1; } - std::vector* measurements() const { return m_measurements; } + std::vector* meas() const { return m_meas; } ubx_t* _root() const { return m__root; } ubx_t* _parent() const { return m__parent; } - std::vector* _raw_measurements() const { return m__raw_measurements; } - std::vector* _io__raw_measurements() const { return m__io__raw_measurements; } + std::vector* _raw_meas() const { return m__raw_meas; } + std::vector* _io__raw_meas() const { return m__io__raw_meas; } }; class rxm_sfrbx_t : public kaitai::kstruct { @@ -170,6 +171,79 @@ public: ubx_t* _parent() const { return m__parent; } }; + class nav_sat_t : public kaitai::kstruct { + + public: + class nav_t; + + nav_sat_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~nav_sat_t(); + + class nav_t : public kaitai::kstruct { + + public: + + nav_t(kaitai::kstream* p__io, ubx_t::nav_sat_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~nav_t(); + + private: + gnss_type_t m_gnss_id; + uint8_t m_sv_id; + uint8_t m_cno; + int8_t m_elev; + int16_t m_azim; + int16_t m_pr_res; + uint32_t m_flags; + ubx_t* m__root; + ubx_t::nav_sat_t* m__parent; + + public: + gnss_type_t gnss_id() const { return m_gnss_id; } + uint8_t sv_id() const { return m_sv_id; } + uint8_t cno() const { return m_cno; } + int8_t elev() const { return m_elev; } + int16_t azim() const { return m_azim; } + int16_t pr_res() const { return m_pr_res; } + uint32_t flags() const { return m_flags; } + ubx_t* _root() const { return m__root; } + ubx_t::nav_sat_t* _parent() const { return m__parent; } + }; + + private: + uint32_t m_itow; + uint8_t m_version; + uint8_t m_num_svs; + std::string m_reserved; + std::vector* m_svs; + ubx_t* m__root; + ubx_t* m__parent; + std::vector* m__raw_svs; + std::vector* m__io__raw_svs; + + public: + uint32_t itow() const { return m_itow; } + uint8_t version() const { return m_version; } + uint8_t num_svs() const { return m_num_svs; } + std::string reserved() const { return m_reserved; } + std::vector* svs() const { return m_svs; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + std::vector* _raw_svs() const { return m__raw_svs; } + std::vector* _io__raw_svs() const { return m__io__raw_svs; } + }; + class nav_pvt_t : public kaitai::kstruct { public: diff --git a/system/ubloxd/tests/ublox.py b/system/ubloxd/tests/ublox.py index 80abc64e2c..0d271ad785 100644 --- a/system/ubloxd/tests/ublox.py +++ b/system/ubloxd/tests/ublox.py @@ -48,6 +48,7 @@ MSG_NAV_TIMEGPS = 0x20 MSG_NAV_TIMEUTC = 0x21 MSG_NAV_CLOCK = 0x22 MSG_NAV_SVINFO = 0x30 +MSG_NAV_SAT = 0x35 MSG_NAV_AOPSTATUS = 0x60 MSG_NAV_DGPS = 0x31 MSG_NAV_DOP = 0x04 diff --git a/system/ubloxd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc index 811492ba9b..a01187d560 100644 --- a/system/ubloxd/ublox_msg.cc +++ b/system/ubloxd/ublox_msg.cc @@ -434,7 +434,7 @@ kj::Array UbloxMsgParser::gen_rxm_rawx(ubx_t::rxm_rawx_t *msg) { mr.setGpsWeek(msg->week()); auto mb = mr.initMeasurements(msg->num_meas()); - auto measurements = *msg->measurements(); + auto measurements = *msg->meas(); for(int8_t i = 0; i < msg->num_meas(); i++) { mb[i].setSvId(measurements[i]->sv_id()); mb[i].setPseudorange(measurements[i]->pr_mes()); @@ -463,6 +463,22 @@ kj::Array UbloxMsgParser::gen_rxm_rawx(ubx_t::rxm_rawx_t *msg) { return capnp::messageToFlatArray(msg_builder); } +kj::Array UbloxMsgParser::gen_nav_sat(ubx_t::nav_sat_t *msg) { + MessageBuilder msg_builder; + auto sr = msg_builder.initEvent().initUbloxGnss().initSatReport(); + sr.setITow(msg->itow()); + + auto svs = sr.initSvs(msg->num_svs()); + auto svs_data = *msg->svs(); + for(int8_t i = 0; i < msg->num_svs(); i++) { + svs[i].setSvId(svs_data[i]->sv_id()); + svs[i].setGnssId(svs_data[i]->gnss_id()); + svs[i].setFlagsBitfield(svs_data[i]->flags()); + } + + return capnp::messageToFlatArray(msg_builder); +} + kj::Array UbloxMsgParser::gen_mon_hw(ubx_t::mon_hw_t *msg) { MessageBuilder msg_builder; auto hwStatus = msg_builder.initEvent().initUbloxGnss().initHwStatus(); diff --git a/system/ubloxd/ublox_msg.h b/system/ubloxd/ublox_msg.h index a6e0623aa0..a52a7db3e5 100644 --- a/system/ubloxd/ublox_msg.h +++ b/system/ubloxd/ublox_msg.h @@ -102,6 +102,7 @@ class UbloxMsgParser { kj::Array gen_rxm_rawx(ubx_t::rxm_rawx_t *msg); kj::Array gen_mon_hw(ubx_t::mon_hw_t *msg); kj::Array gen_mon_hw2(ubx_t::mon_hw2_t *msg); + kj::Array gen_nav_sat(ubx_t::nav_sat_t *msg); private: inline bool valid_cheksum(); diff --git a/system/ubloxd/ubx.ksy b/system/ubloxd/ubx.ksy index 6945680d32..02c757fe71 100644 --- a/system/ubloxd/ubx.ksy +++ b/system/ubloxd/ubx.ksy @@ -17,6 +17,7 @@ seq: 0x0215: rxm_rawx 0x0a09: mon_hw 0x0a0b: mon_hw2 + 0x0135: nav_sat instances: checksum: pos: length + 6 @@ -142,13 +143,13 @@ types: type: u1 - id: reserved1 size: 3 - - id: measurements - type: meas + - id: meas + type: measurement size: 32 repeat: expr repeat-expr: num_meas types: - meas: + measurement: seq: - id: pr_mes type: f8 @@ -179,6 +180,39 @@ types: type: u1 - id: reserved3 size: 1 + nav_sat: + seq: + - id: itow + type: u4 + - id: version + type: u1 + - id: num_svs + type: u1 + - id: reserved + size: 2 + - id: svs + type: nav + size: 12 + repeat: expr + repeat-expr: num_svs + types: + nav: + seq: + - id: gnss_id + type: u1 + enum: gnss_type + - id: sv_id + type: u1 + - id: cno + type: u1 + - id: elev + type: s1 + - id: azim + type: s2 + - id: pr_res + type: s2 + - id: flags + type: u4 nav_pvt: seq: From f00c108acb49bb633167dfdfcbdf84461cf59025 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 16 Mar 2023 01:54:22 +0800 Subject: [PATCH 004/143] cabana: eliminate deep copy of events in live stream mode (#27588) --- tools/cabana/chartswidget.cc | 23 +++++------- tools/cabana/chartswidget.h | 2 +- tools/cabana/streams/abstractstream.h | 2 +- tools/cabana/streams/livestream.cc | 51 ++++++++++----------------- tools/cabana/streams/livestream.h | 24 +++++++++---- 5 files changed, 45 insertions(+), 57 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 184d41ca0b..61afb871ae 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -108,14 +108,14 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { void ChartsWidget::eventsMerged() { { - assert(!can->liveStreaming()); QFutureSynchronizer future_synchronizer; - const auto events = can->events(); for (auto c : charts) { - future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr, events, true)); + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr)); } } - updateState(); + if (can->isPaused()) { + updateState(); + } } void ChartsWidget::zoomIn(double min, double max) { @@ -133,20 +133,13 @@ void ChartsWidget::zoomReset() { void ChartsWidget::updateState() { if (charts.isEmpty()) return; - const auto events = can->events(); - if (can->liveStreaming()) { - // appends incoming events to the end of series - for (auto c : charts) { - c->updateSeries(nullptr, events, false); - } - } - const double cur_sec = can->currentSec(); if (!is_zoomed) { double pos = (cur_sec - display_range.first) / std::max(1.0, (display_range.second - display_range.first)); if (pos < 0 || pos > 0.8) { display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1); } + auto events = can->events(); double max_event_sec = events->empty() ? 0 : (events->back()->mono_time / 1e9 - can->routeStartTime()); double max_sec = std::min(std::floor(display_range.first + max_chart_range), max_event_sec); display_range.first = std::max(0.0, max_sec - max_chart_range); @@ -502,11 +495,11 @@ void ChartView::updateSeriesPoints() { } } -void ChartView::updateSeries(const cabana::Signal *sig, const std::vector *events, bool clear) { - events = events ? events : can->events(); +void ChartView::updateSeries(const cabana::Signal *sig) { + const auto events = can->events(); for (auto &s : sigs) { if (!sig || s.sig == sig) { - if (clear) { + if (!can->liveStreaming()) { s.vals.clear(); s.step_vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index bdc924ff83..c7470a6f12 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -32,7 +32,7 @@ public: ChartView(QWidget *parent = nullptr); void addSeries(const MessageId &msg_id, const cabana::Signal *sig); bool hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const; - void updateSeries(const cabana::Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); + void updateSeries(const cabana::Signal *sig = nullptr); void updatePlot(double cur, double min, double max); void setSeriesType(SeriesType type); void updatePlotArea(int left); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index de7c394303..d1cf9d8037 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -59,7 +59,7 @@ public: QSet sources; protected: - void process(QHash *); + virtual void process(QHash *); bool updateEvent(const Event *event); void updateLastMsgsTo(double sec); diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 592d883c4c..256cfc5a3e 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -1,10 +1,8 @@ #include "tools/cabana/streams/livestream.h" -LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), AbstractStream(parent, true) { - timer = new QTimer(this); - timer->callOnTimeout(this, &LiveStream::removeExpiredEvents); - timer->start(3 * 1000); +#include +LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), AbstractStream(parent, true) { stream_thread = new QThread(this); QObject::connect(stream_thread, &QThread::started, [=]() { streamThread(); }); QObject::connect(stream_thread, &QThread::finished, stream_thread, &QThread::deleteLater); @@ -15,8 +13,6 @@ LiveStream::~LiveStream() { stream_thread->requestInterruption(); stream_thread->quit(); stream_thread->wait(); - for (Event *e : can_events) ::delete e; - for (auto m : messages) delete m; } void LiveStream::streamThread() { @@ -35,11 +31,8 @@ void LiveStream::streamThread() { QThread::msleep(50); continue; } - AlignedBuffer *buf = messages.emplace_back(new AlignedBuffer()); - Event *evt = ::new Event(buf->align(msg)); - delete msg; - - handleEvent(evt); + std::lock_guard lk(lock); + handleEvent(messages.emplace_back(msg).event); // TODO: write stream to log file to replay it with cabana --data_dir flag. } } @@ -53,11 +46,10 @@ void LiveStream::handleEvent(Event *evt) { emit streamStarted(); } - std::lock_guard lk(lock); - can_events.push_back(evt); + received.push_back(evt); if (!pause_) { if (speed_ < 1 && last_update_ts > 0) { - auto it = std::upper_bound(can_events.cbegin(), can_events.cend(), current_ts, [](uint64_t ts, auto &e) { + auto it = std::upper_bound(received.cbegin(), received.cend(), current_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); if (it != can_events.cend()) { @@ -73,27 +65,20 @@ void LiveStream::handleEvent(Event *evt) { } } -void LiveStream::removeExpiredEvents() { - std::lock_guard lk(lock); - if (can_events.size() > 0) { - const uint64_t max_ns = settings.max_cached_minutes * 60 * 1e9; - const uint64_t last_ns = can_events.back()->mono_time; - while (!can_events.empty() && (last_ns - can_events.front()->mono_time) > max_ns) { - ::delete can_events.front(); - delete messages.front(); - can_events.pop_front(); - messages.pop_front(); +void LiveStream::process(QHash *last_messages) { + { + std::lock_guard lk(lock); + uint64_t last_ts = can_events.empty() ? 0 : can_events.back()->mono_time; + auto first = std::upper_bound(received.cbegin(), received.cend(), last_ts, [](uint64_t ts, auto &e) { + return ts < e->mono_time; + }); + can_events.insert(can_events.end(), first, received.cend()); + if (speed_ == 1) { + received.clear(); } } -} - -const std::vector *LiveStream::events() const { - std::lock_guard lk(lock); - if (events_vector.capacity() <= can_events.size()) { - events_vector.reserve(can_events.size() * 2); - } - events_vector.assign(can_events.begin(), can_events.end()); - return &events_vector; + emit eventsMerged(); + AbstractStream::process(last_messages); } void LiveStream::pause(bool pause) { diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 43f67ae95f..657d7e407f 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -1,6 +1,5 @@ #pragma once -#include #include "tools/cabana/streams/abstractstream.h" class LiveStream : public AbstractStream { @@ -17,17 +16,29 @@ public: void setSpeed(float speed) override { speed_ = std::min(1.0, speed); } bool isPaused() const override { return pause_; } void pause(bool pause) override; - const std::vector *events() const override; + const std::vector *events() const override { return &can_events; } protected: + void process(QHash *) override; virtual void handleEvent(Event *evt); virtual void streamThread(); - virtual void removeExpiredEvents(); + + struct Msg { + Msg(Message *m) { + event = ::new Event(aligned_buf.align(m)); + delete m; + } + ~Msg() { + ::delete event; + } + Event *event; + AlignedBuffer aligned_buf; + }; mutable std::mutex lock; - mutable std::vector events_vector; - std::deque can_events; - std::deque messages; + std::vector can_events; + std::vector received; + std::deque messages; std::atomic start_ts = 0; std::atomic current_ts = 0; std::atomic speed_ = 1; @@ -36,5 +47,4 @@ protected: const QString zmq_address; QThread *stream_thread; - QTimer *timer; }; From 9a6bcba7416b9e3f4dcf527131f4ca7250bb0f35 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 15 Mar 2023 14:34:33 -0700 Subject: [PATCH 005/143] UI: remove spammy CameraView log --- selfdrive/ui/qt/widgets/cameraview.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 10300da55c..de3b64cffd 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -374,7 +374,6 @@ void CameraWidget::vipcThread() { clearFrames(); auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); if (streams.empty()) { - qWarning() << "VisionIPC connected, but no streams available"; QThread::msleep(100); continue; } From 629e5f6bf21460f1f50d0a56c131440e0ab4f0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 15:16:47 -0700 Subject: [PATCH 006/143] Fix qcom laika caching and test (#27594) --- selfdrive/locationd/laikad.py | 6 +- selfdrive/locationd/test/test_laikad.py | 162 ++++++++++++++---------- 2 files changed, 97 insertions(+), 71 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 53fbf36066..5b12c7a16a 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -94,6 +94,7 @@ class Laikad: nav_list: List = sum([v for k,v in self.astro_dog.navs.items()], []) ephem_cache = ephemeris_structs.EphemerisCache(**{'glonassEphemerides': [e.data for e in nav_list if e.prn[0]=='R'], 'gpsEphemerides': [e.data for e in nav_list if e.prn[0]=='G']}) + put_nonblocking(EPHEMERIS_CACHE, ephem_cache.to_bytes()) cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time @@ -157,6 +158,8 @@ class Laikad: if self.gps_week is None: return ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) + self.astro_dog.add_orbits({ephem.prn: [ephem]}) + else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) @@ -167,7 +170,7 @@ class Laikad: else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return - self.astro_dog.add_navs({ephem.prn: [ephem]}) + self.astro_dog.add_navs({ephem.prn: [ephem]}) self.cache_ephemeris() def process_report(self, new_meas, t): @@ -421,7 +424,6 @@ def main(sm=None, pm=None, qc=None): if sm.updated[raw_gnss_socket]: gnss_msg = sm[raw_gnss_socket] - msg = process_msg(laikad, gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) if msg is None: # TODO: beautify this, locationd needs a valid message diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index be79ff16bc..b22c9994b7 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -15,7 +15,7 @@ from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime from laika.helpers import ConstellationId, TimeRangeHolder -from laika.raw_gnss import GNSSMeasurement, read_raw_ublox +from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader @@ -70,14 +70,23 @@ def get_log(segs=range(0)): low_gnss.append(mb.as_reader()) else: low_gnss.append(m) - return all_logs, low_gnss +def get_log_qcom(segs=range(0)): + logs = [] + for i in segs: + logs.extend(LogReader(get_url("b0b3cba7abf862d1|2023-03-11--09-40-33", i))) + 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: - msg = laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=True) + if m.which() == 'ubloxGnss': + gnss_msg = m.ubloxGnss + else: + gnss_msg = m.qcomGnss + 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) if return_one_success: @@ -87,10 +96,16 @@ def verify_messages(lr, laikad, return_one_success=False): def get_first_gps_time(logs): for m in logs: - if m.ubloxGnss.which == 'measurementReport': - new_meas = read_raw_ublox(m.ubloxGnss.measurementReport) - if len(new_meas) > 0: - return new_meas[0].recv_time + if m.which() == 'ubloxGnss': + if m.ubloxGnss.which == 'measurementReport': + new_meas = read_raw_ublox(m.ubloxGnss.measurementReport) + if len(new_meas) > 0: + return new_meas[0].recv_time + else: + if m.qcomGnss.which == 'measurementReport': + new_meas = read_raw_qcom(m.qcomGnss.measurementReport) + if len(new_meas) > 0: + return new_meas[0].recv_time def get_measurement_mock(gpstime, sat_ephemeris): @@ -111,6 +126,7 @@ class TestLaikad(unittest.TestCase): logs, low_gnss = get_log(range(1)) cls.logs = logs cls.low_gnss = low_gnss + cls.logs_qcom = get_log_qcom(range(1)) first_gps_time = get_first_gps_time(logs) cls.first_gps_time = first_gps_time @@ -209,12 +225,13 @@ class TestLaikad(unittest.TestCase): self.assertTrue(kf_valid) def test_laika_online_nav_only(self): - laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV) - # Disable fetch_orbits to test NAV only - correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 559 - self.assertEqual(correct_msgs_expected, len(correct_msgs)) - self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV, use_qcom=use_qcom) + # Disable fetch_orbits to test NAV only + correct_msgs = verify_messages(logs, laikad) + correct_msgs_expected = 42 if use_qcom else 559 + self.assertEqual(correct_msgs_expected, len(correct_msgs)) + self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @mock.patch('laika.downloader.download_and_cache_file') def test_laika_offline(self, downloader_mock): @@ -247,65 +264,73 @@ class TestLaikad(unittest.TestCase): print(min(laikad.astro_dog.navs[prn], key=lambda e: e.epoch).epoch.as_datetime()) def test_get_navs_in_process(self): - laikad = Laikad(auto_update=False) - has_navs = False - for m in self.logs: - laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=False) - if laikad.orbit_fetch_future is not None: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if has_navs: - break - self.assertTrue(has_navs) - self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom) + has_navs = False + has_fix = False + for m in logs: + 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: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.orbits.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + if out_msg is not None: + has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): - laikad = Laikad(auto_update=True, save_ephemeris=True) - - def wait_for_cache(): - max_time = 2 - while Params().get(EPHEMERIS_CACHE) is None: - time.sleep(0.1) - max_time -= 0.1 - if max_time < 0: - self.fail("Cache has not been written after 2 seconds") - - # Test cache with no ephemeris - laikad.last_report_time = GPSTime(1,0) - laikad.cache_ephemeris() - wait_for_cache() - Params().remove(EPHEMERIS_CACHE) - - #laikad.astro_dog.get_navs(self.first_gps_time) - laikad.last_report_time = GPSTime(2,0) - laikad.fetch_navs(self.first_gps_time, block=True) - - # Wait for cache to save - wait_for_cache() - - # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True) - # Verify navs are loaded from cache - self.dict_has_values(laikad.astro_dog.navs) - # Verify cache is working for only nav by running a segment - msg = verify_messages(self.logs, laikad, return_one_success=True) - self.assertIsNotNone(msg) - - 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 - laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() - laikad.fetch_navs(self.first_gps_time, block=False) - mock_method.assert_not_called() - - # Verify cache is working for only orbits by running a segment - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) - msg = verify_messages(self.logs, laikad, return_one_success=True) + use_qcom = True + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=True, save_ephemeris=True, use_qcom=use_qcom) + def wait_for_cache(): + max_time = 2 + while Params().get(EPHEMERIS_CACHE) is None: + time.sleep(0.1) + max_time -= 0.1 + if max_time < 0: + self.fail("Cache has not been written after 2 seconds") + + # Test cache with no ephemeris + laikad.last_report_time = GPSTime(1,0) + laikad.cache_ephemeris() + wait_for_cache() + Params().remove(EPHEMERIS_CACHE) + + #laikad.astro_dog.get_navs(self.first_gps_time) + laikad.last_report_time = GPSTime(2,0) + laikad.fetch_navs(self.first_gps_time, block=True) + + # Wait for cache to save + wait_for_cache() + + # Check both nav and orbits separate + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) + # Verify navs are loaded from cache + self.dict_has_values(laikad.astro_dog.navs) + # Verify cache is working for only nav by running a segment + msg = verify_messages(logs, laikad, return_one_success=True) self.assertIsNotNone(msg) - # Verify orbit data is not downloaded - mock_method.assert_not_called() + 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 + laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() + laikad.fetch_navs(self.first_gps_time, block=False) + mock_method.assert_not_called() + + # Verify cache is working for only orbits by running a segment + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) + msg = verify_messages(self.logs, laikad, return_one_success=True) + self.assertIsNotNone(msg) + # Verify orbit data is not downloaded + mock_method.assert_not_called() + break def test_low_gnss_meas(self): cnt = 0 @@ -323,6 +348,5 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) - if __name__ == "__main__": unittest.main() From 896fa029f93501af7871e7e5edced2bc0885d53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 20:06:29 -0700 Subject: [PATCH 007/143] Laikad: cleanup time range holder (#27595) * cleanup time range holder * update * unused import * unused import * unused import * bump laika --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 4 +-- selfdrive/locationd/test/test_laikad.py | 41 +++++++++++++------------ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/laika_repo b/laika_repo index b896cdbbd1..354afd63f7 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit b896cdbbd1e8f85df25a1afa0c9a2ec150b72f92 +Subproject commit 354afd63f74cac63669637e3d5e33d416405c428 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 5b12c7a16a..3f96e4d9f3 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -35,7 +35,7 @@ POS_FIX_RESIDUAL_THRESHOLD = 100.0 class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, - valid_ephem_types=(EphemerisType.NAV,), + valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), save_ephemeris=False, use_qcom=False): """ valid_const: GNSS constellation which can be used @@ -158,7 +158,7 @@ class Laikad: if self.gps_week is None: return ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) - self.astro_dog.add_orbits({ephem.prn: [ephem]}) + self.astro_dog.add_qcom_polys({ephem.prn: [ephem]}) else: if gnss_msg.which() == 'ephemeris': diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index b22c9994b7..2e03551f6e 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -6,7 +6,7 @@ import cereal.messaging as messaging from common.params import Params from datetime import datetime from unittest import mock -from unittest.mock import patch +#from unittest.mock import patch from tqdm import tqdm @@ -14,7 +14,7 @@ from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime -from laika.helpers import ConstellationId, TimeRangeHolder +from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url @@ -261,11 +261,10 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) prn = "R01" self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) - print(min(laikad.astro_dog.navs[prn], key=lambda e: e.epoch).epoch.as_datetime()) def test_get_navs_in_process(self): for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom) + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) has_navs = False has_fix = False for m in logs: @@ -275,14 +274,14 @@ class TestLaikad(unittest.TestCase): laikad.orbit_fetch_future.result() vals = laikad.astro_dog.navs.values() has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.orbits.values() + vals = laikad.astro_dog.qcom_polys.values() has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 if out_msg is not None: has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid - + self.assertTrue(has_navs or has_polys) self.assertTrue(has_fix) - self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): @@ -318,19 +317,22 @@ class TestLaikad(unittest.TestCase): msg = verify_messages(logs, laikad, return_one_success=True) self.assertIsNotNone(msg) - 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 - laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() - laikad.fetch_navs(self.first_gps_time, block=False) - mock_method.assert_not_called() - # Verify cache is working for only orbits by running a segment - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) - msg = verify_messages(self.logs, laikad, return_one_success=True) - self.assertIsNotNone(msg) - # Verify orbit data is not downloaded - mock_method.assert_not_called() - break + + #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 + # laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() + # laikad.fetch_navs(self.first_gps_time, block=False) + # mock_method.assert_not_called() + + # # Verify cache is working for only orbits by running a segment + # laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) + # msg = verify_messages(self.logs, laikad, return_one_success=True) + # self.assertIsNotNone(msg) + # # Verify orbit data is not downloaded + # mock_method.assert_not_called() + #break def test_low_gnss_meas(self): cnt = 0 @@ -348,5 +350,6 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) + if __name__ == "__main__": unittest.main() From 38cb42f76aa9fe21b0e71569934864d578499c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 20:26:19 -0700 Subject: [PATCH 008/143] LaikaD new cache version (#27596) --- common/params.cc | 2 +- selfdrive/locationd/laikad.py | 2 +- system/loggerd/tests/test_loggerd.py | 8 ++++---- tools/gpstest/rpc_server.py | 2 +- tools/gpstest/test_laikad.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/params.cc b/common/params.cc index e74c63bf6a..e71f802d61 100644 --- a/common/params.cc +++ b/common/params.cc @@ -137,7 +137,7 @@ std::unordered_map keys = { {"IsReleaseBranch", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, - {"LaikadEphemerisV2", PERSISTENT | DONT_LOG}, + {"LaikadEphemerisV3", PERSISTENT | DONT_LOG}, {"LanguageSetting", PERSISTENT}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastGPSPosition", PERSISTENT}, diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 3f96e4d9f3..f43e68ceba 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -27,7 +27,7 @@ from selfdrive.locationd.models.gnss_kf import States as GStates from system.swaglog import cloudlog MAX_TIME_GAP = 10 -EPHEMERIS_CACHE = 'LaikadEphemerisV2' +EPHEMERIS_CACHE = 'LaikadEphemerisV3' DOWNLOADS_CACHE_FOLDER = "/tmp/comma_download_cache/" CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index 54098d13d0..f39b8bb9d6 100755 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -86,7 +86,7 @@ class TestLoggerd(unittest.TestCase): params.clear_all() for k, _, v in fake_params: params.put(k, v) - params.put("LaikadEphemerisV2", "abc") + params.put("LaikadEphemerisV3", "abc") lr = list(LogReader(str(self._gen_bootlog()))) initData = lr[0].initData @@ -103,14 +103,14 @@ class TestLoggerd(unittest.TestCase): # check params logged_params = {entry.key: entry.value for entry in initData.params.entries} - expected_params = set(k for k, _, __ in fake_params) | {'LaikadEphemerisV2'} + expected_params = set(k for k, _, __ in fake_params) | {'LaikadEphemerisV3'} assert set(logged_params.keys()) == expected_params, set(logged_params.keys()) ^ expected_params - assert logged_params['LaikadEphemerisV2'] == b'', f"DONT_LOG param value was logged: {repr(logged_params['LaikadEphemerisV2'])}" + assert logged_params['LaikadEphemerisV3'] == b'', f"DONT_LOG param value was logged: {repr(logged_params['LaikadEphemerisV3'])}" for param_key, initData_key, v in fake_params: self.assertEqual(getattr(initData, initData_key), v) self.assertEqual(logged_params[param_key].decode(), v) - params.put("LaikadEphemerisV2", "") + params.put("LaikadEphemerisV3", "") def test_rotation(self): os.environ["LOGGERD_TEST"] = "1" diff --git a/tools/gpstest/rpc_server.py b/tools/gpstest/rpc_server.py index a368566982..178e8b2c3c 100644 --- a/tools/gpstest/rpc_server.py +++ b/tools/gpstest/rpc_server.py @@ -17,7 +17,7 @@ ALT_DELTA = 30 MATCH_NUM = 10 REPORT_STATS = 10 -EPHEM_CACHE = "/data/params/d/LaikadEphemerisV2" +EPHEM_CACHE = "/data/params/d/LaikadEphemerisV3" DOWNLOAD_CACHE = "/tmp/comma_download_cache" SERVER_LOG_FILE = "/tmp/fuzzy_server.log" diff --git a/tools/gpstest/test_laikad.py b/tools/gpstest/test_laikad.py index 24ffa6c424..689b0f0b9f 100644 --- a/tools/gpstest/test_laikad.py +++ b/tools/gpstest/test_laikad.py @@ -39,7 +39,7 @@ class TestLaikad(unittest.TestCase): def setUp(self): # ensure laikad cold start - Params().remove("LaikadEphemerisV2") + Params().remove("LaikadEphemerisV3") os.environ["LAIKAD_NO_INTERNET"] = "1" managed_processes['laikad'].start() From 57d10a26e7f60e96134c7741716b5c6892f78fda Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 16 Mar 2023 03:58:08 +0000 Subject: [PATCH 009/143] fix tabulate types (#27598) fix types for tabulate --- poetry.lock | 11 +++++------ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index ec4022c81f..521bf3c0c3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4357,9 +4357,9 @@ types-urllib3 = "<1.27" [[package]] name = "types-tabulate" -version = "0.9.0.1" +version = "0.8.11" description = "Typing stubs for tabulate" -category = "main" +category = "dev" optional = false python-versions = "*" @@ -4575,7 +4575,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "669485055bf8d77336509cb7a3878e06aa32431c520825948914d76b57347fde" +content-hash = "043d4bffddfddc2a5d6d20f51662a9992754831b387eb7e318c2420f3240049e" [metadata.files] adal = [ @@ -5618,7 +5618,6 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, - {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -8059,8 +8058,8 @@ types-requests = [ {file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"}, ] types-tabulate = [ - {file = "types-tabulate-0.9.0.1.tar.gz", hash = "sha256:e486292c279f19247865bdabe802419740a0e74b53444e7f7a8009e08129da5d"}, - {file = "types_tabulate-0.9.0.1-py3-none-any.whl", hash = "sha256:be2ea0de05f615ccfcbadf6206aa720e265955eb1de23e343aec9d8bf3fa9aaa"}, + {file = "types-tabulate-0.8.11.tar.gz", hash = "sha256:17a5fa3b5ca453815778fc9865e8ecd0118b07b2b9faff3e2b06fe448174dd5e"}, + {file = "types_tabulate-0.8.11-py3-none-any.whl", hash = "sha256:af811268241e8fb87b63c052c87d1e329898a93191309d5d42111372232b2e0e"}, ] types-urllib3 = [ {file = "types-urllib3-1.26.25.1.tar.gz", hash = "sha256:a948584944b2412c9a74b9cf64f6c48caf8652cb88b38361316f6d15d8a184cd"}, diff --git a/pyproject.toml b/pyproject.toml index b1ad273cd7..c53dcb5381 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,6 @@ urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" polyline = "^1.4.0" -types-tabulate = "^0.9.0.1" [tool.poetry.group.dev.dependencies] @@ -108,6 +107,7 @@ types-certifi = "^2021.10.8" types-pycurl = "^7.45.1" types-PyYAML = "^6.0" types-requests = "^2.28.11" +types-tabulate = "^0.8.10" [tool.poetry.group.xx] From d26d8b3ba9787dc02b9c116d7e750a3b36dd0846 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Thu, 16 Mar 2023 10:59:27 +0100 Subject: [PATCH 010/143] Improve OX frame timing jitter (#27582) * frame timing script * enable vsync output and improve fsin tracking * increase measurement time * fix python linting --------- Co-authored-by: Comma Device --- .../debug/internal/check_frame_frequencies.py | 43 +++++++++++++++++++ system/camerad/cameras/sensor2_i2c.h | 9 ++-- 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100755 selfdrive/debug/internal/check_frame_frequencies.py diff --git a/selfdrive/debug/internal/check_frame_frequencies.py b/selfdrive/debug/internal/check_frame_frequencies.py new file mode 100755 index 0000000000..9ac8bfc80e --- /dev/null +++ b/selfdrive/debug/internal/check_frame_frequencies.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import time +import statistics +import cereal.messaging as messaging + +from typing import Dict + +camera_states = [ + 'roadCameraState', + 'wideRoadCameraState', + 'driverCameraState' +] + +def fmt(val): + ref = 0.05 + return f"{val:.6f} ({100 * val / ref:.2f}%)" + +if __name__ == "__main__": + sm = messaging.SubMaster(camera_states) + + prev_sof = {state: None for state in camera_states} + diffs: Dict[str, list] = {state: [] for state in camera_states} + + st = time.monotonic() + while True: + sm.update() + + for state in camera_states: + if sm.updated[state]: + if prev_sof[state] is not None: + diffs[state].append((sm[state].timestampSof - prev_sof[state]) / 1e9) + prev_sof[state] = sm[state].timestampSof + + if time.monotonic() - st > 10: + for state in camera_states: + values = diffs[state] + ref = 0.05 + print(f"{state} \tMean: {fmt(statistics.mean(values))} \t Min: {fmt(min(values))} \t Max: {fmt(max(values))} \t Std: {statistics.stdev(values):.6f} \t Num frames: {len(values)}") + diffs[state] = [] + + print() + st = time.monotonic() diff --git a/system/camerad/cameras/sensor2_i2c.h b/system/camerad/cameras/sensor2_i2c.h index 83fcb8f7a9..4db4bfd4d8 100644 --- a/system/camerad/cameras/sensor2_i2c.h +++ b/system/camerad/cameras/sensor2_i2c.h @@ -58,7 +58,7 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { // SC ctrl {0x3001, 0x03}, // io_pad_oen - {0x3002, 0xf8}, // io_pad_oen + {0x3002, 0xfc}, // io_pad_oen {0x3005, 0x80}, // io_pad_out {0x3007, 0x01}, // io_pad_sel {0x3008, 0x80}, // io_pad_sel @@ -85,6 +85,9 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { {0x3882, 0x8}, {0x3883, 0x0D}, {0x3836, 0x1F}, {0x3837, 0x40}, + {0x3892, 0x44}, + {0x3823, 0x48}, + {0x3012, 0x41}, // SC_PHY_CTRL = 4 lane MIPI {0x3020, 0x05}, // SC_CTRL_20 @@ -179,8 +182,8 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { {0x3820, 0x04}, {0x3821, 0x19}, - {0x3832, 0x00}, - {0x3834, 0x00}, + {0x3832, 0xF0}, + {0x3834, 0xF0}, {0x384c, 0x02}, {0x384d, 0x0d}, {0x3850, 0x00}, From c2ec18cb715766a7d83276f13cf26f1a86283f78 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 16 Mar 2023 10:43:22 -0700 Subject: [PATCH 011/143] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index b231281c8b..c0aea3273a 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit b231281c8b2c79c46892576dee4c8a56d5e0b2d2 +Subproject commit c0aea3273a82a91f10554b1b3317727da99f4564 From 719901b57c1b21183c6208fa8142c56c7a18c61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 13:06:30 -0700 Subject: [PATCH 012/143] Bump laika (#27605) * bump laika * Update ref_commit --- laika_repo | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/laika_repo b/laika_repo index 354afd63f7..8463fe8fed 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 354afd63f74cac63669637e3d5e33d416405c428 +Subproject commit 8463fe8fed272f58093406a990532084bc060359 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dae7ceab1a..50288bfd03 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -b79fa775682401c25aa9ce38b5542b4206d0c56b +c8ba9450af16f9efc70eb76a5edc205aed53e779 From e6c514eb72f0c87186c637c8bbd9f19eabcaa140 Mon Sep 17 00:00:00 2001 From: kevinsdev <37430136+kevinsdev@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:24:22 -0700 Subject: [PATCH 013/143] Added firmware for 2021 Lexus NX Base (#27604) * Update values.py Added my 2021 Lexus NX 300 Base * Update values.py Added 2021 Lexus NX Base --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index a8e143e80a..bd2228c3df 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1729,6 +1729,7 @@ FW_VERSIONS = { b'\x018966378B2100\x00\x00\x00\x00', b'\x018966378B3000\x00\x00\x00\x00', b'\x018966378B4100\x00\x00\x00\x00', + b'\x018966378G2000\x00\x00\x00\x00', b'\x018966378G3000\x00\x00\x00\x00', b'\x018966378B2000\x00\x00\x00\x00', ], From 5c383927859a20feccdccaf0102f8d0924d28134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 13:29:02 -0700 Subject: [PATCH 014/143] Laikad: always return msg (#27599) * always return msg * always return msg * Not all qcom constellations are understood * call error error --- selfdrive/locationd/laikad.py | 38 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index f43e68ceba..fe5126522c 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -125,8 +125,15 @@ 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 support GLONASS - return constellation_id in [ConstellationId.GPS, ConstellationId.SBAS] + # TODO: Understand and use remaining unknown constellations + try: + good_constellation = constellation_id in [ConstellationId.GPS, ConstellationId.SBAS] + except NotImplementedError: + good_constellation = False + # gpsWeek 65535 is received rarely from quectel, this cannot be + # passed to GnssMeasurements's gpsWeek (Int16) + good_week = not getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max + return good_constellation and good_week elif gnss_msg.which() == 'measurementReport' and not self.use_qcom: return True else: @@ -196,15 +203,15 @@ class Laikad: return position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, processed_measurements def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): + out_msg = messaging.new_message("gnssMeasurements") if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) - return None + return out_msg elif self.is_good_report(gnss_msg): - week, tow, new_meas = self.read_report(gnss_msg) self.gps_week = week if len(new_meas) == 0: - return None + return out_msg t = gnss_mono_time * 1e-9 if week > 0: @@ -215,17 +222,16 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: - return None + return out_msg position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) meas_msgs = [create_measurement_msg(m) for m in corrected_measurements] - msg = messaging.new_message("gnssMeasurements") measurement_msg = log.LiveLocationKalman.Measurement.new_message P_diag = self.gnss_kf.P.diagonal() kf_valid = all(self.kf_valid(t)) - msg.gnssMeasurements = { + out_msg.gnssMeasurements = { "gpsWeek": week, "gpsTimeOfWeek": tow, "kalmanPositionECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), @@ -240,7 +246,7 @@ class Laikad: "measTime": gnss_mono_time, "correctedMeasurements": meas_msgs } - return msg + return out_msg #elif gnss_msg.which() == 'ionoData': # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. @@ -377,15 +383,6 @@ class EphemerisSourceType(IntEnum): def process_msg(laikad, gnss_msg, mono_time, block=False): - # TODO: Understand and use remaining unknown constellations - if gnss_msg.which() == "drMeasurementReport": - if getattr(gnss_msg, gnss_msg.which()).source not in ['glonass', 'gps', 'beidou', 'sbas']: - return None - - if getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max: - # gpsWeek 65535 is received rarely from quectel, this cannot be - # passed to GnssMeasurements's gpsWeek (Int16) - return None return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) @@ -424,10 +421,7 @@ def main(sm=None, pm=None, qc=None): if sm.updated[raw_gnss_socket]: gnss_msg = sm[raw_gnss_socket] - msg = process_msg(laikad, gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) - if msg is None: - # TODO: beautify this, locationd needs a valid message - msg = messaging.new_message("gnssMeasurements") + msg = laikad.process_gnss_msg(gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) pm.send('gnssMeasurements', msg) if not laikad.got_first_gnss_msg and sm.updated['clocks']: From a11a5d6231c5d7e677dbd5d13a1ad3b0c21608bc Mon Sep 17 00:00:00 2001 From: freddiebd Date: Thu, 16 Mar 2023 20:34:52 +0000 Subject: [PATCH 015/143] VW MQB: Add FW for 2016 Golf Mk7 (#27581) --- 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 694b4006f8..2b853f9d7d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -394,6 +394,7 @@ FW_VERSIONS = { b'\xf1\x8704L906021DT\xf1\x895520', b'\xf1\x8704L906021DT\xf1\x898127', b'\xf1\x8704L906021N \xf1\x895518', + b'\xf1\x8704L906026BN\xf1\x891197', b'\xf1\x8704L906026BP\xf1\x897608', b'\xf1\x8704L906026NF\xf1\x899528', b'\xf1\x8704L906056CL\xf1\x893823', @@ -514,6 +515,7 @@ FW_VERSIONS = { b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\x0511A00403A0', b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\x0516A00604A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A00404A1', + 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\x0521A00507A1', From d5dfd3f1a69772c68a24a9069c50cc7fdb7b793c Mon Sep 17 00:00:00 2001 From: klaw73 <127580531+klaw73@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:38:02 -0400 Subject: [PATCH 016/143] Add missing FW for 2020 Lexus NX Hybrid (#27565) * Added fw for 2020LexusNXH * Added fw for 2020LexusNXH * Add fw to 2020Lexus NXH --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index bd2228c3df..326b07075b 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1752,6 +1752,7 @@ FW_VERSIONS = { CAR.LEXUS_NXH_TSS2: { (Ecu.engine, 0x7e0, None): [ b'\x0237887000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02378A0000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'F152678210\x00\x00\x00\x00\x00\x00', @@ -1761,6 +1762,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301400\x00\x00\x00\x00', + b'\x018821F3301300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F78030A0\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', From cb5573cbfd4b674d431be1fef04afe9928b58b83 Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Fri, 17 Mar 2023 05:25:31 +0800 Subject: [PATCH 017/143] VW MQB: Add FW for 2022 Skoda Kodiaq 1.5TSI (#27489) * VW MQB: Add FW for 2022 Skoda Kodiaq 1.5TSI carVin': 'TMBJB9NS3N8051692' * alphabetical order * add to docs --------- Co-authored-by: Cameron Clough Co-authored-by: Shane Smiskol --- 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 2b853f9d7d..5d8c6e13c5 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1075,6 +1075,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026DE\xf1\x895418', b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026HT\xf1\x893617', + b'\xf1\x8705E906018DJ\xf1\x890915', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', ], @@ -1084,6 +1085,7 @@ FW_VERSIONS = { b'\xf1\x870DL300012M \xf1\x892107', b'\xf1\x870DL300012N \xf1\x892110', b'\xf1\x870DL300013G \xf1\x892119', + b'\xf1\x870GC300046Q \xf1\x892802', ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AP\xf1\x890306\xf1\x82\r11110011110011421111314211', @@ -1091,11 +1093,13 @@ FW_VERSIONS = { b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1213001211001244212111442100', b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', + b'\xf1\x873Q0959655DJ\xf1\x890731\xf1\x82\x0e1513001511001205232113052J00', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6050405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6060405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6070405', + b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G500', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G600', ], (Ecu.fwdRadar, 0x757, None): [ From fe358102f2df380c070b3cfaed28cd3c9d2ea91b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 16 Mar 2023 14:31:55 -0700 Subject: [PATCH 018/143] test: fix Honda and Hyundai tests (#27606) test honda and hyundai --- selfdrive/car/honda/tests/__init__.py | 0 selfdrive/car/hyundai/tests/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 selfdrive/car/honda/tests/__init__.py create mode 100644 selfdrive/car/hyundai/tests/__init__.py diff --git a/selfdrive/car/honda/tests/__init__.py b/selfdrive/car/honda/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/car/hyundai/tests/__init__.py b/selfdrive/car/hyundai/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 0d1e272b917b8c1a98453bbe78337a42cd8451fe Mon Sep 17 00:00:00 2001 From: martinl Date: Thu, 16 Mar 2023 23:32:22 +0200 Subject: [PATCH 019/143] Subaru: Add 2019 Forester FPv2 (#27500) * Subaru: Add 2019 Forester FPv2 * Update selfdrive/car/subaru/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/subaru/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 5c7d3f5e4d..9c4447631d 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -273,9 +273,11 @@ FW_VERSIONS = { b'\xa3 \031\024\000', b'\xa3 \x14\x01', b'\xf1\x00\xbb\r\x05', + b'\xa3 \x18&\x00', ], (Ecu.eps, 0x746, None): [ b'\x8d\xc0\x04\x00', + b'\x8d\xc0\x00\x00', ], (Ecu.fwdCamera, 0x787, None): [ b'\x00\x00e!\x1f@ \x11', @@ -292,6 +294,7 @@ FW_VERSIONS = { b'\xcb\"`p\a', b'\xf1\x00\xa2\x10\n', b'\xcf"`p\x07', + b'\xb6\xa2`A\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\032\xf6B0\000', @@ -299,6 +302,7 @@ FW_VERSIONS = { b'\032\xf6b`\000', b'\x1a\xf6B`\x00', b'\x1a\xf6b0\x00', + b'\x1a\xe6B1\x00', ], }, CAR.FORESTER_PREGLOBAL: { From 61f25b5b958ec5f9d420fdd1c607d6665e9b48b1 Mon Sep 17 00:00:00 2001 From: Oxygen Date: Fri, 17 Mar 2023 05:48:29 +0800 Subject: [PATCH 020/143] Firmware version for TOYOTA Camry 2.0G, China built 2022.07 (#27558) Update values.py Firmware version for Carmy 2.0G, China Build 2022.07 Co-authored-by: Shane Smiskol --- selfdrive/car/toyota/values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 326b07075b..43f0593325 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -527,14 +527,17 @@ FW_VERSIONS = { CAR.CAMRY_TSS2: { (Ecu.eps, 0x7a1, None): [ b'8965B33630\x00\x00\x00\x00\x00\x00', + b'8965B33640\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'\x01F152606370\x00\x00\x00\x00\x00\x00', b'\x01F152606390\x00\x00\x00\x00\x00\x00', b'\x01F152606400\x00\x00\x00\x00\x00\x00', + b'\x01F152606431\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x018966306Q5000\x00\x00\x00\x00', + b'\x018966306Q9000\x00\x00\x00\x00', b'\x018966306T3100\x00\x00\x00\x00', b'\x018966306T3200\x00\x00\x00\x00', b'\x018966306T4000\x00\x00\x00\x00', @@ -542,11 +545,13 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F6201200\x00\x00\x00\x00', + b'\x018821F6201300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F0602100\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F0602200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', + b'\x028646F3305200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', ], }, From 87f3a658a7f3a52877136f141ef528d0864bf04b Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Fri, 17 Mar 2023 06:03:22 +0800 Subject: [PATCH 021/143] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202022=20?= =?UTF-8?q?=C5=A0koda=20Kodiaq=20(#27602)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @jyoung8607 I try to do this joy better I setup my C3 on this car to get information to merge this FPV2 The route name is 0bbe367c98fa1538|2023-03-16--11-41-19--2 Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 5d8c6e13c5..e63975b0c0 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1075,6 +1075,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026DE\xf1\x895418', b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026HT\xf1\x893617', + b'\xf1\x8783A907115E \xf1\x890001', b'\xf1\x8705E906018DJ\xf1\x890915', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', @@ -1085,6 +1086,7 @@ FW_VERSIONS = { b'\xf1\x870DL300012M \xf1\x892107', b'\xf1\x870DL300012N \xf1\x892110', b'\xf1\x870DL300013G \xf1\x892119', + b'\xf1\x870GC300014N \xf1\x892801', b'\xf1\x870GC300046Q \xf1\x892802', ], (Ecu.srs, 0x715, None): [ @@ -1107,6 +1109,7 @@ FW_VERSIONS = { b'\xf1\x872Q0907572R \xf1\x890372', b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x872Q0907572AA\xf1\x890396', + b'\xf1\x872Q0907572AB\xf1\x890397', ], }, CAR.SKODA_OCTAVIA_MK3: { From 95216de5910c62bf81a7bf6053b5917de98dc825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 17:00:54 -0700 Subject: [PATCH 022/143] LAIKAD: TTFF, and ephemeris statuses in logs (#27591) * ttff in logs * More meta info * cleanup * passess tests * unused import * fix linting * ttff of 0 is invalid * ref commit * bump cereal --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 116 ++++++++++++++--------- selfdrive/locationd/test/test_laikad.py | 95 ++++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 111 insertions(+), 106 deletions(-) diff --git a/cereal b/cereal index 80a8eb8459..7492dc3f45 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 +Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 diff --git a/laika_repo b/laika_repo index 8463fe8fed..719c79a156 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 8463fe8fed272f58093406a990532084bc060359 +Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index fe5126522c..695e9adc03 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime -from laika.helpers import ConstellationId +from laika.helpers import ConstellationId, get_sv_id from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind @@ -33,6 +33,44 @@ CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 +class LogEphemerisType(IntEnum): + nav = 0 + nasaUltraRapid = 1 + glonassIacUltraRapid = 2 + qcom = 3 + +class EphemerisSource(IntEnum): + gnssChip = 0 + internet = 1 + cache = 2 + unknown = 3 + +def get_log_eph_type(ephem): + if ephem.eph_type == EphemerisType.NAV: + source_type = LogEphemerisType.nav + elif ephem.eph_type == EphemerisType.QCOM_POLY: + source_type = LogEphemerisType.qcom + else: + assert ephem.file_epoch is not None + file_src = ephem.file_source + if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' + source_type = LogEphemerisType.nasaUltraRapid + elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' + source_type = LogEphemerisType.glonassIacUltraRapid + else: + raise Exception(f"Didn't expect file source {file_src}") + return source_type + +def get_log_eph_source(ephem): + if ephem.file_name == 'qcom' or ephem.file_name == 'ublox': + source = EphemerisSource.gnssChip + elif ephem.file_name == EPHEMERIS_CACHE: + source = EphemerisSource.cache + else: + source = EphemerisSource.internet + return source + + class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), @@ -64,6 +102,8 @@ class Laikad: self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom + self.first_log_time = None + self.ttff = -1 def load_cache(self): if not self.save_ephemeris: @@ -76,8 +116,8 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] - gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: nav_dict[e.prn] = [] @@ -99,6 +139,21 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time + def create_ephem_statuses(self): + ephemeris_statuses = [] + prns_to_check = self.astro_dog.get_all_ephem_prns() + for prn in prns_to_check: + eph = self.astro_dog.get_eph(prn, self.last_report_time) + if eph is not None: + status = log.GnssMeasurements.EphemerisStatus.new_message() + status.constellationId = ConstellationId.from_rinex_char(prn[0]).value + status.svId = get_sv_id(prn) + status.type = get_log_eph_type(eph).value + status.source = get_log_eph_source(eph).value + ephemeris_statuses.append(status) + return ephemeris_statuses + + def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -170,10 +225,10 @@ class Laikad: else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct) + ephem = GPSEphemeris(data_struct, file_name='ublox') elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct) + ephem = GLONASSEphemeris(data_struct, file_name='ublox') else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return @@ -204,6 +259,12 @@ class Laikad: def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") + out_msg.gnssMeasurements = { + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), + } + if self.first_log_time is None: + self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) return out_msg @@ -223,6 +284,8 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: return out_msg + if self.ttff <= 0: + self.ttff = max(1e-3, t - self.first_log_time) position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) @@ -244,14 +307,12 @@ class Laikad: "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs + "correctedMeasurements": meas_msgs, + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), } return out_msg - #elif gnss_msg.which() == 'ionoData': - # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. - - def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid valid = self.kf_valid(t) @@ -335,31 +396,8 @@ def create_measurement_msg(meas: GNSSMeasurement): c.satPos = meas.sat_pos_final.tolist() c.satVel = meas.sat_vel.tolist() c.satVel = meas.sat_vel.tolist() - ephem = meas.sat_ephemeris - assert ephem is not None - week, time_of_week = -1, -1 - if ephem.eph_type == EphemerisType.NAV: - source_type = EphemerisSourceType.nav - elif ephem.eph_type == EphemerisType.QCOM_POLY: - source_type = EphemerisSourceType.qcom - else: - assert ephem.file_epoch is not None - week = ephem.file_epoch.week - time_of_week = ephem.file_epoch.tow - file_src = ephem.file_source - if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' - source_type = EphemerisSourceType.nasaUltraRapid - elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' - source_type = EphemerisSourceType.glonassIacUltraRapid - else: - raise Exception(f"Didn't expect file source {file_src}") - - c.ephemerisSource.type = source_type.value - c.ephemerisSource.gpsWeek = week - c.ephemerisSource.gpsTimeOfWeek = int(time_of_week) return c - def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMeasurement]): ekf_data = defaultdict(list) for m in measurements: @@ -375,18 +413,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) -class EphemerisSourceType(IntEnum): - nav = 0 - nasaUltraRapid = 1 - glonassIacUltraRapid = 2 - qcom = 3 - - -def process_msg(laikad, gnss_msg, mono_time, block=False): - - return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) - - def clear_tmp_cache(): if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 2e03551f6e..265db50c6d 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -12,11 +12,11 @@ from tqdm import tqdm from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs +from laika.ephemeris import EphemerisType from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg +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 @@ -138,9 +138,9 @@ class TestLaikad(unittest.TestCase): laikad = Laikad() laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) + # Get results and save orbits to laikad: laikad.fetch_navs(gpstime, block=False) - ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) @@ -153,6 +153,7 @@ class TestLaikad(unittest.TestCase): self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) + def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() @@ -175,35 +176,6 @@ class TestLaikad(unittest.TestCase): check_has_navs() self.assertEqual(laikad.last_fetch_navs_t, real_current_time) - def test_ephemeris_source_in_msg(self): - dicto = {'svId': 1} - data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) - - gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - # Verify gps satellite returns same source - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nasa source by using older date - gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nav source type - ephem = GPSEphemeris(data_mock) - meas = get_measurement_mock(gpstime, ephem) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - def test_laika_online(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) @@ -263,26 +235,34 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) def test_get_navs_in_process(self): - for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) - has_navs = False - has_fix = False - for m in logs: - 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: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.qcom_polys.values() - has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if out_msg is not None: + for auto_fetch_navs in [True, False]: + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=auto_fetch_navs) + has_navs = False + has_fix = False + seen_chip_eph = False + seen_internet_eph = False + + for m in logs: + 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: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.qcom_polys.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid - - self.assertTrue(has_navs or has_polys) - self.assertTrue(has_fix) - self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + if len(out_msg.gnssMeasurements.ephemerisStatuses): + seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertTrue(seen_chip_eph or auto_fetch_navs) + self.assertTrue(seen_internet_eph or not auto_fetch_navs) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): use_qcom = True @@ -303,18 +283,19 @@ class TestLaikad(unittest.TestCase): Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) - laikad.last_report_time = GPSTime(2,0) - laikad.fetch_navs(self.first_gps_time, block=True) - - # Wait for cache to save + msg = verify_messages(logs, laikad, return_one_success=True) + laikad.cache_ephemeris() wait_for_cache() # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, + save_ephemeris=True, use_qcom=use_qcom, auto_fetch_navs=False) # Verify navs are loaded from cache self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(logs, laikad, return_one_success=True) + self.assertTrue(len(msg.gnssMeasurements.ephemerisStatuses)) + self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) @@ -349,7 +330,5 @@ 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() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 50288bfd03..fbe02bda3a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c8ba9450af16f9efc70eb76a5edc205aed53e779 +3b127e8aa63d3e5d260e130631ebc2dd67347556 From 4cff94366f751e53363c811a129f0d2dd93b4655 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 16 Mar 2023 19:01:45 -0700 Subject: [PATCH 023/143] Revert "LAIKAD: TTFF, and ephemeris statuses in logs (#27591)" This reverts commit 95216de5910c62bf81a7bf6053b5917de98dc825. --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 116 +++++++++-------------- selfdrive/locationd/test/test_laikad.py | 95 +++++++++++-------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 106 insertions(+), 111 deletions(-) diff --git a/cereal b/cereal index 7492dc3f45..80a8eb8459 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 +Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 diff --git a/laika_repo b/laika_repo index 719c79a156..8463fe8fed 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed +Subproject commit 8463fe8fed272f58093406a990532084bc060359 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 695e9adc03..fe5126522c 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime -from laika.helpers import ConstellationId, get_sv_id +from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind @@ -33,44 +33,6 @@ CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 -class LogEphemerisType(IntEnum): - nav = 0 - nasaUltraRapid = 1 - glonassIacUltraRapid = 2 - qcom = 3 - -class EphemerisSource(IntEnum): - gnssChip = 0 - internet = 1 - cache = 2 - unknown = 3 - -def get_log_eph_type(ephem): - if ephem.eph_type == EphemerisType.NAV: - source_type = LogEphemerisType.nav - elif ephem.eph_type == EphemerisType.QCOM_POLY: - source_type = LogEphemerisType.qcom - else: - assert ephem.file_epoch is not None - file_src = ephem.file_source - if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' - source_type = LogEphemerisType.nasaUltraRapid - elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' - source_type = LogEphemerisType.glonassIacUltraRapid - else: - raise Exception(f"Didn't expect file source {file_src}") - return source_type - -def get_log_eph_source(ephem): - if ephem.file_name == 'qcom' or ephem.file_name == 'ublox': - source = EphemerisSource.gnssChip - elif ephem.file_name == EPHEMERIS_CACHE: - source = EphemerisSource.cache - else: - source = EphemerisSource.internet - return source - - class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), @@ -102,8 +64,6 @@ class Laikad: self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom - self.first_log_time = None - self.ttff = -1 def load_cache(self): if not self.save_ephemeris: @@ -116,8 +76,8 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] - gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: nav_dict[e.prn] = [] @@ -139,21 +99,6 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time - def create_ephem_statuses(self): - ephemeris_statuses = [] - prns_to_check = self.astro_dog.get_all_ephem_prns() - for prn in prns_to_check: - eph = self.astro_dog.get_eph(prn, self.last_report_time) - if eph is not None: - status = log.GnssMeasurements.EphemerisStatus.new_message() - status.constellationId = ConstellationId.from_rinex_char(prn[0]).value - status.svId = get_sv_id(prn) - status.type = get_log_eph_type(eph).value - status.source = get_log_eph_source(eph).value - ephemeris_statuses.append(status) - return ephemeris_statuses - - def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -225,10 +170,10 @@ class Laikad: else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct, file_name='ublox') + ephem = GPSEphemeris(data_struct) elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct, file_name='ublox') + ephem = GLONASSEphemeris(data_struct) else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return @@ -259,12 +204,6 @@ class Laikad: def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") - out_msg.gnssMeasurements = { - "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), - } - if self.first_log_time is None: - self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) return out_msg @@ -284,8 +223,6 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: return out_msg - if self.ttff <= 0: - self.ttff = max(1e-3, t - self.first_log_time) position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) @@ -307,12 +244,14 @@ class Laikad: "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs, - "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), + "correctedMeasurements": meas_msgs } return out_msg + #elif gnss_msg.which() == 'ionoData': + # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. + + def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid valid = self.kf_valid(t) @@ -396,8 +335,31 @@ def create_measurement_msg(meas: GNSSMeasurement): c.satPos = meas.sat_pos_final.tolist() c.satVel = meas.sat_vel.tolist() c.satVel = meas.sat_vel.tolist() + ephem = meas.sat_ephemeris + assert ephem is not None + week, time_of_week = -1, -1 + if ephem.eph_type == EphemerisType.NAV: + source_type = EphemerisSourceType.nav + elif ephem.eph_type == EphemerisType.QCOM_POLY: + source_type = EphemerisSourceType.qcom + else: + assert ephem.file_epoch is not None + week = ephem.file_epoch.week + time_of_week = ephem.file_epoch.tow + file_src = ephem.file_source + if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' + source_type = EphemerisSourceType.nasaUltraRapid + elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' + source_type = EphemerisSourceType.glonassIacUltraRapid + else: + raise Exception(f"Didn't expect file source {file_src}") + + c.ephemerisSource.type = source_type.value + c.ephemerisSource.gpsWeek = week + c.ephemerisSource.gpsTimeOfWeek = int(time_of_week) return c + def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMeasurement]): ekf_data = defaultdict(list) for m in measurements: @@ -413,6 +375,18 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) +class EphemerisSourceType(IntEnum): + nav = 0 + nasaUltraRapid = 1 + glonassIacUltraRapid = 2 + qcom = 3 + + +def process_msg(laikad, gnss_msg, mono_time, block=False): + + return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) + + def clear_tmp_cache(): if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 265db50c6d..2e03551f6e 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -12,11 +12,11 @@ from tqdm import tqdm from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType +from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad import EPHEMERIS_CACHE, Laikad +from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader from selfdrive.manager.process_config import managed_processes @@ -138,9 +138,9 @@ class TestLaikad(unittest.TestCase): laikad = Laikad() laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) - # Get results and save orbits to laikad: laikad.fetch_navs(gpstime, block=False) + ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) @@ -153,7 +153,6 @@ class TestLaikad(unittest.TestCase): self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) - def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() @@ -176,6 +175,35 @@ class TestLaikad(unittest.TestCase): check_has_navs() self.assertEqual(laikad.last_fetch_navs_t, real_current_time) + def test_ephemeris_source_in_msg(self): + dicto = {'svId': 1} + data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) + + gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC + laikad = Laikad() + laikad.fetch_navs(gpstime, block=True) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + # Verify gps satellite returns same source + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + + # Test nasa source by using older date + gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) + laikad = Laikad() + laikad.fetch_navs(gpstime, block=True) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + + # Test nav source type + ephem = GPSEphemeris(data_mock) + meas = get_measurement_mock(gpstime, ephem) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + def test_laika_online(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) @@ -235,34 +263,26 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) def test_get_navs_in_process(self): - for auto_fetch_navs in [True, False]: - for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=auto_fetch_navs) - has_navs = False - has_fix = False - seen_chip_eph = False - seen_internet_eph = False - - for m in logs: - 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: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.qcom_polys.values() - has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) + has_navs = False + has_fix = False + for m in logs: + 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: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.qcom_polys.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + if out_msg is not None: has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid - if len(out_msg.gnssMeasurements.ephemerisStatuses): - seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) - seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) - - self.assertTrue(has_navs or has_polys) - self.assertTrue(has_fix) - self.assertTrue(seen_chip_eph or auto_fetch_navs) - self.assertTrue(seen_internet_eph or not auto_fetch_navs) - self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): use_qcom = True @@ -283,19 +303,18 @@ class TestLaikad(unittest.TestCase): Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) - msg = verify_messages(logs, laikad, return_one_success=True) - laikad.cache_ephemeris() + laikad.last_report_time = GPSTime(2,0) + laikad.fetch_navs(self.first_gps_time, block=True) + + # Wait for cache to save wait_for_cache() # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, - save_ephemeris=True, use_qcom=use_qcom, auto_fetch_navs=False) + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) # Verify navs are loaded from cache self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(logs, laikad, return_one_success=True) - self.assertTrue(len(msg.gnssMeasurements.ephemerisStatuses)) - self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) @@ -330,5 +349,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() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index fbe02bda3a..50288bfd03 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3b127e8aa63d3e5d260e130631ebc2dd67347556 +c8ba9450af16f9efc70eb76a5edc205aed53e779 From 4208b74ed8dbabe884646f9de69caefb666b6b44 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 16 Mar 2023 19:04:04 -0700 Subject: [PATCH 024/143] update to torch 2.0 and cuda 11.8 (#27608) * wip: update to torch 2.0 * update opencv --- pyproject.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c53dcb5381..7506ee552d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,7 +83,7 @@ mypy = "^0.961" myst-parser = "^0.18.0" natsort = "^8.1.0" numpy = "^1.23.0" -opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl", platform = "linux" } +opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu118/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl", platform = "linux" } pandas = "^1.4.3" parameterized = "^0.8.1" paramiko = "^2.11.0" @@ -117,7 +117,7 @@ optional = true aenum = "^3.1.11" aiohttp = "^3.8.1" albumentations = "^1.2.1" -apex = { url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" } +apex = { url = "https://github.com/commaai/apex/releases/download/pytorch2.0.0%2Bcu11.8/apex-0.1-cp38-cp38-linux_x86_64.whl" } azure-cli-core = "^2.38.0" azure-common = "^1.1.28" azure-core = "^1.24.2" @@ -127,7 +127,7 @@ azure-storage-nspkg = "~3.1" blosc = "==1.9.2" cloudpickle = "^2.1.0" configargparse = "^1.5.3" -cupy-cuda113 = "^10.6.0" +cupy-cuda11x = "^11.6.0" datadog = "^0.44.0" dotmap = "^1.3.30" einops = "^0.5.0" @@ -166,10 +166,10 @@ scikit-learn = "^1.1.1" segmentation-models-pytorch = "==0.2.1" simplejson = "^3.17.6" SQLAlchemy = "^1.4.39" -torch = { url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } +torch = { url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl" } torchsummary = "^1.5.1" -torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } -triton = "^1.1.1" +torchvision = { url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.1%2Bcu118-cp38-cp38-linux_x86_64.whl" } +triton = "^2.0.0" Werkzeug = "^2.1.2" zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } omegaconf = "^2.3.0" From b0ba79451e63d376dec436545f98f648b3a933db Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 16 Mar 2023 21:09:21 -0700 Subject: [PATCH 025/143] upgrade to torch 2.0 cuda 11.8 (#27611) forgot to lock --- poetry.lock | 133 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/poetry.lock b/poetry.lock index 521bf3c0c3..4abd6777ba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -113,10 +113,12 @@ category = "dev" optional = false python-versions = "*" +[package.dependencies] +packaging = ">20.6" + [package.source] type = "url" -url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" - +url = "https://github.com/commaai/apex/releases/download/pytorch2.0.0%2Bcu11.8/apex-0.1-cp38-cp38-linux_x86_64.whl" [[package]] name = "appdirs" version = "1.4.4" @@ -600,6 +602,17 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "cmake" +version = "3.26.0" +description = "CMake is an open-source, cross-platform family of tools designed to build, test and package software" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +test = ["codecov (>=2.0.5)", "coverage (>=4.2)", "flake8 (>=3.0.4)", "path.py (>=11.5.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.4.0)", "pytest-runner (>=2.9)", "pytest-virtualenv (>=1.7.0)", "scikit-build (>=0.10.0)", "setuptools (>=28.0.0)", "virtualenv (>=15.0.3)", "wheel"] + [[package]] name = "colorama" version = "0.4.5" @@ -716,8 +729,8 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] [[package]] -name = "cupy-cuda113" -version = "10.6.0" +name = "cupy-cuda11x" +version = "11.6.0" description = "CuPy: NumPy & SciPy for GPU" category = "dev" optional = false @@ -725,12 +738,12 @@ python-versions = ">=3.7" [package.dependencies] fastrlock = ">=0.5" -numpy = ">=1.18,<1.25" +numpy = ">=1.20,<1.27" [package.extras] -all = ["Cython (>=0.29.22,<3)", "optuna (>=2.0)", "scipy (>=1.4,<1.11)"] +all = ["Cython (>=0.29.22,<3)", "optuna (>=2.0)", "scipy (>=1.6,<1.12)"] stylecheck = ["autopep8 (==1.5.5)", "flake8 (==3.8.4)", "mypy (==0.950)", "pbr (==5.5.1)", "pycodestyle (==2.6.0)", "types-setuptools (==57.4.14)"] -test = ["hypothesis (>=6.37.2)", "pytest (>=6.2)"] +test = ["hypothesis (>=6.37.2,<6.55.0)", "pytest (>=7.2)"] [[package]] name = "cycler" @@ -1898,6 +1911,14 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "lit" +version = "15.0.7" +description = "A Software Testing Tool" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "lockfile" version = "0.12.2" @@ -2586,8 +2607,7 @@ numpy = [ [package.source] type = "url" -url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" - +url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu118/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" [[package]] name = "osmium" version = "3.4.1" @@ -4220,19 +4240,26 @@ python-versions = ">=3.6,<4.0" [[package]] name = "torch" -version = "1.11.0+cu113" +version = "2.0.0+cu118" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" category = "dev" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" [package.dependencies] +filelock = "*" +jinja2 = "*" +networkx = "*" +sympy = "*" +triton = {version = "2.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} typing-extensions = "*" +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] + [package.source] type = "url" -url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" - +url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl" [[package]] name = "torchsummary" version = "1.5.1" @@ -4243,26 +4270,24 @@ python-versions = "*" [[package]] name = "torchvision" -version = "0.12.0+cu113" +version = "0.15.1+cu118" description = "image and video datasets and models for torch deep learning" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" [package.dependencies] numpy = "*" pillow = ">=5.3.0,<8.3.0 || >=8.4.0" requests = "*" -torch = "1.11.0" -typing-extensions = "*" +torch = "2.0.0" [package.extras] scipy = ["scipy"] [package.source] type = "url" -url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" - +url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.1%2Bcu118-cp38-cp38-linux_x86_64.whl" [[package]] name = "tornado" version = "6.2" @@ -4302,16 +4327,22 @@ test = ["pre-commit", "pytest"] [[package]] name = "triton" -version = "1.1.1" +version = "2.0.0" description = "A language and compiler for custom Deep Learning operations" category = "dev" optional = false python-versions = "*" [package.dependencies] +cmake = "*" filelock = "*" +lit = "*" torch = "*" +[package.extras] +tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] + [[package]] name = "types-atomicwrites" version = "1.4.5.1" @@ -4575,7 +4606,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "043d4bffddfddc2a5d6d20f51662a9992754831b387eb7e318c2420f3240049e" +content-hash = "a16ec604c5251dc860a44f7133289d0b7b16120757f8c903f3917329753c52d1" [metadata.files] adal = [ @@ -5040,6 +5071,25 @@ cloudpickle = [ {file = "cloudpickle-2.2.0-py3-none-any.whl", hash = "sha256:7428798d5926d8fcbfd092d18d01a2a03daf8237d8fcdc8095d256b8490796f0"}, {file = "cloudpickle-2.2.0.tar.gz", hash = "sha256:3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f"}, ] +cmake = [ + {file = "cmake-3.26.0-py2.py3-none-macosx_10_10_universal2.macosx_10_10_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:4881727389325af84e39f1ec646b7249d8910b4ed637205bee6d589cb2b2ebd2"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2010_i686.manylinux_2_12_i686.whl", hash = "sha256:babd1e38c85d38a4bf4164c3126ec8cf4cd8d374072e2a4a181e52e953007f8c"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:1851be29d79bb39505954165e934d31994268d49f566ead6fff840a5092e444d"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:483aaaeb9535deaa2657c928af5d9f0da9329f89bc249f494923495745a03677"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2f78c6194f224d462333e08d3acd571c553b58d04935971b87efbe76f241353c"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:cf129c8b71f1344975f179f30287baa8804c4c61ff1b13003244b4157b676e13"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fabb82c69223eda27e673c5c6bb02985d60cf0baa631a2e4932eed87e8229928"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502cbed2335557920b88687c6f3ff4ce433bd416204c928ad489e399e76149f5"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:b81c7775b125786c1696232078e9ceb0c9c66d26fb0a2259f40e33983170f924"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:f4cc1dde7613cc813d15fd840a33e18cd07a443aa67205d74b9b05f55f08a459"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:ac6ca9d9ff58900138bbbebc55857647fb99f1c40b84d8a232f23b0d27d7f48a"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:85e0bad5aeb3a82919ed7d78b76a0462eafe2f918076a1823a09c6f37910f3e0"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:5523b9701be367572155e77294bf8aa3ac9aa0d73c50dcd6c57903d12bcb308e"}, + {file = "cmake-3.26.0-py2.py3-none-win32.whl", hash = "sha256:96f0e887260255eeb83bcf3465d51bc6c94078251c9312fa142dce6d3e80acac"}, + {file = "cmake-3.26.0-py2.py3-none-win_amd64.whl", hash = "sha256:a0719a6f79cdc4d7b16caf757b8ae13eae1c6ce5a08d594cc09774afe129515d"}, + {file = "cmake-3.26.0-py2.py3-none-win_arm64.whl", hash = "sha256:11159c9b64c6473d84361ab44ef2c85e1bd2db7a2b1b798ce8bf5988f32adf43"}, + {file = "cmake-3.26.0.tar.gz", hash = "sha256:c18185c9cc147d0fa1e9228962aa37901b37866bd5d617e9efa23dfe706f7321"}, +] colorama = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, @@ -5209,15 +5259,17 @@ cryptography = [ {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"}, {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"}, ] -cupy-cuda113 = [ - {file = "cupy_cuda113-10.6.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:27e5efe2c3afa80ff48654cb27f9e0eddb36f8b26ef0d32d3ba0a233e1359b51"}, - {file = "cupy_cuda113-10.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8b96076d1ddd33fdb2c908ed0f8109caf69d37d36f839a8a8cdae1312508336f"}, - {file = "cupy_cuda113-10.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22363c2863727cae5154aa4bab9e8a648d7fe66c9e2195d81dd4e8693c2e61ce"}, - {file = "cupy_cuda113-10.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8cc69b9d5735372477a7af3822c8f8e996ffe6de05cfc917500af9dc0117ca3e"}, - {file = "cupy_cuda113-10.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:10dc6899577e445426d81f0960ba9059d9aaa750426997c61fad882d6345264c"}, - {file = "cupy_cuda113-10.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:c6893ac9040a11610e63973063dfd715dbda8bd07ef99951bab7a09c7f335e1e"}, - {file = "cupy_cuda113-10.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4bf4bc06d991c06b95f6fe558d117cafd93bd4eeaf80606f18dd31d20d2eff25"}, - {file = "cupy_cuda113-10.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:3745fc42dca86ba8a1109ddc7964aed8e1efc0ce8085cb2f140dcd6429f26354"}, +cupy-cuda11x = [ + {file = "cupy_cuda11x-11.6.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:1b9914f57868a1559e9bfabfbae8c724585914e8e1f277acb9cdb6aa0756eaa4"}, + {file = "cupy_cuda11x-11.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:ac8dd082ddb00996bc4d37cc5765907048f467aadb61bcbff25f3c2a88c50583"}, + {file = "cupy_cuda11x-11.6.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:bf7496340dfbc2eaa3e0ebfd03c4ab8b1fc36d7d14f68718c33eeb395aaa6eed"}, + {file = "cupy_cuda11x-11.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:e3bbd55c26d60069d7e5af2200fb47e7c42ca6437acac297637a2d3c00f6fe46"}, + {file = "cupy_cuda11x-11.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0d7ebcfd7234946719ad28890593d9fc78fad5753ef4b073e0d7bdb7da2f5640"}, + {file = "cupy_cuda11x-11.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3bc3f81fbc5a86c7155c6036809f2ada4023fc0870dce158d3d9f6d0b575727f"}, + {file = "cupy_cuda11x-11.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1d6810568e683cb153972b3019ddb5efc369036511122117d9eda09cf84d1042"}, + {file = "cupy_cuda11x-11.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:31c1ec72ffe9ad6fda9fb0a2aff1fcca38da66a8e521e333bae0d67ebc80ead0"}, + {file = "cupy_cuda11x-11.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6a4822daadfce0464cb619099eb82c7ba30ae7755d6869ba5eba1c675a9eed67"}, + {file = "cupy_cuda11x-11.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:3d0f44d747b38ce2b213d64270265f953b68cf29860ec5fa65848b9faaea3fc1"}, ] cycler = [ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, @@ -5618,6 +5670,7 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6044,6 +6097,9 @@ libusb1 = [ {file = "libusb1-3.0.0-py3-none-win_amd64.whl", hash = "sha256:6f6bb010632ada35c661d17a65e135077beef0fbb2434d5ffdb3a4a911fd9490"}, {file = "libusb1-3.0.0.tar.gz", hash = "sha256:5792a9defee40f15d330a40d9b1800545c32e47ba7fc66b6f28f133c9fcc8538"}, ] +lit = [ + {file = "lit-15.0.7.tar.gz", hash = "sha256:ed08ac55afe714a193653df293ae8a6ee6c45d6fb11eeca72ce347d99b88ecc8"}, +] lockfile = [ {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, @@ -7008,6 +7064,7 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -7015,12 +7072,14 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, + {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, @@ -8031,11 +8090,15 @@ traitlets = [ {file = "traitlets-5.5.0.tar.gz", hash = "sha256:b122f9ff2f2f6c1709dab289a05555be011c87828e911c0cf4074b85cb780a79"}, ] triton = [ - {file = "triton-1.1.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8441e6f44517aef8f6345f621c003926cbe970892802411a949ccda516cbd5ba"}, - {file = "triton-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840776bc1f4757fb2d6af974694c5e5313220ceec238ee6118b9728bc2aa9ade"}, - {file = "triton-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d42cdaa7d56de463d762c18cc876bfd0828a2b6a706263393fe7e10d1c83ca"}, - {file = "triton-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc19c0e902bbf7d29de4d444455608065a2c56e3524f4bc94e724511ca518f3"}, - {file = "triton-1.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02f798cd2dd922228082ce1a4e9d81badb9a6217a9aac6d783e95bf7055974d"}, + {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"}, + {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"}, + {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"}, + {file = "triton-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fedce6a381901b1547e0e7e1f2546e4f65dca6d91e2d8a7305a2d1f5551895be"}, + {file = "triton-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75834f27926eab6c7f00ce73aaf1ab5bfb9bec6eb57ab7c0bfc0a23fac803b4c"}, + {file = "triton-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0117722f8c2b579cd429e0bee80f7731ae05f63fe8e9414acd9a679885fcbf42"}, + {file = "triton-2.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcd9be5d0c2e45d2b7e6ddc6da20112b6862d69741576f9c3dbaf941d745ecae"}, + {file = "triton-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42a0d2c3fc2eab4ba71384f2e785fbfd47aa41ae05fa58bf12cb31dcbd0aeceb"}, + {file = "triton-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c47b72c72693198163ece9d90a721299e4fb3b8e24fd13141e384ad952724f"}, ] types-atomicwrites = [ {file = "types-atomicwrites-1.4.5.1.tar.gz", hash = "sha256:9e9f0923ebf93524b28bcece5a23ac8c3820f39b060df29f671936d2e4bc04bc"}, From 204f7d862390d86ab958275cd887b8cbc3e66f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 22:09:05 -0700 Subject: [PATCH 026/143] Ttff logs (#27610) * ttff in logs * More meta info * cleanup * passess tests * unused import * fix linting * ttff of 0 is invalid * ref commit * bump cereal * Update ref_commit * sort ephem status list * sort ephem status list * update ref --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 117 ++++++++++++++--------- selfdrive/locationd/test/test_laikad.py | 95 +++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 112 insertions(+), 106 deletions(-) diff --git a/cereal b/cereal index 80a8eb8459..7492dc3f45 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 +Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 diff --git a/laika_repo b/laika_repo index 8463fe8fed..719c79a156 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 8463fe8fed272f58093406a990532084bc060359 +Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index fe5126522c..3698867ec9 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime -from laika.helpers import ConstellationId +from laika.helpers import ConstellationId, get_sv_id from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind @@ -33,6 +33,44 @@ CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 +class LogEphemerisType(IntEnum): + nav = 0 + nasaUltraRapid = 1 + glonassIacUltraRapid = 2 + qcom = 3 + +class EphemerisSource(IntEnum): + gnssChip = 0 + internet = 1 + cache = 2 + unknown = 3 + +def get_log_eph_type(ephem): + if ephem.eph_type == EphemerisType.NAV: + source_type = LogEphemerisType.nav + elif ephem.eph_type == EphemerisType.QCOM_POLY: + source_type = LogEphemerisType.qcom + else: + assert ephem.file_epoch is not None + file_src = ephem.file_source + if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' + source_type = LogEphemerisType.nasaUltraRapid + elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' + source_type = LogEphemerisType.glonassIacUltraRapid + else: + raise Exception(f"Didn't expect file source {file_src}") + return source_type + +def get_log_eph_source(ephem): + if ephem.file_name == 'qcom' or ephem.file_name == 'ublox': + source = EphemerisSource.gnssChip + elif ephem.file_name == EPHEMERIS_CACHE: + source = EphemerisSource.cache + else: + source = EphemerisSource.internet + return source + + class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), @@ -64,6 +102,8 @@ class Laikad: self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom + self.first_log_time = None + self.ttff = -1 def load_cache(self): if not self.save_ephemeris: @@ -76,8 +116,8 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] - gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: nav_dict[e.prn] = [] @@ -99,6 +139,22 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time + def create_ephem_statuses(self): + ephemeris_statuses = [] + prns_to_check = list(self.astro_dog.get_all_ephem_prns()) + prns_to_check.sort() + for prn in prns_to_check: + eph = self.astro_dog.get_eph(prn, self.last_report_time) + if eph is not None: + status = log.GnssMeasurements.EphemerisStatus.new_message() + status.constellationId = ConstellationId.from_rinex_char(prn[0]).value + status.svId = get_sv_id(prn) + status.type = get_log_eph_type(eph).value + status.source = get_log_eph_source(eph).value + ephemeris_statuses.append(status) + return ephemeris_statuses + + def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -170,10 +226,10 @@ class Laikad: else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct) + ephem = GPSEphemeris(data_struct, file_name='ublox') elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct) + ephem = GLONASSEphemeris(data_struct, file_name='ublox') else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return @@ -204,6 +260,12 @@ class Laikad: def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") + out_msg.gnssMeasurements = { + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), + } + if self.first_log_time is None: + self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) return out_msg @@ -223,6 +285,8 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: return out_msg + if self.ttff <= 0: + self.ttff = max(1e-3, t - self.first_log_time) position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) @@ -244,14 +308,12 @@ class Laikad: "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs + "correctedMeasurements": meas_msgs, + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), } return out_msg - #elif gnss_msg.which() == 'ionoData': - # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. - - def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid valid = self.kf_valid(t) @@ -335,31 +397,8 @@ def create_measurement_msg(meas: GNSSMeasurement): c.satPos = meas.sat_pos_final.tolist() c.satVel = meas.sat_vel.tolist() c.satVel = meas.sat_vel.tolist() - ephem = meas.sat_ephemeris - assert ephem is not None - week, time_of_week = -1, -1 - if ephem.eph_type == EphemerisType.NAV: - source_type = EphemerisSourceType.nav - elif ephem.eph_type == EphemerisType.QCOM_POLY: - source_type = EphemerisSourceType.qcom - else: - assert ephem.file_epoch is not None - week = ephem.file_epoch.week - time_of_week = ephem.file_epoch.tow - file_src = ephem.file_source - if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' - source_type = EphemerisSourceType.nasaUltraRapid - elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' - source_type = EphemerisSourceType.glonassIacUltraRapid - else: - raise Exception(f"Didn't expect file source {file_src}") - - c.ephemerisSource.type = source_type.value - c.ephemerisSource.gpsWeek = week - c.ephemerisSource.gpsTimeOfWeek = int(time_of_week) return c - def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMeasurement]): ekf_data = defaultdict(list) for m in measurements: @@ -375,18 +414,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) -class EphemerisSourceType(IntEnum): - nav = 0 - nasaUltraRapid = 1 - glonassIacUltraRapid = 2 - qcom = 3 - - -def process_msg(laikad, gnss_msg, mono_time, block=False): - - return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) - - def clear_tmp_cache(): if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 2e03551f6e..265db50c6d 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -12,11 +12,11 @@ from tqdm import tqdm from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs +from laika.ephemeris import EphemerisType from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg +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 @@ -138,9 +138,9 @@ class TestLaikad(unittest.TestCase): laikad = Laikad() laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) + # Get results and save orbits to laikad: laikad.fetch_navs(gpstime, block=False) - ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) @@ -153,6 +153,7 @@ class TestLaikad(unittest.TestCase): self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) + def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() @@ -175,35 +176,6 @@ class TestLaikad(unittest.TestCase): check_has_navs() self.assertEqual(laikad.last_fetch_navs_t, real_current_time) - def test_ephemeris_source_in_msg(self): - dicto = {'svId': 1} - data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) - - gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - # Verify gps satellite returns same source - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nasa source by using older date - gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nav source type - ephem = GPSEphemeris(data_mock) - meas = get_measurement_mock(gpstime, ephem) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - def test_laika_online(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) @@ -263,26 +235,34 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) def test_get_navs_in_process(self): - for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) - has_navs = False - has_fix = False - for m in logs: - 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: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.qcom_polys.values() - has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if out_msg is not None: + for auto_fetch_navs in [True, False]: + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=auto_fetch_navs) + has_navs = False + has_fix = False + seen_chip_eph = False + seen_internet_eph = False + + for m in logs: + 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: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.qcom_polys.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid - - self.assertTrue(has_navs or has_polys) - self.assertTrue(has_fix) - self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + if len(out_msg.gnssMeasurements.ephemerisStatuses): + seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertTrue(seen_chip_eph or auto_fetch_navs) + self.assertTrue(seen_internet_eph or not auto_fetch_navs) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): use_qcom = True @@ -303,18 +283,19 @@ class TestLaikad(unittest.TestCase): Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) - laikad.last_report_time = GPSTime(2,0) - laikad.fetch_navs(self.first_gps_time, block=True) - - # Wait for cache to save + msg = verify_messages(logs, laikad, return_one_success=True) + laikad.cache_ephemeris() wait_for_cache() # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, + save_ephemeris=True, use_qcom=use_qcom, auto_fetch_navs=False) # Verify navs are loaded from cache self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(logs, laikad, return_one_success=True) + self.assertTrue(len(msg.gnssMeasurements.ephemerisStatuses)) + self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) @@ -349,7 +330,5 @@ 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() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 50288bfd03..cbe2a016ce 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c8ba9450af16f9efc70eb76a5edc205aed53e779 +5775220ec2e62dcdedb92d96270f1380bbd88c39 From b5198f99ea66c68aab87f4d9e525d306ebe97b72 Mon Sep 17 00:00:00 2001 From: Kay Oh Date: Fri, 17 Mar 2023 15:08:51 +0900 Subject: [PATCH 027/143] Add missing FW for 2022 (2023MY) Hyundai IONIQ 5 (#27590) Update values.py Korean Ver. --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index cf0143543a..f7cedf550e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1562,6 +1562,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', + b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206', From 2f95148a67bce42dc8ba9954d7bc87197e5adbd2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 16 Mar 2023 23:16:11 -0700 Subject: [PATCH 028/143] bump panda (#27612) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index c0aea3273a..e4cc97d882 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c0aea3273a82a91f10554b1b3317727da99f4564 +Subproject commit e4cc97d8826dc95a7833b859c36948302445a499 From 57c4d78869ad197189427ab68c45ac8cc7bbd9d0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 17 Mar 2023 00:03:21 -0700 Subject: [PATCH 029/143] Toyota: add 2023 RAV4/RAV4 Hybrid as dashcam (#27609) * test out lta message * correctly send * percentage is percentage driver isn't overriding * closer to stock system * should be able to send LTA at 100hz, counter is the same as LKA * small amount of torque towards desired * Offset commanded torque correctly * Too little torque * use car's SETME's * Revert "use car's SETME's" This reverts commit c88856969995f97cc5ec4e2b24a5cc4e3ef4721a. * try cutting steer every second * Didn't seem to matter This reverts commit 6923498b2a9eed8beb3998f441899f1df4948f6f. * steer to 0 * let packer set counter * add for camry * log steer faults * comments * bump opendbc * add opParams * add lta safety * set safety param * fix torque control bug * bump panda * fix missing signal * [experiment] apply some rate limiting and anti-windup * no faults, clip to 90 deg, decent torque blending * clean up blending * toyota angle rate limits * use std angle limits * assert we only add angle control to TSS2 cars * clean up carcontroller a bit * space space * bump opendbc * clean up toyotacan from opendbc change * bump panda * will tests run? * steer at zero * refactor angle to use LatControlPID with zero gains * stop some faults and tuning * possibly fix integral wind up at max torque * Add 2023 rav4 * limit torque inside EPS when overriding (no huge windup in edge cases when overriding) * fix wind up issue after turns (or prolonged saturation) * this doesn't work that well * try these limits * try this * log the angle! * global variable * Apply suggestions from code review * clip angle to 3 m/s/s * some tolerance for roll * raise limits a bit * bumppanda * fix faults * still not good * offsetting causing hugging? * Revert "offsetting causing hugging?" This reverts commit a42ec0b772ed74a1fd54b7fef2e7c275a3e8333b. * reduce kp * class var not needed * limit up angle delta * fix saturation check * feedforward includes offset * some threshold for roll * bump panda * surely we don't need this * test stuff * Toyota: Add FW for 2023 RAV4 Hybrid (#27494) * Toyota: Add FW for 2023 RAV4 Hybrid * Set RAVH_TSS2_2022 to use angle SteerControlType * bump panda * remove extras * Revert "remove extras" This reverts commit 87378e734915c107f57f99a5feef4dcb2b2a9a37. * no max angle limit for now * add as separate platforms * remove debug scripts * revert to master * remove these FW versions from 2022 * dashcam these cars :( * fix test * interface * add to untested routes * never send torque with LTA cars * fix values * clean up controlsd * reset lat control files * use the car param * add to params * bump panda to master * Update selfdrive/car/toyota/carcontroller.py * don't set torque params if angle control (fixes controlsd bug) * reset controlsd * keyword * in another pr * simplify test * rm line * Update selfdrive/car/toyota/tests/test_toyota.py --------- Co-authored-by: crispbee <84819466+crispbee@users.noreply.github.com> --- selfdrive/car/tests/routes.py | 2 + selfdrive/car/torque_data/override.yaml | 4 ++ selfdrive/car/toyota/carcontroller.py | 5 +++ selfdrive/car/toyota/interface.py | 18 +++++--- selfdrive/car/toyota/tests/__init__.py | 0 selfdrive/car/toyota/tests/test_toyota.py | 13 ++++++ selfdrive/car/toyota/values.py | 51 +++++++++++++++++++++-- 7 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 selfdrive/car/toyota/tests/__init__.py create mode 100755 selfdrive/car/toyota/tests/test_toyota.py diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 4ca7c0a16c..2c4ec84e86 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -27,6 +27,8 @@ non_tested_cars = [ HYUNDAI.KIA_OPTIMA_H, HONDA.ODYSSEY_CHN, VOLKSWAGEN.CRAFTER_MK2, # need a route from an ACC-equipped Crafter + TOYOTA.RAV4_TSS2_2023, + TOYOTA.RAV4H_TSS2_2023, ] CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,)) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index cc1681bce1..75051316fa 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -7,6 +7,10 @@ NISSAN LEAF 2018 Instrument Cluster: [.nan, 1.5, .nan] NISSAN LEAF 2018: [.nan, 1.5, .nan] NISSAN ROGUE 2019: [.nan, 1.5, .nan] +# Toyota LTA also has torque +TOYOTA RAV4 2023: [.nan, 3.0, .nan] +TOYOTA RAV4 HYBRID 2023: [.nan, 3.0, .nan] + # Tesla has high torque TESLA AP1 MODEL S: [.nan, 2.5, .nan] TESLA AP2 MODEL S: [.nan, 2.5, .nan] diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 8004ea9dca..66a7b57f01 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -76,6 +76,11 @@ class CarController: apply_steer_req = 0 self.steer_rate_counter = 0 + # Never actuate with LKA on cars that only support LTA + if self.CP.steerControlType == car.CarParams.SteerControlType.angle: + apply_steer = 0 + apply_steer_req = 0 + # TODO: probably can delete this. CS.pcm_acc_status uses a different signal # than CS.cruiseState.enabled. confirm they're not meaningfully different if not CC.enabled and CS.pcm_acc_status: diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 8b3fd048d9..e6476863c3 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,8 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams, NO_STOP_TIMER_CAR +from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ + MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -23,13 +24,18 @@ class CarInterface(CarInterfaceBase): if candidate in (CAR.RAV4, CAR.PRIUS_V, CAR.COROLLA, CAR.LEXUS_ESH, CAR.LEXUS_CTH): ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_ALT_BRAKE + if candidate in ANGLE_CONTROL_CAR: + ret.dashcamOnly = True + ret.steerControlType = car.CarParams.SteerControlType.angle + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_LTA + else: + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + ret.steerActuatorDelay = 0.12 # Default delay, Prius has larger delay ret.steerLimitTimer = 0.4 ret.stoppingControl = False # Toyota starts braking more when it thinks you want to stop stop_and_go = False - steering_angle_deadzone_deg = 0.0 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg) if candidate == CAR.PRIUS: stop_and_go = True @@ -40,9 +46,8 @@ class CarInterface(CarInterfaceBase): # Only give steer angle deadzone to for bad angle sensor prius for fw in car_fw: if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00': - steering_angle_deadzone_deg = 0.2 ret.steerActuatorDelay = 0.25 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg) + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.2) elif candidate == CAR.PRIUS_V: stop_and_go = True @@ -102,7 +107,8 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.7983 ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid - elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022): + elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, + CAR.RAV4_TSS2_2023, CAR.RAV4H_TSS2_2023): stop_and_go = True ret.wheelbase = 2.68986 ret.steerRatio = 14.3 diff --git a/selfdrive/car/toyota/tests/__init__.py b/selfdrive/car/toyota/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/car/toyota/tests/test_toyota.py b/selfdrive/car/toyota/tests/test_toyota.py new file mode 100755 index 0000000000..5648f75fe7 --- /dev/null +++ b/selfdrive/car/toyota/tests/test_toyota.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +import unittest + +from selfdrive.car.toyota.values import TSS2_CAR, ANGLE_CONTROL_CAR + + +class TestToyotaInterfaces(unittest.TestCase): + def test_angle_car_set(self): + self.assertTrue(len(ANGLE_CONTROL_CAR - TSS2_CAR) == 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 43f0593325..965a9e6506 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -67,8 +67,10 @@ class CAR: RAV4H = "TOYOTA RAV4 HYBRID 2017" RAV4_TSS2 = "TOYOTA RAV4 2019" RAV4_TSS2_2022 = "TOYOTA RAV4 2022" + RAV4_TSS2_2023 = "TOYOTA RAV4 2023" RAV4H_TSS2 = "TOYOTA RAV4 HYBRID 2019" RAV4H_TSS2_2022 = "TOYOTA RAV4 HYBRID 2022" + RAV4H_TSS2_2023 = "TOYOTA RAV4 HYBRID 2023" MIRAI = "TOYOTA MIRAI 2021" # TSS 2.5 SIENNA = "TOYOTA SIENNA 2018" @@ -157,8 +159,10 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { ], CAR.RAV4_TSS2: ToyotaCarInfo("Toyota RAV4 2019-21", video_link="https://www.youtube.com/watch?v=wJxjDd42gGA"), CAR.RAV4_TSS2_2022: ToyotaCarInfo("Toyota RAV4 2022"), + CAR.RAV4_TSS2_2023: ToyotaCarInfo("Toyota RAV4 2023"), CAR.RAV4H_TSS2: ToyotaCarInfo("Toyota RAV4 Hybrid 2019-21"), CAR.RAV4H_TSS2_2022: ToyotaCarInfo("Toyota RAV4 Hybrid 2022", video_link="https://youtu.be/U0nH9cnrFB0"), + CAR.RAV4H_TSS2_2023: ToyotaCarInfo("Toyota RAV4 Hybrid 2023"), CAR.MIRAI: ToyotaCarInfo("Toyota Mirai 2021"), CAR.SIENNA: ToyotaCarInfo("Toyota Sienna 2018-20", video_link="https://www.youtube.com/watch?v=q1UPOo4Sh68", min_enable_speed=MIN_ACC_SPEED), @@ -1459,6 +1463,23 @@ FW_VERSIONS = { b'\x028646F0R02100\x00\x00\x00\x008646G0R01100\x00\x00\x00\x00', ], }, + CAR.RAV4_TSS2_2023: { + (Ecu.abs, 0x7b0, None): [ + b'\x01F15260R450\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'\x028965B0R11000\x00\x00\x00\x008965B0R12000\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x01896634AJ2000\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F0R03100\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0R05100\x00\x00\x00\x008646G0R02100\x00\x00\x00\x00', + ], + }, CAR.RAV4H_TSS2: { (Ecu.engine, 0x700, None): [ b'\x01896634A15000\x00\x00\x00\x00', @@ -1546,6 +1567,23 @@ FW_VERSIONS = { b'\x028646F0R02100\x00\x00\x00\x008646G0R01100\x00\x00\x00\x00', ], }, + CAR.RAV4H_TSS2_2023: { + (Ecu.abs, 0x7b0, None): [ + b'\x01F15264283200\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'\x028965B0R11000\x00\x00\x00\x008965B0R12000\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x01896634AE1001\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F0R03100\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0R05100\x00\x00\x00\x008646G0R02100\x00\x00\x00\x00', + ], + }, CAR.SIENNA: { (Ecu.engine, 0x700, None): [ b'\x01896630832100\x00\x00\x00\x00', @@ -2104,6 +2142,7 @@ DBC = { CAR.AVALONH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.RAV4_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.RAV4_TSS2_2022: dbc_dict('toyota_nodsu_pt_generated', None), + CAR.RAV4_TSS2_2023: dbc_dict('toyota_nodsu_pt_generated', None), CAR.COROLLA_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.COROLLAH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.LEXUS_ES_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), @@ -2114,6 +2153,7 @@ DBC = { CAR.LEXUS_CTH: dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'), CAR.RAV4H_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.RAV4H_TSS2_2022: dbc_dict('toyota_nodsu_pt_generated', None), + CAR.RAV4H_TSS2_2023: dbc_dict('toyota_nodsu_pt_generated', None), CAR.LEXUS_NXH: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), CAR.LEXUS_NX: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), CAR.LEXUS_NX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), @@ -2128,8 +2168,8 @@ DBC = { EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_IS: 77, CAR.LEXUS_RC: 77, CAR.LEXUS_CTH: 100, CAR.PRIUS_V: 100}) # Toyota/Lexus Safety Sense 2.0 and 2.5 -TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, - CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, +TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4_TSS2_2023, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, + CAR.RAV4H_TSS2_2023, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2, CAR.CHRH_TSS2} NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} @@ -2138,10 +2178,13 @@ NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} UNSUPPORTED_DSU_CAR = {CAR.LEXUS_IS, CAR.LEXUS_RC} # these cars have a radar which sends ACC messages instead of the camera -RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2, CAR.CHRH_TSS2} +RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2_2023, CAR.RAV4_TSS2_2023, CAR.CHR_TSS2, CAR.CHRH_TSS2} + +# these cars use the Lane Tracing Assist (LTA) message for lateral control +ANGLE_CONTROL_CAR = {CAR.RAV4H_TSS2_2023, CAR.RAV4_TSS2_2023} EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.CHRH_TSS2, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, - CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, + CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.RAV4H_TSS2_2023, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} # no resume button press required From 74db5a4b421c822065677b12c4493c4e20aa2a9b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Mar 2023 01:16:14 +0800 Subject: [PATCH 030/143] cabana: group CAN events by message id to reduce the time complex from O(N) to O(1) (#27601) * refactor streams * helper function xLessThan * fix fill gaps --- tools/cabana/binaryview.cc | 2 +- tools/cabana/chartswidget.cc | 84 +++++++------------- tools/cabana/dbc.cc | 2 +- tools/cabana/dbc.h | 6 +- tools/cabana/dbcmanager.cc | 1 - tools/cabana/historylog.cc | 43 ++++------- tools/cabana/mainwin.cc | 10 +-- tools/cabana/messageswidget.cc | 6 +- tools/cabana/streams/abstractstream.cc | 103 +++++++++++++------------ tools/cabana/streams/abstractstream.h | 20 ++++- tools/cabana/streams/livestream.cc | 9 +-- tools/cabana/streams/livestream.h | 8 +- tools/cabana/streams/replaystream.cc | 13 +++- tools/cabana/streams/replaystream.h | 3 +- tools/cabana/tools/findsimilarbits.cc | 39 ++++------ tools/replay/replay.h | 1 + 16 files changed, 162 insertions(+), 188 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index b81f7d5e79..0a4f6fc999 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -422,7 +422,7 @@ void BinaryItemDelegate::drawBorder(QPainter* painter, const QStyleOptionViewIte painter->setClipRegion(QRegion(rc).subtracted(subtract)); if (!subtract.isEmpty()) { // fill gaps inside corners. - painter->setPen(QPen(border_color, 2)); + painter->setPen(QPen(border_color, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); for (auto &r : subtract) { painter->drawRect(r); } diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 61afb871ae..04734e6749 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -16,6 +16,8 @@ #include const int MAX_COLUMN_COUNT = 4; +static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; } + // ChartsWidget ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { @@ -135,13 +137,11 @@ void ChartsWidget::updateState() { const double cur_sec = can->currentSec(); if (!is_zoomed) { - double pos = (cur_sec - display_range.first) / std::max(1.0, (display_range.second - display_range.first)); + double pos = (cur_sec - display_range.first) / std::max(1.0, max_chart_range); if (pos < 0 || pos > 0.8) { display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1); } - auto events = can->events(); - double max_event_sec = events->empty() ? 0 : (events->back()->mono_time / 1e9 - can->routeStartTime()); - double max_sec = std::min(std::floor(display_range.first + max_chart_range), max_event_sec); + double max_sec = std::min(std::floor(display_range.first + max_chart_range), can->lastEventSecond()); display_range.first = std::max(0.0, max_sec - max_chart_range); display_range.second = display_range.first + max_chart_range; } else if (cur_sec < zoomed_range.first || cur_sec >= zoomed_range.second) { @@ -326,6 +326,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { setRenderHint(QPainter::Antialiasing); // TODO: enable zoomIn/seekTo in live streaming mode. setRubberBand(can->liveStreaming() ? QChartView::NoRubberBand : QChartView::HorizontalRubberBand); + setMouseTracking(true); QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); @@ -481,8 +482,8 @@ void ChartView::updatePlot(double cur, double min, double max) { void ChartView::updateSeriesPoints() { // Show points when zoomed in enough for (auto &s : sigs) { - auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - auto end = std::lower_bound(begin, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); + auto end = std::lower_bound(begin, s.vals.end(), axis_x->max(), xLessThan); int num_points = std::max(end - begin, 1); int pixels_per_point = width() / num_points; @@ -496,64 +497,33 @@ void ChartView::updateSeriesPoints() { } void ChartView::updateSeries(const cabana::Signal *sig) { - const auto events = can->events(); for (auto &s : sigs) { if (!sig || s.sig == sig) { if (!can->liveStreaming()) { s.vals.clear(); s.step_vals.clear(); - s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz - s.step_vals.reserve(settings.max_cached_minutes * 60 * 100 * 2); s.last_value_mono_time = 0; } s.series->setColor(getColor(s.sig)); - struct Chunk { - std::vector::const_iterator first, second; - QVector vals; - QVector step_vals; - }; - // split into one minitue chunks - QVector chunks; - Event begin_event(cereal::Event::Which::INIT_DATA, s.last_value_mono_time); - auto begin = std::upper_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); - for (auto it = begin, second = begin; it != events->end(); it = second) { - second = std::lower_bound(it, events->end(), (*it)->mono_time + 1e9 * 60, [](auto &e, uint64_t ts) { return e->mono_time < ts; }); - chunks.push_back({it, second}); + auto msgs = can->events().at(s.msg_id); + auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time=s.last_value_mono_time}); + int new_size = std::max(s.vals.size() + std::distance(first, msgs.cend()), settings.max_cached_minutes * 60 * 100); + if (s.vals.capacity() <= new_size) { + s.vals.reserve(new_size * 2); + s.step_vals.reserve(new_size * 4); } - QtConcurrent::blockingMap(chunks, [&](Chunk &chunk) { - chunk.vals.reserve(60 * 100); // 100 hz - chunk.step_vals.reserve(60 * 100 * 2); // 100 hz - double route_start_time = can->routeStartTime(); - for (auto it = chunk.first; it != chunk.second; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - if (s.msg_id.address == c.getAddress() && s.msg_id.source == c.getSrc()) { - auto dat = c.getDat(); - double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *s.sig); - double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds - chunk.vals.push_back({ts, value}); - if (!chunk.step_vals.empty()) { - chunk.step_vals.push_back({ts, chunk.step_vals.back().y()}); - } - chunk.step_vals.push_back({ts,value}); - } - } - } - } - }); - for (auto &c : chunks) { - s.vals.append(c.vals); - if (!c.step_vals.empty()) { - if (!s.step_vals.empty()) { - s.step_vals.append({c.step_vals.first().x(), s.step_vals.back().y()}); - } - s.step_vals.append(c.step_vals); + const double route_start_time = can->routeStartTime(); + for (auto end = msgs.cend(); first != end; ++first) { + double value = get_raw_value(first->dat, first->size, *s.sig); + double ts = first->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()}); } - } - if (events->size()) { - s.last_value_mono_time = events->back()->mono_time; + s.step_vals.append({ts, value}); + s.last_value_mono_time = first->mono_time; } if (!can->liveStreaming()) { s.segment_tree.build(s.vals); @@ -580,8 +550,8 @@ void ChartView::updateAxisY() { unit.clear(); } - auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); + auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), xLessThan); if (can->liveStreaming()) { for (auto it = first; it != last; ++it) { if (it->y() < min) min = it->y(); @@ -826,8 +796,8 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); for (auto &s : sigs) { if (s.series->useOpenGL() && s.series->isVisible() && s.series->pointsVisible()) { - auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); + auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), xLessThan); for (auto it = first; it != last; ++it) { painter->setBrush(s.series->color()); painter->drawEllipse(chart()->mapToPosition(*it), 4, 4); @@ -929,7 +899,7 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); main_layout->addWidget(buttonBox, 3, 2); - for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) { + for (auto it = can->last_msgs.cbegin(); it != can->last_msgs.cend(); ++it) { if (auto m = dbc()->msg(it.key())) { msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key().toString()), QVariant::fromValue(it.key())); } diff --git a/tools/cabana/dbc.cc b/tools/cabana/dbc.cc index ff100e01f7..38002af06c 100644 --- a/tools/cabana/dbc.cc +++ b/tools/cabana/dbc.cc @@ -27,7 +27,7 @@ static QVector BIG_ENDIAN_START_BITS = []() { return ret; }(); -double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig) { +double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig) { int64_t val = 0; int i = sig.msb / 8; diff --git a/tools/cabana/dbc.h b/tools/cabana/dbc.h index a2ebbc16cc..701908112f 100644 --- a/tools/cabana/dbc.h +++ b/tools/cabana/dbc.h @@ -38,6 +38,10 @@ struct MessageId { uint qHash(const MessageId &item); Q_DECLARE_METATYPE(MessageId); +template <> +struct std::hash { + std::size_t operator()(const MessageId &k) const noexcept { return qHash(k); } +}; typedef QList> ValueDescription; @@ -72,7 +76,7 @@ namespace cabana { } // Helper functions -double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig); +double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig); int bigEndianStartBitsIndex(int start_bit); int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size); diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 651367ba57..49aac5c18b 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -212,4 +212,3 @@ DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; } - diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 830fd30d49..3e80a6a697 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -119,40 +119,31 @@ template std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; QVector values(sigs.size()); - for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - if (msg_id.address == c.getAddress() && msg_id.source == c.getSrc()) { - const auto dat = c.getDat(); - for (int i = 0; i < sigs.size(); ++i) { - values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *sigs[i]); - } - if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { - auto &m = msgs.emplace_back(); - m.mono_time = (*it)->mono_time; - m.data = QByteArray((char *)dat.begin(), dat.size()); - m.sig_values = values; - if (msgs.size() >= batch_size && min_time == 0) - return msgs; - } - } + for (; first != last && first->mono_time > min_time; ++first) { + for (int i = 0; i < sigs.size(); ++i) { + values[i] = get_raw_value(first->dat, first->size, *sigs[i]); + } + if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { + auto &m = msgs.emplace_back(); + m.mono_time = first->mono_time; + m.data = QByteArray((const char *)first->dat, first->size); + m.sig_values = values; + if (msgs.size() >= batch_size && min_time == 0) { + return msgs; } } } return msgs; } -template std::deque HistoryLogModel::fetchData<>(std::vector::iterator first, std::vector::iterator last, uint64_t min_time); -template std::deque HistoryLogModel::fetchData<>(std::vector::reverse_iterator first, std::vector::reverse_iterator last, uint64_t min_time); - std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { - auto events = can->events(); + const auto &events = can->events().at(msg_id); const auto freq = can->lastMessage(msg_id).freq; const bool update_colors = !display_signals_mode || sigs.empty(); if (dynamic_mode) { - auto first = std::upper_bound(events->rbegin(), events->rend(), from_time, [=](uint64_t ts, auto &e) { return e->mono_time < ts; }); - auto msgs = fetchData(first, events->rend(), min_time); + auto first = std::upper_bound(events.rbegin(), events.rend(), CanEvent{.mono_time=from_time}, std::greater()); + auto msgs = fetchData(first, events.rend(), min_time); if (update_colors && (min_time > 0 || messages.empty())) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); @@ -162,10 +153,10 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti return msgs; } else { assert(min_time == 0); - auto first = std::upper_bound(events->begin(), events->end(), from_time, [=](uint64_t ts, auto &e) { return ts < e->mono_time; }); - auto msgs = fetchData(first, events->end(), 0); + auto first = std::upper_bound(events.begin(), events.end(), CanEvent{.mono_time=from_time}); + auto msgs = fetchData(first, events.end(), 0); if (update_colors) { - for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { + for (auto it = msgs.begin(); it != msgs.end(); ++it) { hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); it->colors = hex_colors.colors; } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 56ffe872d6..befbf270c6 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -446,15 +446,7 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe } void MainWindow::updateStatus() { - float cached_minutes = 0; - if (!can->liveStreaming()) { - if (auto events = can->events(); !events->empty()) { - cached_minutes = (events->back()->mono_time - events->front()->mono_time) / (1e9 * 60); - } - } else { - settings.max_cached_minutes = settings.max_cached_minutes; - } - status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(cached_minutes, 0, 'f', 1).arg(settings.fps)); + status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(settings.max_cached_minutes).arg(settings.fps)); } void MainWindow::dockCharts(bool dock) { diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index b4a7ed7b34..8dd0bac820 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -160,7 +160,7 @@ void MessageListModel::setFilterString(const QString &string) { filter_str = string; msgs.clear(); - for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { if (filter_str.isEmpty() || contains(it.key(), filter_str)) { msgs.push_back(it.key()); } @@ -206,8 +206,8 @@ void MessageListModel::sortMessages() { void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); - if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { - msgs = can->can_msgs.keys(); + if (filter_str.isEmpty() && msgs.size() != can->last_msgs.size()) { + msgs = can->last_msgs.keys(); } if (msgs.size() != prev_row_count) { sortMessages(); diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index c8ff449098..d60beed0c8 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,6 +1,5 @@ #include "tools/cabana/streams/abstractstream.h" #include -#include AbstractStream *can = nullptr; @@ -13,7 +12,7 @@ AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_liv void AbstractStream::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { - can_msgs[it.key()] = it.value(); + last_msgs[it.key()] = it.value(); } emit updated(); emit msgsReceived(messages); @@ -62,66 +61,68 @@ bool AbstractStream::updateEvent(const Event *event) { const CanData &AbstractStream::lastMessage(const MessageId &id) { static CanData empty_data; - auto it = can_msgs.find(id); - return it != can_msgs.end() ? it.value() : empty_data; + auto it = last_msgs.find(id); + return it != last_msgs.end() ? it.value() : empty_data; } -static QHash parseEvents(std::vector::const_reverse_iterator first, - std::vector::const_reverse_iterator last, double route_start_time) { - QHash msgs; - msgs.reserve(500); - for (auto it = first; it != last; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - auto &m = msgs[{.source = c.getSrc(), .address = c.getAddress()}]; - if (++m.count == 1) { - m.ts = ((*it)->mono_time / 1e9) - route_start_time; - m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); - m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); - m.last_change_t = QVector(m.dat.size(), m.ts); - m.bit_change_counts.resize(m.dat.size()); - } - } - } - } - return msgs; -}; - // it is thread safe to update data in updateLastMsgsTo. // updateEvent will not be called before replayStream::seekedTo return. void AbstractStream::updateLastMsgsTo(double sec) { - uint64_t ts = (sec + routeStartTime()) * 1e9; - const uint64_t delta = std::max(std::ceil(sec / std::thread::hardware_concurrency()), 30.0) * 1e9; - const auto evs = events(); - auto first = std::upper_bound(evs->crbegin(), evs->crend(), ts, [](uint64_t ts, auto &e) { return ts > e->mono_time; }); - QFutureSynchronizer> synchronizer; - while(first != evs->crend()) { - ts = (*first)->mono_time > delta ? (*first)->mono_time - delta : 0; - auto last = std::lower_bound(first, evs->crend(), ts, [](auto &e, uint64_t ts) { return e->mono_time > ts; }); - synchronizer.addFuture(QtConcurrent::run(parseEvents, first, last, routeStartTime())); - first = last; - } - synchronizer.waitForFinished(); - new_msgs->clear(); change_trackers.clear(); - can_msgs.clear(); + last_msgs.clear(); counters.clear(); - for (const auto &f : synchronizer.futures()) { - auto msgs = f.result(); - for (auto it = msgs.cbegin(); it != msgs.cend(); ++it) { - counters[it.key()] += it.value().count; - auto m = can_msgs.find(it.key()); - if (m == can_msgs.end()) { - m = can_msgs.insert(it.key(), it.value()); - } else { - m.value().count += it.value().count; - } - m.value().freq = m.value().count / std::max(1.0, m.value().ts); + + CanEvent last_event = {.mono_time = uint64_t((sec + routeStartTime()) * 1e9)}; + for (auto &[id, e] : events_) { + auto it = std::lower_bound(e.crbegin(), e.crend(), last_event, std::greater()); + if (it != e.crend()) { + auto &m = last_msgs[id]; + m.dat = QByteArray((const char *)it->dat, it->size); + m.ts = it->mono_time / 1e9 - routeStartTime(); + m.count = std::distance(it, e.crend()); + m.freq = m.count / std::max(1.0, m.ts); + m.last_change_t = QVector(m.dat.size(), m.ts); + m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); + m.bit_change_counts = QVector>(m.dat.size()); + counters[id] = m.count; } } QTimer::singleShot(0, [this]() { emit updated(); - emit msgsReceived(&can_msgs); + emit msgsReceived(&last_msgs); }); } + +void AbstractStream::parseEvents(std::unordered_map> &msgs, + std::vector::const_iterator first, std::vector::const_iterator last) { + for (; first != last; ++first) { + if ((*first)->which == cereal::Event::Which::CAN) { + for (const auto &c : (*first)->event.getCan()) { + auto dat = c.getDat(); + auto &m = msgs[{.source = c.getSrc(), .address = c.getAddress()}].emplace_back(); + m.size = std::min(dat.size(), std::size(m.dat)); + memcpy(m.dat, (uint8_t *)dat.begin(), m.size); + m.mono_time = (*first)->mono_time; + } + last_event_ts = std::max(last_event_ts, (*first)->mono_time); + } + } +} + +void AbstractStream::mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append) { + if (first == last) return; + + if (append) { + parseEvents(events_, first, last); + } else { + std::unordered_map> new_events; + parseEvents(new_events, first, last); + for (auto &[id, new_e] : new_events) { + auto &e = events_[id]; + auto it = std::upper_bound(e.cbegin(), e.cend(), new_e.front()); + e.insert(it, new_e.cbegin(), new_e.cend()); + } + } + emit eventsMerged(); +} diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index d1cf9d8037..3c7bdd6132 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -1,7 +1,8 @@ #pragma once #include - +#include +#include #include #include @@ -20,6 +21,14 @@ struct CanData { QVector> bit_change_counts; }; +struct CanEvent { + uint64_t mono_time; + uint8_t size; + uint8_t dat[64]; + inline bool operator<(const CanEvent &r) const { return mono_time < r.mono_time; } + inline bool operator>(const CanEvent &r) const { return mono_time > r.mono_time; } +}; + class AbstractStream : public QObject { Q_OBJECT @@ -27,6 +36,7 @@ public: AbstractStream(QObject *parent, bool is_live_streaming); virtual ~AbstractStream() {}; inline bool liveStreaming() const { return is_live_streaming; } + inline double lastEventSecond() const { return last_event_ts / 1e9 - routeStartTime(); } virtual void seekTo(double ts) {} virtual QString routeName() const = 0; virtual QString carFingerprint() const { return ""; } @@ -37,11 +47,12 @@ public: virtual const CanData &lastMessage(const MessageId &id); virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } virtual const Route *route() const { return nullptr; } - virtual const std::vector *events() const = 0; virtual void setSpeed(float speed) {} virtual bool isPaused() const { return false; } virtual void pause(bool pause) {} + const std::unordered_map> &events() const { return events_; } virtual const std::vector> getTimeline() { return {}; } + void mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append); signals: void paused(); @@ -55,19 +66,22 @@ signals: void sourcesUpdated(const QSet &s); public: - QHash can_msgs; + QHash last_msgs; QSet sources; protected: virtual void process(QHash *); bool updateEvent(const Event *event); void updateLastMsgsTo(double sec); + void parseEvents(std::unordered_map> &msgs, std::vector::const_iterator first, std::vector::const_iterator last); bool is_live_streaming = false; std::atomic processing = false; QHash counters; std::unique_ptr> new_msgs; QHash change_trackers; + std::unordered_map> events_; + uint64_t last_event_ts = 0; }; // A global pointer referring to the unique AbstractStream object diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 256cfc5a3e..62ad635152 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -52,7 +52,7 @@ void LiveStream::handleEvent(Event *evt) { auto it = std::upper_bound(received.cbegin(), received.cend(), current_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); - if (it != can_events.cend()) { + if (it != received.cend()) { bool skip = (nanos_since_boot() - last_update_ts) < ((*it)->mono_time - current_ts) / speed_; if (skip) return; @@ -68,16 +68,15 @@ void LiveStream::handleEvent(Event *evt) { void LiveStream::process(QHash *last_messages) { { std::lock_guard lk(lock); - uint64_t last_ts = can_events.empty() ? 0 : can_events.back()->mono_time; - auto first = std::upper_bound(received.cbegin(), received.cend(), last_ts, [](uint64_t ts, auto &e) { + auto first = std::upper_bound(received.cbegin(), received.cend(), last_event_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); - can_events.insert(can_events.end(), first, received.cend()); + mergeEvents(first, received.cend(), true); if (speed_ == 1) { received.clear(); + messages.clear(); } } - emit eventsMerged(); AbstractStream::process(last_messages); } diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 657d7e407f..598c0b9365 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -16,27 +16,23 @@ public: void setSpeed(float speed) override { speed_ = std::min(1.0, speed); } bool isPaused() const override { return pause_; } void pause(bool pause) override; - const std::vector *events() const override { return &can_events; } protected: - void process(QHash *) override; virtual void handleEvent(Event *evt); virtual void streamThread(); + void process(QHash *) override; struct Msg { Msg(Message *m) { event = ::new Event(aligned_buf.align(m)); delete m; } - ~Msg() { - ::delete event; - } + ~Msg() { ::delete event; } Event *event; AlignedBuffer aligned_buf; }; mutable std::mutex lock; - std::vector can_events; std::vector received; std::deque messages; std::atomic start_ts = 0; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index ebd969be61..140a795d3a 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -14,13 +14,24 @@ static bool event_filter(const Event *e, void *opaque) { return ((ReplayStream *)opaque)->eventFilter(e); } +void ReplayStream::mergeSegments() { + for (auto &[n, seg] : replay->segments()) { + if (seg && seg->isLoaded() && !processed_segments.count(n)) { + const auto &events = seg->log->events; + bool append = processed_segments.empty() || *processed_segments.rbegin() < n; + processed_segments.insert(n); + mergeEvents(events.cbegin(), events.cend(), append); + } + } +} + bool ReplayStream::loadRoute(const QString &route, const QString &data_dir) { 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); - QObject::connect(replay.get(), &Replay::segmentsMerged, this, &AbstractStream::eventsMerged); QObject::connect(replay.get(), &Replay::streamStarted, this, &AbstractStream::streamStarted); + QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments); if (replay->load()) { const auto &segments = replay->route()->segments(); if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 3505f6abf4..6fc61f7f36 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -20,13 +20,14 @@ public: inline double currentSec() const override { return replay->currentSeconds(); } inline QDateTime currentDateTime() const override { return replay->currentDateTime(); } inline const Route *route() const override { return replay->route(); } - inline const std::vector *events() const override { return replay->events(); } inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; inline const std::vector> getTimeline() override { return replay->getTimeline(); } private: + void mergeSegments(); std::unique_ptr replay = nullptr; uint32_t replay_flags = REPLAY_FLAG_NONE; + std::set processed_segments; }; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 7768359df4..ffd0df0501 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -19,7 +19,7 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi QHBoxLayout *form_layout = new QHBoxLayout(); bus_combo = new QComboBox(this); QSet bus_set; - for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { bus_set << it.key().source; } for (uint8_t bus : bus_set) { @@ -102,29 +102,24 @@ void FindSimilarBitsDlg::find() { QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt) { QHash> mismatches; QHash msg_count; - auto events = can->events(); int bit_to_find = -1; - for (auto e : *events) { - if (e->which == cereal::Event::Which::CAN) { - for (const auto &c : e->event.getCan()) { - if (c.getSrc() == bus) { - const auto dat = c.getDat(); - uint32_t address = c.getAddress(); - if (address == selected_address && dat.size() > byte_idx) { - bit_to_find = ((dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; - } - ++msg_count[address]; - if (bit_to_find == -1) continue; + for (const auto &[id, msg] : can->events()) { + if (id.source == bus) { + for (const auto &c : msg) { + if (id.address == selected_address && c.size > byte_idx) { + bit_to_find = ((c.dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + } + ++msg_count[id.address]; + if (bit_to_find == -1) continue; - auto &mismatched = mismatches[address]; - if (mismatched.size() < dat.size() * 8) { - mismatched.resize(dat.size() * 8); - } - for (int i = 0; i < dat.size(); ++i) { - for (int j = 0; j < 8; ++j) { - int bit = ((dat[i] >> (7 - j)) & 1) != 0; - mismatched[i * 8 + j] += (bit != bit_to_find); - } + auto &mismatched = mismatches[id.address]; + if (mismatched.size() < c.size * 8) { + mismatched.resize(c.size * 8); + } + for (int i = 0; i < c.size; ++i) { + for (int j = 0; j < 8; ++j) { + int bit = ((c.dat[i] >> (7 - j)) & 1) != 0; + mismatched[i * 8 + j] += (bit != bit_to_find); } } } diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 6788a97d03..2bb426361b 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -71,6 +71,7 @@ public: inline void setSpeed(float speed) { speed_ = speed; } inline float getSpeed() const { return speed_; } inline const std::vector *events() const { return events_.get(); } + inline const std::map> &segments() const { return segments_; }; inline const std::string &carFingerprint() const { return car_fingerprint_; } inline const std::vector> getTimeline() { std::lock_guard lk(timeline_lock); From d8a55de1669704e7a847c346f715d0659d54e9ca Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Mar 2023 07:14:43 +0800 Subject: [PATCH 031/143] ui: remove lupdate warnings: "Qualifying with unknown namespace" (#27616) --- selfdrive/ui/update_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/update_translations.py b/selfdrive/ui/update_translations.py index e15d4c3433..5964eb49dc 100755 --- a/selfdrive/ui/update_translations.py +++ b/selfdrive/ui/update_translations.py @@ -19,7 +19,7 @@ def update_translations(vanish=False, plural_only=None, translations_dir=TRANSLA for file in translation_files.values(): tr_file = os.path.join(translations_dir, f"{file}.ts") - args = f"lupdate -locations none -recursive {UI_DIR} -ts {tr_file}" + args = f"lupdate -locations none -recursive {UI_DIR} -ts {tr_file} -I {BASEDIR}" if vanish: args += " -no-obsolete" if file in plural_only: From 455d76cdb6d06d85171bc252a06517d5432b6c68 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 Mar 2023 16:17:42 -0700 Subject: [PATCH 032/143] manager: log time with exit param (#27615) * manager: log time with exit param * fix double brackets --- selfdrive/manager/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 1128097251..1b10cee806 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -153,7 +153,7 @@ def manager_thread() -> None: for param in ("DoUninstall", "DoShutdown", "DoReboot"): if params.get_bool(param): shutdown = True - params.put("LastManagerExitReason", param) + params.put("LastManagerExitReason", f"{param} {datetime.datetime.now()}") cloudlog.warning(f"Shutting down manager - {param} set") if shutdown: From 741d26b0255b806fce545b987b52e7a21c5a5d14 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Mar 2023 07:18:38 +0800 Subject: [PATCH 033/143] cabana: set min-max values from size when creating a new signal. (#27589) --- tools/cabana/signaledit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 673a68a50b..d91f6c1401 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -245,7 +245,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { } } - cabana::Signal sig = {.is_little_endian = little_endian, .factor = 1}; + cabana::Signal sig = {.is_little_endian = little_endian, .factor = 1, .min = "0", .max = QString::number(std::pow(2, size) - 1)}; for (int i = 1; /**/; ++i) { sig.name = QString("NEW_SIGNAL_%1").arg(i); if (msg->sig(sig.name) == nullptr) break; From 4718fa574813b966557e453f25ab65a56fbce8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 17 Mar 2023 16:39:44 -0700 Subject: [PATCH 034/143] Bump laika (#27618) * Laika on master * use constellation id --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/laika_repo b/laika_repo index 719c79a156..6fadabd860 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed +Subproject commit 6fadabd86043ee19e06c6ed59aa4e688c14fa8e4 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 3698867ec9..87b0cf9291 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -72,7 +72,7 @@ def get_log_eph_source(ephem): class Laikad: - def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, + def __init__(self, valid_const=(ConstellationId.GPS, ConstellationId.GLONASS), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), save_ephemeris=False, use_qcom=False): """ From 529ba41825c3d47ee6f322ddecc8471d8e0cdd3a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 19 Mar 2023 05:34:11 +0800 Subject: [PATCH 035/143] cabana: display zoom range while dragging rubber-band selection (#27620) --- tools/cabana/chartswidget.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 04734e6749..09fcbf2ee2 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -666,6 +666,8 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } else if ((max_rounded - min_rounded) >= 0.5) { // zoom in if selected range is greater than 0.5s emit zoomIn(min_rounded, max_rounded); + } else { + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } event->accept(); } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { @@ -738,6 +740,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (rubber_rect != rubber->geometry()) { rubber->setGeometry(rubber_rect); } + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } } @@ -804,6 +807,21 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } } + + // paint zoom range + auto rubber = findChild(); + if (rubber && rubber->isVisible() && rubber->width() > 1) { + painter->setPen(Qt::white); + auto rubber_rect = rubber->geometry().normalized(); + for (const auto &pt : {rubber_rect.bottomLeft(), rubber_rect.bottomRight()}) { + QString sec = QString::number(chart()->mapToValue(pt).x(), 'f', 1); + // ChartAxisElement's padding is 4 (https://codebrowser.dev/qt5/qtcharts/src/charts/axis/chartaxiselement_p.h.html) + auto r = painter->fontMetrics().boundingRect(sec).adjusted(-6, -4, 6, 4); + pt == rubber_rect.bottomLeft() ? r.moveTopRight(pt + QPoint{0, 2}) : r.moveTopLeft(pt + QPoint{0, 2}); + painter->fillRect(r, Qt::gray); + painter->drawText(r, Qt::AlignCenter, sec); + } + } } QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { From 5e269b25c470b73cd4a413d10d89c1f74584b41f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 Mar 2023 20:03:00 -0700 Subject: [PATCH 036/143] plotjuggler: update controls mismatch layout --- .../layouts/controls_mismatch_debug.xml | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/tools/plotjuggler/layouts/controls_mismatch_debug.xml b/tools/plotjuggler/layouts/controls_mismatch_debug.xml index adca3eed29..54586d6e7b 100644 --- a/tools/plotjuggler/layouts/controls_mismatch_debug.xml +++ b/tools/plotjuggler/layouts/controls_mismatch_debug.xml @@ -1,37 +1,44 @@ - + - + - - + + - - + + - - + + - + - - + + - + - - + + - - + + + + + + + + + @@ -46,8 +53,8 @@ - - + + From ae423a68686ca258c40fa679b931011e99f5f780 Mon Sep 17 00:00:00 2001 From: koch-cf <62287055+koch-cf@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:10:19 -0400 Subject: [PATCH 037/143] GM: Buick LaCrosse 2017-19 support (#27332) * Added Buick LaCrosse 2017 * Added Buick LaCrosse as candidate * Added Buick LaCrosse CAR_INFO and Fingerprint * Added Buick LaCrosse to non_tested_cars * Added Buick LaCrosse * Updated number of supported cars to 237 * Added ACC and LKAS description to Buick LaCrosse * Updated CAR_INFO for Buick LaCrosse * Added the Escalade which was recently updated * Update selfdrive/car/gm/values.py Suggested fingerprint by @sshane Co-authored-by: Shane Smiskol * Premium is a trim with ACC. Use package name instead * lacrosse custom FF; fit info: describe(steer_offsets) = DescribeResult(nobs=1649402, minmax=(-0.7127894163131714, 5.3997602462768555), mean=3.3090523060153645, variance=0.3130325564084465, skewness=-1.5986155151533736, kurtosis=8.18810418298873) Samples: 1357787 Regularizing... Regularized samples: 1140 speed: DescribeResult(nobs=1140, minmax=(8.478170424241286, 35.837870224662446), mean=27.888804767013475, variance=34.16742353763829, skewness=-1.068587303119431, kurtosis=0.6193071765927134) angle: DescribeResult(nobs=1140, minmax=(-21.057768565637094, 28.516874490999708), mean=-0.4328602593886506, variance=43.19046813273241, skewness=0.001966426701503317, kurtosis=0.20547357649038434) steer: DescribeResult(nobs=1140, minmax=(-0.8432471203007578, 0.9634959333674695), mean=-0.021981142946747863, variance=0.20152217060233915, skewness=0.03202313890158864, kurtosis=-1.2318826088567174) Performing fit... Fit: [5.85397825e-01 3.27650818e-01 4.60531117e-03 1.32307599e+01 1.37194709e-01 1.33099557e-01 6.14782304e-02] ANGLE_COEF = 0.58539783 ANGLE_COEF2 = 0.32765082 ANGLE_OFFSET = 0.00460531 SPEED_OFFSET = 13.23075991 SIGMOID_COEF_RIGHT = 0.13719471 SIGMOID_COEF_LEFT = 0.13309956 SPEED_COEF = 0.06147823 MAE old 0.2098, new 0.0309 STD old 0.1021, new 0.0273 deg 00-03:457, deg 03-06:258, deg 06-09:218, deg 09-12:132, deg 12-15:62 deg 15-18:6, deg 18-21:4, deg 21-24:1, deg 24-27:0, deg 27-30:2 deg 30-33:0, deg 33-36:0, deg 36-39:0, deg 39-42:0, deg 42-45:0 mph 10-15:0, mph 15-20:1, mph 20-25:18, mph 25-30:12, mph 30-35:30 mph 35-40:26, mph 40-45:52, mph 45-50:54, mph 50-55:73, mph 55-60:86 mph 60-65:204, mph 65-70:228, mph 70-75:179, mph 75-80:176, mph 80-85:1 mph 85-90:0, * Update routes.py * remove from non tested routes * use torque controller * update docs * update releases --------- Co-authored-by: Shane Smiskol Co-authored-by: Tim Wilson --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/gm/interface.py | 7 +++++++ selfdrive/car/gm/values.py | 7 +++++++ selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 9cfcbafea1..55b0dbad7e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,7 @@ Version 0.9.2 (2023-03-XX) ======================== * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. +* Buick LaCrosse 2017-19 support thanks to koch-cf! * Škoda Fabia 2022-23 support thanks to jyoung8607! Version 0.9.1 (2023-02-28) diff --git a/docs/CARS.md b/docs/CARS.md index 070d068cab..c4a3cedfe0 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 238 Supported Cars +# 239 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -17,6 +17,7 @@ A supported vehicle is one that just works when you install a comma three. All s |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)](##)|J533|| |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)](##)|J533|| |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)](##)|J533|| +|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)](##)|OBD-II|| |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)](##)|OBD-II|| |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)](##)|OBD-II|| |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)](##)|GM|| diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 7e6e71c642..602d7e31b6 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -150,6 +150,13 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia() ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking + elif candidate == CAR.BUICK_LACROSSE: + ret.mass = 1712. + STD_CARGO_KG + ret.wheelbase = 2.91 + ret.steerRatio = 15.8 + ret.centerToFront = ret.wheelbase * 0.4 # wild guess + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.BUICK_REGAL: ret.mass = 3779. * CV.LB_TO_KG + STD_CARGO_KG # (3849+3708)/2 ret.wheelbase = 2.83 # 111.4 inches in meters diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 2ac418b629..0d13cb9827 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -66,6 +66,7 @@ class CAR: CADILLAC_ATS = "CADILLAC ATS Premium Performance 2018" MALIBU = "CHEVROLET MALIBU PREMIER 2017" ACADIA = "GMC ACADIA DENALI 2018" + BUICK_LACROSSE = "BUICK LACROSSE 2017" BUICK_REGAL = "BUICK REGAL ESSENCE 2018" ESCALADE = "CADILLAC ESCALADE 2017" ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016" @@ -99,6 +100,7 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"), CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), + CAR.BUICK_LACROSSE: GMCarInfo("Buick LaCrosse 2017-19", "Driver Confidence Package 2"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.ESCALADE: GMCarInfo("Cadillac Escalade 2017", "Driver Assist Package"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), @@ -156,6 +158,11 @@ FINGERPRINTS = { { 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 368: 8, 381: 2, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 5, 844: 8, 853: 8, 866: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7 }], + CAR.BUICK_LACROSSE: [ + # LaCrosse Premium AWD 2017 + { + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 + }], CAR.BUICK_REGAL : [ # Regal TourX Essence w/ ACC 2018 { diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 2c4ec84e86..4dd19d24e3 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -52,6 +52,7 @@ routes = [ CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA), CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL), + CarTestRoute("75a6bcb9b8b40373|2023-03-11--22-47-33", GM.BUICK_LACROSSE), CarTestRoute("ef8f2185104d862e|2023-02-09--18-37-13", GM.ESCALADE), CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV), CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 696d9829d1..5feef12206 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -50,6 +50,7 @@ HONDA CIVIC SEDAN 1.6 DIESEL 2019: HONDA CIVIC (BOSCH) 2019 HONDA E 2020: HONDA CIVIC (BOSCH) 2019 HONDA ODYSSEY CHN 2019: HONDA ODYSSEY 2018 +BUICK LACROSSE 2017: CHEVROLET VOLT PREMIER 2017 BUICK REGAL ESSENCE 2018: CHEVROLET VOLT PREMIER 2017 CADILLAC ESCALADE ESV 2016: CHEVROLET VOLT PREMIER 2017 CADILLAC ATS Premium Performance 2018: CHEVROLET VOLT PREMIER 2017 From bfbfdb28519a6da890569d30dfa325df53a7ef22 Mon Sep 17 00:00:00 2001 From: tonzy74 <69013596+tonzy74@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:18:07 -0400 Subject: [PATCH 038/143] Kia: Sorento 2021 support (#27623) * Update values.py * Update selfdrive/car/hyundai/values.py * update docs --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c4a3cedfe0..a7b6764f0c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -117,7 +117,7 @@ A supported vehicle is one that just works when you install a comma three. All s |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)](##)|Hyundai A|| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Kia|Sorento 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)](##)|Hyundai K|| +|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)](##)|Hyundai K|| |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)](##)|Hyundai A|| |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)](##)|Hyundai N|| |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)](##)|Hyundai N|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index f7cedf550e..09114512b0 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -224,7 +224,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), ], - CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2022-23", harness=Harness.hyundai_k), + CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", harness=Harness.hyundai_k), CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", harness=Harness.hyundai_a), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), @@ -1637,9 +1637,11 @@ FW_VERSIONS = { CAR.KIA_SORENTO_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.05 99210-R5000 210623', + b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.03 99210-R5000 200903', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ', + b'\xf1\x00MQ4_ SCC F-CUP 1.00 1.06 99110-P2000 ', ], }, CAR.KIA_NIRO_HEV_2ND_GEN: { From e5069058f0291c1a285ae530d57f4cf0a9813b84 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Tue, 21 Mar 2023 05:21:59 +0900 Subject: [PATCH 039/143] Kia: add missing Korean EV6 fwdCamera FW (#27621) * add EV6 kor camera fw * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 09114512b0..06f2e27876 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1552,6 +1552,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630', + b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823', ], }, CAR.IONIQ_5: { From 744f1e4f5764146927b830c34cd11ef9b67ecc2c Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:22:50 -0500 Subject: [PATCH 040/143] Add missing CAMRY_TSS2 engine & fwdCamera f/w (#27619) `ChromeNinja#0001` 2023 Camry ICE DongleID/route a9c072de54f9194d|2023-03-17--17-24-56 --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 965a9e6506..4edafc0c28 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -542,6 +542,7 @@ FW_VERSIONS = { (Ecu.engine, 0x700, None): [ b'\x018966306Q5000\x00\x00\x00\x00', b'\x018966306Q9000\x00\x00\x00\x00', + b'\x018966306R3000\x00\x00\x00\x00', b'\x018966306T3100\x00\x00\x00\x00', b'\x018966306T3200\x00\x00\x00\x00', b'\x018966306T4000\x00\x00\x00\x00', @@ -557,6 +558,7 @@ FW_VERSIONS = { b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', + b'\x028646F3305500\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.CAMRYH_TSS2: { From fa01a8e6b37aa76636fa314670657b7258f272d7 Mon Sep 17 00:00:00 2001 From: Luqi Pan Date: Mon, 20 Mar 2023 13:24:41 -0700 Subject: [PATCH 041/143] Add fwd camera value for 2023 GV60 Advanced (#27617) --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 06f2e27876..88e952567c 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1630,6 +1630,7 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215', b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU000 211215', + b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.03 99211-CU000 221118', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ', From 285204c5d1e83944d69dc7126c7c1d7e7921f9a2 Mon Sep 17 00:00:00 2001 From: cpaioletti <65311022+cpaioletti@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:28:52 -0400 Subject: [PATCH 042/143] Kia: add missing fwdCamera for Niro HEV 2023 (#27557) * Update values.py for 2023 Kia Niro HEV {'carParams': {'alternativeExperience': 0, 'autoResumeSng': True, 'carFingerprint': 'mock', 'carFw': [{'address': 2004, 'brand': 'hyundai', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'\xf1\x00SG2 MDPS C 1.00 1.06 56310AT050\x00 4SG2C106', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2012, 'subAddress': 0}, {'address': 2000, 'brand': 'hyundai', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2008, 'subAddress': 0}, {'address': 2017, 'brand': 'hyundai', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'\xf1\x00PSBG2552 D121049\x00\x00\x00DSG2G16XXH049NS6MC\xe3x', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 1988, 'brand': 'hyundai', 'bus': 1, 'ecu': 'fwdCamera', 'fwVersion': b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 1996, 'subAddress': 0}, {'address': 2016, 'brand': 'hyundai', 'bus': 1, 'ecu': 'engine', 'fwVersion': b'\xf1\x87391S3-08AF0\xf1\x81HM6M7_0a0_D00', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2024, 'subAddress': 0}, {'address': 2000, 'brand': 'hyundai', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'\xf1\x8799110AT000\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2008, 'subAddress': 0}, {'address': 2004, 'brand': 'hyundai', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'\xf1\x8756310AT050\x00\xf1\x00SG2 MDPS C 1.00 1.06 56310AT050\x00 4SG2C106', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2012, 'subAddress': 0}, {'address': 2017, 'brand': 'hyundai', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'\xf1\x8795441-2BGJ0\x00\xf1\x81D121049\x00\x00\x00\xf1\x00PSBG2552 D121049\x00\x00\x00DSG2G16XXH049NS6' b'MC\xe3x', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 2000, 'brand': 'hyundai', 'bus': 4, 'ecu': 'fwdRadar', 'fwVersion': b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2008, 'subAddress': 0}, {'address': 1975, 'brand': 'hyundai', 'bus': 4, 'ecu': 'cornerRadar', 'fwVersion': b'\xf1\x00SG2 BCW RR 1.01 , 1.04 (wQ\x83"\x02\x01\x03@', 'logging': True, 'request': [b'"\xf1\x00'], 'responseAddress': 1983, 'subAddress': 0}, {'address': 1988, 'brand': 'hyundai', 'bus': 4, 'ecu': 'fwdCamera', 'fwVersion': b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 1996, 'subAddress': 0}, {'address': 2017, 'brand': 'mazda', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'D121049\x00\x00\x00', 'logging': False, 'request': [b'"\xf1\x88'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 2016, 'brand': 'subaru', 'bus': 1, 'ecu': 'engine', 'fwVersion': b'0TD23N6HGXD00\x00', 'logging': False, 'request': [b'>\x00', b'"\xf1\x82'], 'responseAddress': 2024, 'subAddress': 0}, {'address': 2017, 'brand': 'subaru', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'DSG2G16XXH049NS6', 'logging': False, 'request': [b'>\x00', b'"\xf1\x82'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 2016, 'brand': 'volkswagen', 'bus': 1, 'ecu': 'engine', 'fwVersion': b'\xf1\x87391S3-08AF0\xf1\x820TD23N6HGXD00\x00', 'logging': False, 'request': [b'"\xf1\x87\xf1\x89\xf1\x82'], 'responseAddress': 2024, 'subAddress': 0}, {'address': 2017, 'brand': 'volkswagen', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'\xf1\x8795441-2BGJ0\x00\xf1\x89D121049\x00\x00\x00\xf1\x82DSG2G16XXH049NS6', 'logging': False, 'request': [b'"\xf1\x87\xf1\x89\xf1\x82'], 'responseAddress': 2025, 'subAddress': 0}], * Update values.py to add missing comma Added missing comma to Line 1659 to fix previous new firmware additions for 2023 Kia Niro Hybrid * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 88e952567c..49e4ce033d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1649,6 +1649,7 @@ FW_VERSIONS = { CAR.KIA_NIRO_HEV_2ND_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.08 99211-AT000 220531', + b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', From f9c112e9b87530c463e2b10cac7bf7440d7c32d9 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:31:50 -0400 Subject: [PATCH 043/143] Hyundai: add Sonata FW version to enable radar tracks (#27463) --- selfdrive/debug/hyundai_enable_radar_points.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/debug/hyundai_enable_radar_points.py b/selfdrive/debug/hyundai_enable_radar_points.py index 07ce5ebddb..3a0ff33cb6 100755 --- a/selfdrive/debug/hyundai_enable_radar_points.py +++ b/selfdrive/debug/hyundai_enable_radar_points.py @@ -32,6 +32,9 @@ SUPPORTED_FW_VERSIONS = { b"DN8_ SCC FHCUP 1.00 1.00 99110-L0000\x19\x08)\x15T ": ConfigValues( default_config=b"\x00\x00\x00\x01\x00\x00", tracks_enabled=b"\x00\x00\x00\x01\x00\x01"), + b"DN8_ SCC F-CUP 1.00 1.00 99110-L0000\x19\x08)\x15T ": ConfigValues( + default_config=b"\x00\x00\x00\x01\x00\x00", + tracks_enabled=b"\x00\x00\x00\x01\x00\x01"), # 2021 SONATA HYBRID b"DNhe SCC FHCUP 1.00 1.02 99110-L5000 \x01#\x15# ": ConfigValues( default_config=b"\x00\x00\x00\x01\x00\x00", From aa0421ffd7dd73976b45635cb62182d66c4f1613 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Mar 2023 21:20:35 -0700 Subject: [PATCH 044/143] Chrysler: add FW for 2023 Ram 1500 (#27634) add FW for 2023 Ram 1500 --- docs/CARS.md | 2 +- selfdrive/car/chrysler/values.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a7b6764f0c..1f668dbe8b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -149,7 +149,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| -|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|| +|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)](##)|Ram|| |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)](##)|J533|| |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)](##)|J533|| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 9f00484f34..951e5d7347 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -73,7 +73,7 @@ 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-22", harness=Harness.ram), + CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", harness=Harness.ram), CAR.RAM_HD: [ ChryslerCarInfo("Ram 2500 2020-22", harness=Harness.ram), ChryslerCarInfo("Ram 3500 2020-22", harness=Harness.ram), @@ -187,12 +187,14 @@ FW_VERSIONS = { b'68434860AC', b'68527375AD', b'68453503AC', + b'68510283AG', ], (Ecu.srs, 0x744, None): [ b'68441329AB', b'68490898AA', b'68428609AB', b'68500728AA', + b'68615033AA', ], (Ecu.abs, 0x747, None): [ b'68432418AD', @@ -202,6 +204,7 @@ FW_VERSIONS = { b'68436004AD', b'68535469AB', b'68438454AC', + b'68586307AB', ], (Ecu.fwdRadar, 0x753, None): [ b'68320950AL', @@ -210,17 +213,20 @@ FW_VERSIONS = { b'68475160AG', b'04672892AB', b'68475160AE', + b'04672932AB', ], (Ecu.eps, 0x75A, None): [ b'68273275AG', b'68469901AA', b'68552788AA', + b'68585112AB', ], (Ecu.engine, 0x7e0, None): [ b'68448163AJ', b'68500630AD', b'68539650AD', b'68378758AM ', + b'05036066AE ', ], (Ecu.transmission, 0x7e1, None): [ b'68360078AL', From 4a844078cd675ca2c75d822f5d776ca8b0b71dbf Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Mar 2023 21:39:06 -0700 Subject: [PATCH 045/143] Chrysler: add FW for 2019 Ram 3500 (#27636) * Add 2019 Ram 3500 * wrong ones * missing EPS --- selfdrive/car/chrysler/values.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 951e5d7347..b2fb1e83bc 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -76,7 +76,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", harness=Harness.ram), CAR.RAM_HD: [ ChryslerCarInfo("Ram 2500 2020-22", harness=Harness.ram), - ChryslerCarInfo("Ram 3500 2020-22", harness=Harness.ram), + ChryslerCarInfo("Ram 3500 2019-22", harness=Harness.ram), ], } @@ -260,6 +260,7 @@ FW_VERSIONS = { b'04672895AB', b'56029827AG', b'68484694AE', + b'56029827AH', ], (Ecu.eps, 0x761, None): [ b'68421036AC', From aa4286153a2fb2a003307a15fbcb91ffd05d6ec2 Mon Sep 17 00:00:00 2001 From: realfast Date: Tue, 21 Mar 2023 00:54:55 -0500 Subject: [PATCH 046/143] Ram: FW version dump (#27083) * Add extra firmwares and sort for rams * Added another ECU * Update selfdrive/car/chrysler/values.py Co-authored-by: Shane Smiskol * Apply suggestions from code review * sort * formatting --------- Co-authored-by: Shane Smiskol --- selfdrive/car/chrysler/values.py | 87 +++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index b2fb1e83bc..984f92b5aa 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -50,6 +50,7 @@ class CarControllerParams: self.STEER_DELTA_DOWN = 3 self.STEER_MAX = 261 # higher than this faults the EPS + STEER_THRESHOLD = 120 RAM_DT = {CAR.RAM_1500, } @@ -62,6 +63,7 @@ class ChryslerCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC)" harness: Enum = Harness.fca + CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { CAR.PACIFICA_2017_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2017-18"), CAR.PACIFICA_2018_HYBRID: None, # same platforms @@ -182,92 +184,141 @@ FW_QUERY_CONFIG = FwQueryConfig( FW_VERSIONS = { CAR.RAM_1500: { (Ecu.combinationMeter, 0x742, None): [ - b'68294063AH', + b'68294051AG', + b'68294051AI', + b'68294052AG', b'68294063AG', + b'68294063AH', + b'68294063AI', + b'68434846AC', + b'68434858AC', b'68434860AC', - b'68527375AD', b'68453503AC', + b'68453505AC', + b'68453511AC', + b'68453513AD', + b'68453514AD', b'68510283AG', + b'68527375AD', ], (Ecu.srs, 0x744, None): [ + b'68428609AB', b'68441329AB', + b'68473844AB', b'68490898AA', - b'68428609AB', b'68500728AA', b'68615033AA', ], (Ecu.abs, 0x747, None): [ - b'68432418AD', + b'68292406AH', b'68432418AB', + b'68432418AD', + b'68436004AD', b'68436004AE', + b'68438454AC', b'68438454AD', - b'68436004AD', + b'68438456AE', + b'68438456AF', b'68535469AB', - b'68438454AC', + b'68535470AC', b'68586307AB', ], (Ecu.fwdRadar, 0x753, None): [ - b'68320950AL', + b'04672892AB', + b'04672932AB', + b'68320950AH', + b'68320950AI', b'68320950AJ', + b'68320950AL', + b'68320950AM', b'68454268AB', - b'68475160AG', - b'04672892AB', b'68475160AE', - b'04672932AB', + b'68475160AF', + b'68475160AG', ], (Ecu.eps, 0x75A, None): [ + b'68273275AF', b'68273275AG', + b'68312176AE', + b'68312176AG', + b'68440789AC', + b'68466110AB', b'68469901AA', + b'68522583AB', + b'68522585AB', b'68552788AA', + b'68552790AA', b'68585112AB', ], (Ecu.engine, 0x7e0, None): [ + b'05036065AE ', + b'05036066AE ', + b'68378701AI ', + b'68378758AM ', b'68448163AJ', + b'68448165AK', b'68500630AD', + b'68500630AE', b'68539650AD', - b'68378758AM ', - b'05036066AE ', ], (Ecu.transmission, 0x7e1, None): [ b'68360078AL', - b'68384328AD', - b'68360085AL', + b'68360080AM', b'68360081AM', - b'68502994AD', + b'68360085AL', + b'68384328AD', + b'68384332AD', b'68445533AB', - b'68540431AB', b'68484467AC', + b'68502994AD', + b'68540431AB', ], }, CAR.RAM_HD: { (Ecu.combinationMeter, 0x742, None): [ b'68361606AH', + b'68437735AC', b'68492693AD', + b'68525485AB', + b'68525487AB', + b'68525498AB', ], (Ecu.srs, 0x744, None): [ b'68399794AC', b'68428503AA', b'68428505AA', + b'68428507AA', ], (Ecu.abs, 0x747, None): [ b'68334977AH', + b'68455481AC', + b'68504022AA', b'68504022AB', - b'68530686AB', b'68504022AC', + b'68530686AB', + b'68530686AC', ], (Ecu.fwdRadar, 0x753, None): [ b'04672895AB', b'56029827AG', - b'68484694AE', b'56029827AH', + b'68462657AE', + b'68484694AD', + b'68484694AE', ], (Ecu.eps, 0x761, None): [ b'68421036AC', b'68507906AB', ], (Ecu.engine, 0x7e0, None): [ + b'52370131AF', + b'52370231AF', + b'52370231AG', + b'52370931CT', + b'52401032AE', b'52421132AF', + b'68527616AD ', b'M2370131MB', b'M2421132MB', ], From e0ac5a940e8a57d140478d11e66b3485cddee3ab Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 11:25:36 -0700 Subject: [PATCH 047/143] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index e4cc97d882..d70fa4e120 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e4cc97d8826dc95a7833b859c36948302445a499 +Subproject commit d70fa4e1200ad47c66587c78fd90030a3be1cc43 From ee36c106af73b34819764ac7d23721981d387d88 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 16:14:22 -0700 Subject: [PATCH 048/143] process replay: update after laika publish policy change (#27647) * laika pubs all * lr for locationd * fix locationd qcom * update refs --- .../test/process_replay/process_replay.py | 30 ++++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 971ddb3fe2..f547fce0bc 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -248,15 +248,6 @@ def ublox_rcv_callback(msg): return [] -def laika_rcv_callback(msg, CP, cfg, fsm): - if msg.which() == 'ubloxGnss' and msg.ubloxGnss.which() == "measurementReport": - return ["gnssMeasurements"], True - elif msg.which() == 'qcomGnss' and msg.qcomGnss.which() == "drMeasurementReport": - return ["gnssMeasurements"], True - else: - return [], False - - CONFIGS = [ ProcessConfig( proc_name="controlsd", @@ -331,7 +322,7 @@ CONFIGS = [ pub_sub={ "cameraOdometry": ["liveLocationKalman"], "accelerometer": [], "gyroscope": [], - "gpsLocationExternal": [], "liveCalibration": [], "carState": [], + "gpsLocationExternal": [], "liveCalibration": [], "carState": [], "gpsLocation": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, @@ -371,7 +362,7 @@ CONFIGS = [ }, ignore=["logMonoTime"], init_callback=get_car_params, - should_recv_callback=laika_rcv_callback, + should_recv_callback=None, tolerance=NUMPY_TOLERANCE, fake_pubsubmaster=True, ), @@ -398,7 +389,7 @@ def replay_process(cfg, lr, fingerprint=None): return cpp_replay_process(cfg, lr, fingerprint) -def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): +def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): params = Params() params.clear_all() params.put_bool("OpenpilotEnabledToggle", True) @@ -406,7 +397,6 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): params.put_bool("DisengageOnAccelerator", True) params.put_bool("WideCameraOnly", False) params.put_bool("DisableLogging", False) - params.put_bool("UbloxAvailable", True) params.put_bool("ObdMultiplexingDisabled", True) os.environ["NO_RADAR_SLEEP"] = "1" @@ -414,6 +404,10 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): os.environ['SKIP_FW_QUERY'] = "" os.environ['FINGERPRINT'] = "" + if lr is not None: + services = {m.which() for m in lr} + params.put_bool("UbloxAvailable", "ubloxGnss" in services) + if cfg is not None: # Clear all custom processConfig environment variables for config in CONFIGS: @@ -485,10 +479,10 @@ def python_replay_process(cfg, lr, fingerprint=None): if fingerprint is not None: os.environ['SKIP_FW_QUERY'] = "1" os.environ['FINGERPRINT'] = fingerprint - setup_env(cfg=cfg, controlsState=controlsState) + 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) + 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() @@ -517,7 +511,7 @@ def python_replay_process(cfg, lr, fingerprint=None): recv_socks, 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) % int(service_list[msg.which()].frequency / service_list[s].frequency) == 0] + (fsm.frame + 1) % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0] should_recv = bool(len(recv_socks)) if msg.which() == 'can': @@ -549,14 +543,14 @@ def cpp_replay_process(cfg, lr, fingerprint=None): log_msgs = [] # We need to fake SubMaster alive since we can't inject a fake clock - setup_env(simulation=True, cfg=cfg) + setup_env(simulation=True, cfg=cfg, lr=lr) managed_processes[cfg.proc_name].prepare() managed_processes[cfg.proc_name].start() try: with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}"): - while not all(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): + while not any(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): time.sleep(0) # Make sure all subscribers are connected diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index cbe2a016ce..cf19e9cb07 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5775220ec2e62dcdedb92d96270f1380bbd88c39 +30128f043985c8a793cdca2ad9ea1039c5086d72 \ No newline at end of file From 7319afbd516ea1b32736d67d8c5be7663dce9ae3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 16:43:40 -0700 Subject: [PATCH 049/143] process replay: prep for laikad subsock + QCOM GPS (#27632) * process replay: prep for laikad subsock * cleanup * fix for qcomGnss * detect ublox * more debug info in err * wip * cleanup --- selfdrive/locationd/laikad.py | 4 +- .../test/process_replay/process_replay.py | 78 ++++++++++--------- .../test/process_replay/test_processes.py | 11 ++- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 87b0cf9291..be272f1774 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -420,11 +420,11 @@ def clear_tmp_cache(): os.mkdir(DOWNLOADS_CACHE_FOLDER) -def main(sm=None, pm=None, qc=None): +def main(sm=None, pm=None): #clear_tmp_cache() use_qcom = not Params().get_bool("UbloxAvailable", block=True) - if use_qcom or (qc is not None and qc): + if use_qcom: raw_gnss_socket = "qcomGnss" else: raw_gnss_socket = "ubloxGnss" diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index f547fce0bc..9c0225796d 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -238,14 +238,14 @@ def torqued_rcv_callback(msg, CP, cfg, fsm): return recv_socks, fsm.frame == 0 or msg.which() == 'liveLocationKalman' -def ublox_rcv_callback(msg): +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"] + return ["gpsLocationExternal"], True elif (msg_class, msg_id) in {(2, 1 * 16 + 5), (10, 9)}: - return ["ubloxGnss"] + return ["ubloxGnss"], True else: - return [] + return [], False CONFIGS = [ @@ -364,7 +364,7 @@ CONFIGS = [ init_callback=get_car_params, should_recv_callback=None, tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, + fake_pubsubmaster=False, ), ProcessConfig( proc_name="torqued", @@ -386,7 +386,7 @@ def replay_process(cfg, lr, fingerprint=None): if cfg.fake_pubsubmaster: return python_replay_process(cfg, lr, fingerprint) else: - return cpp_replay_process(cfg, lr, fingerprint) + return replay_process_with_sockets(cfg, lr, fingerprint) def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): @@ -401,8 +401,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'] = "" + os.environ["SKIP_FW_QUERY"] = "" + os.environ["FINGERPRINT"] = "" + + if lr is not None: + services = {m.which() for m in lr} + params.put_bool("UbloxAvailable", "ubloxGnss" in services) if lr is not None: services = {m.which() for m in lr} @@ -458,12 +462,6 @@ def python_replay_process(cfg, lr, fingerprint=None): 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())] - # laikad needs decision between submaster ubloxGnss and qcomGnss, prio given to ubloxGnss - if cfg.proc_name == "laikad": - args = (*args, not any(m.which() == "ubloxGnss" for m in pub_msgs)) - service = "qcomGnss" if args[2] else "ubloxGnss" - pub_msgs = [m for m in pub_msgs if m.which() == service or m.which() == 'clocks'] - controlsState = None initialized = False for msg in lr: @@ -534,49 +532,53 @@ def python_replay_process(cfg, lr, fingerprint=None): return log_msgs -def cpp_replay_process(cfg, lr, fingerprint=None): - sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] # We get responses here +def replay_process_with_sockets(cfg, lr, fingerprint=None): + sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] pm = messaging.PubMaster(cfg.pub_sub.keys()) 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())] - log_msgs = [] # We need to fake SubMaster alive since we can't inject a fake clock setup_env(simulation=True, 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() + log_msgs = [] try: - with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}"): + # 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) - # Make sure all subscribers are connected - sockets = {s: messaging.sub_sock(s, timeout=2000) for s in sub_sockets} - for s in sub_sockets: - messaging.recv_one_or_none(sockets[s]) + # Make sure all subscribers are connected + sockets = {s: messaging.sub_sock(s, timeout=2000) for s in sub_sockets} + for s in sub_sockets: + messaging.recv_one_or_none(sockets[s]) - for i, msg in enumerate(pub_msgs): + # Do the replay + cnt = 0 + for msg in pub_msgs: + with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): pm.send(msg.which(), msg.as_builder()) + while not pm.all_readers_updated(msg.which()): + time.sleep(0) - resp_sockets = cfg.pub_sub[msg.which()] if cfg.should_recv_callback is None else cfg.should_recv_callback(msg) + 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) for s in resp_sockets: - response = messaging.recv_one_retry(sockets[s]) - - if response is None: - print(f"Warning, no response received {i}") - else: - - response = response.as_builder() - response.logMonoTime = msg.logMonoTime - response = response.as_reader() - log_msgs.append(response) - - if not len(resp_sockets): # We only need to wait if we didn't already wait for a response - while not pm.all_readers_updated(msg.which()): - time.sleep(0) + m = messaging.recv_one_retry(sockets[s]) + 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() diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 07117c2e7f..a2dd938e2f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -18,7 +18,7 @@ from tools.lib.logreader import LogReader source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY ("HYUNDAI", "02c45f73a2e5c6e9|2021-01-01--19-08-22--1"), # HYUNDAI.SONATA - ("HYUNDAI2", "d545129f3ca90f28|2022-11-07--20-43-08--3"), # HYUNDAI.KIA_EV6 + ("HYUNDAI2", "d545129f3ca90f28|2022-11-07--20-43-08--3"), # HYUNDAI.KIA_EV6 (+ QCOM GPS) ("TOYOTA", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA.PRIUS (INDI) ("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR) ("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2 @@ -70,7 +70,7 @@ def run_test_process(data): res = None if not args.upload_only: lr = LogReader.from_bytes(lr_dat) - res, log_msgs = test_process(cfg, lr, ref_log_path, cur_log_fn, args.ignore_fields, args.ignore_msgs) + res, log_msgs = test_process(cfg, lr, segment, ref_log_path, cur_log_fn, args.ignore_fields, args.ignore_msgs) # save logs so we can upload when updating refs save_log(cur_log_fn, log_msgs) @@ -88,7 +88,7 @@ def get_log_data(segment): return (segment, f.read()) -def test_process(cfg, lr, ref_log_path, new_log_path, ignore_fields=None, ignore_msgs=None): +def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=None, ignore_msgs=None): if ignore_fields is None: ignore_fields = [] if ignore_msgs is None: @@ -96,7 +96,10 @@ def test_process(cfg, lr, ref_log_path, new_log_path, ignore_fields=None, ignore ref_log_msgs = list(LogReader(ref_log_path)) - log_msgs = replay_process(cfg, lr) + try: + log_msgs = replay_process(cfg, lr) + except Exception as e: + raise Exception("failed on segment: " + segment) from e # check to make sure openpilot is engaged in the route if cfg.proc_name == "controlsd": From a86730a2c601188c480285c45999efa00c3b3d4a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 22 Mar 2023 07:55:06 +0800 Subject: [PATCH 050/143] camerad: remove deprecated focus parameters from FrameMetadata (#27638) --- system/camerad/cameras/camera_common.cc | 3 --- system/camerad/cameras/camera_common.h | 5 ----- 2 files changed, 8 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 7ee3738057..9ef5d89a4e 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -157,9 +157,6 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr framed.setHighConversionGain(frame_data.high_conversion_gain); framed.setMeasuredGreyFraction(frame_data.measured_grey_fraction); framed.setTargetGreyFraction(frame_data.target_grey_fraction); - framed.setLensPos(frame_data.lens_pos); - framed.setLensErr(frame_data.lens_err); - framed.setLensTruePos(frame_data.lens_true_pos); framed.setProcessingTime(frame_data.processing_time); const float ev = c->cur_ev[frame_data.frame_id % 3]; diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 088b9f7939..07d1291a2a 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -66,11 +66,6 @@ typedef struct FrameMetadata { float measured_grey_fraction; float target_grey_fraction; - // Focus - unsigned int lens_pos; - float lens_err; - float lens_true_pos; - float processing_time; } FrameMetadata; From fc5a575ba3aef8fd4b3b7bac93bbc557c3bee11a Mon Sep 17 00:00:00 2001 From: Gijs Koning Date: Wed, 22 Mar 2023 01:07:19 +0100 Subject: [PATCH 051/143] laikad: use non-conflating socket for gnss msgs (#24888) * Use subsock * wait for one * wrong name * try cpp proc replay * fix recv pattern --------- Co-authored-by: Bruce Wayne Co-authored-by: Adeeb Shihadeh --- selfdrive/locationd/laikad.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index be272f1774..2e3ee1b7f0 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -116,7 +116,7 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: @@ -154,7 +154,7 @@ class Laikad: ephemeris_statuses.append(status) return ephemeris_statuses - + def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -262,7 +262,7 @@ class Laikad: out_msg = messaging.new_message("gnssMeasurements") out_msg.gnssMeasurements = { "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), + "ephemerisStatuses": self.create_ephem_statuses(), } if self.first_log_time is None: self.first_log_time = 1e-9 * gnss_mono_time @@ -310,7 +310,7 @@ class Laikad: "measTime": gnss_mono_time, "correctedMeasurements": meas_msgs, "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), + "ephemerisStatuses": self.create_ephem_statuses(), } return out_msg @@ -425,17 +425,18 @@ def main(sm=None, pm=None): use_qcom = not Params().get_bool("UbloxAvailable", block=True) if use_qcom: - raw_gnss_socket = "qcomGnss" + raw_name = "qcomGnss" else: - raw_gnss_socket = "ubloxGnss" + raw_name = "ubloxGnss" + raw_gnss_sock = messaging.sub_sock(raw_name, conflate=False, timeout=1000) if sm is None: - sm = messaging.SubMaster([raw_gnss_socket, 'clocks']) + sm = messaging.SubMaster(['clocks',]) if pm is None: pm = messaging.PubMaster(['gnssMeasurements']) # disable until set as main gps source, to better analyze startup time - use_internet = False #"LAIKAD_NO_INTERNET" not in os.environ + use_internet = False # "LAIKAD_NO_INTERNET" not in os.environ replay = "REPLAY" in os.environ if replay or "CI" in os.environ: @@ -444,18 +445,17 @@ def main(sm=None, pm=None): laikad = Laikad(save_ephemeris=not replay, auto_fetch_navs=use_internet, use_qcom=use_qcom) while True: - sm.update() - - if sm.updated[raw_gnss_socket]: - gnss_msg = sm[raw_gnss_socket] - msg = laikad.process_gnss_msg(gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) - pm.send('gnssMeasurements', msg) + for in_msg in messaging.drain_sock(raw_gnss_sock): + out_msg = laikad.process_gnss_msg(getattr(in_msg, raw_name), in_msg.logMonoTime, replay) + pm.send('gnssMeasurements', out_msg) + sm.update(0) if not laikad.got_first_gnss_msg and sm.updated['clocks']: clocks_msg = sm['clocks'] t = GPSTime.from_datetime(datetime.utcfromtimestamp(clocks_msg.wallTimeNanos * 1E-9)) if laikad.auto_fetch_navs: laikad.fetch_navs(t, block=replay) + if __name__ == "__main__": main() From be659c976c633876a58ee282550f9ccf52a1e504 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 17:28:38 -0700 Subject: [PATCH 052/143] log current bootlog (#27645) * log current bootlog * rm path * mv that --------- Co-authored-by: Comma Device --- common/params.cc | 1 + system/loggerd/bootlog.cc | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/common/params.cc b/common/params.cc index e71f802d61..c084e03d38 100644 --- a/common/params.cc +++ b/common/params.cc @@ -98,6 +98,7 @@ std::unordered_map keys = { {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CompletedTrainingVersion", PERSISTENT}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"CurrentBootlog", PERSISTENT}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisablePowerDown", PERSISTENT}, diff --git a/system/loggerd/bootlog.cc b/system/loggerd/bootlog.cc index 4deb5b41f3..becd293c02 100644 --- a/system/loggerd/bootlog.cc +++ b/system/loggerd/bootlog.cc @@ -2,6 +2,7 @@ #include #include "cereal/messaging/messaging.h" +#include "common/params.h" #include "common/swaglog.h" #include "system/loggerd/logger.h" @@ -48,7 +49,8 @@ static kj::Array build_boot_log() { } int main(int argc, char** argv) { - const std::string path = LOG_ROOT + "/boot/" + logger_get_route_name(); + const std::string timestr = logger_get_route_name(); + const std::string path = LOG_ROOT + "/boot/" + timestr; LOGW("bootlog to %s", path.c_str()); // Open bootlog @@ -61,5 +63,8 @@ int main(int argc, char** argv) { // Write bootlog file.write(build_boot_log().asBytes()); + // Write out bootlog param to match routes with bootlog + Params().put("CurrentBootlog", timestr.c_str()); + return 0; } From 114b1e4a143acd1d20c2513035873c15228cef8c Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:41:31 +0900 Subject: [PATCH 053/143] Kia: add missing Korean EV6 fwdCamera FW (#27641) * Kia: add missing Korean EV6 fwdCamera FW * Apply suggestions from code review * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 49e4ce033d..fc0469ffed 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1553,6 +1553,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823', + b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.06 99210-CV000 220328', ], }, CAR.IONIQ_5: { From 660b9e9718129d80afc0cb3d235fcefb22ba0fc6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 Mar 2023 19:16:05 -0700 Subject: [PATCH 054/143] Chrysler: add FW versions for 2019 Jeep Grand Cherokee (#27649) add FW versions for Jeep 2019 --- selfdrive/car/chrysler/values.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 984f92b5aa..8799f073c9 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -182,6 +182,30 @@ FW_QUERY_CONFIG = FwQueryConfig( ) FW_VERSIONS = { + CAR.JEEP_CHEROKEE_2019: { + (Ecu.combinationMeter, 0x742, None): [ + b'68402971AD', + ], + (Ecu.srs, 0x744, None): [ + b'68355363AB', + ], + (Ecu.abs, 0x747, None): [ + b'68408639AD', + ], + (Ecu.fwdRadar, 0x753, None): [ + b'68456722AC', + ], + (Ecu.eps, 0x75A, None): [ + b'68453431AA', + ], + (Ecu.engine, 0x7e0, None): [ + b'05035674AB ', + ], + (Ecu.transmission, 0x7e1, None): [ + b'05035707AA', + ], + }, + CAR.RAM_1500: { (Ecu.combinationMeter, 0x742, None): [ b'68294051AG', From aeb905a2bf64475d3d33b70da6e8a60e4b0985c9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 Mar 2023 19:21:11 -0700 Subject: [PATCH 055/143] Toyota LTA: allow no torque (#27646) * no torque * Update ref_commit * Update ref_commit --- selfdrive/car/toyota/toyotacan.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index 7e360cc4e1..a78b70608c 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -17,7 +17,7 @@ def create_lta_steer_command(packer, steer, steer_req, raw_cnt): "SETME_X1": 1, "SETME_X3": 3, "PERCENTAGE": 100, - "SETME_X64": 0x64, + "SETME_X64": 0, "ANGLE": 0, "STEER_ANGLE_CMD": steer, "STEER_REQUEST": steer_req, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index cf19e9cb07..5f3db2fa88 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -30128f043985c8a793cdca2ad9ea1039c5086d72 \ No newline at end of file +ad3192c5ab1743bc1671c5c29816b360747cc3e0 From aefe636cc1b415f4ebf63f71ae9ae298461e37ac Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Mar 2023 00:23:51 -0700 Subject: [PATCH 056/143] GM: common longitudinal actuator delay (#27357) * common longitudinal actuator delay * comment * remove dup * move * clean up * Update ref_commit --- selfdrive/car/gm/interface.py | 4 +--- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 602d7e31b6..f501c8c7dd 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -78,7 +78,6 @@ class CarInterface(CarInterfaceBase): ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling ret.vEgoStopping = 0.25 ret.vEgoStarting = 0.25 - ret.longitudinalActuatorDelayUpperBound = 0.5 if experimental_long: ret.pcmCruise = False @@ -113,6 +112,7 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz + ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking if candidate == CAR.VOLT: ret.mass = 1607. + STD_CARGO_KG @@ -148,7 +148,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.4 # end to end is 13.46 ret.centerToFront = ret.wheelbase * 0.4 ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia() - ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking elif candidate == CAR.BUICK_LACROSSE: ret.mass = 1712. + STD_CARGO_KG @@ -175,7 +174,6 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.95 # 116 inches in meters ret.steerRatio = 17.3 ret.centerToFront = ret.wheelbase * 0.5 - ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.ESCALADE_ESV: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 5f3db2fa88..d20b7f5d7a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -ad3192c5ab1743bc1671c5c29816b360747cc3e0 +a4ee2bfc9a9518a23a4f0fac4df124d1f12deb79 From dcbadc554d009c0e8d5c9a034cf748391c5015a8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Mar 2023 01:27:23 +0800 Subject: [PATCH 057/143] cabana: sets the line width with floating point precision. (#27653) --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 09fcbf2ee2..c98ca3bc69 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -843,7 +843,7 @@ QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { series->setUseOpenGL(true); // Qt doesn't properly apply device pixel ratio in OpenGL mode QPen pen = series->pen(); - pen.setWidth(2.0 * qApp->devicePixelRatio()); + pen.setWidthF(2.0 * devicePixelRatioF()); series->setPen(pen); #endif chart()->addSeries(series); From 89d767da49a32bd78024ac224236f82bf2b2fff5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Mar 2023 02:02:34 +0800 Subject: [PATCH 058/143] cabana: improve find similar bits (#27651) * improve find similar bits * 2 precision --- tools/cabana/mainwin.cc | 6 +- tools/cabana/streams/abstractstream.h | 1 + tools/cabana/streams/replaystream.h | 1 + tools/cabana/tools/findsimilarbits.cc | 110 ++++++++++++++++---------- tools/cabana/tools/findsimilarbits.h | 5 +- 5 files changed, 78 insertions(+), 45 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index befbf270c6..b7cfd9dc2a 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -133,8 +133,10 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(undo_view); commands_menu->addAction(commands_act); - QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); - tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); + if (!can->liveStreaming()) { + QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); + tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); + } QMenu *help_menu = menuBar()->addMenu(tr("&Help")); help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 3c7bdd6132..8e19f69d2a 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -50,6 +50,7 @@ public: virtual void setSpeed(float speed) {} virtual bool isPaused() const { return false; } virtual void pause(bool pause) {} + virtual const std::vector *rawEvents() const { return nullptr; } const std::unordered_map> &events() const { return events_; } virtual const std::vector> getTimeline() { return {}; } void mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 6fc61f7f36..10dc804716 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -23,6 +23,7 @@ public: inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; + const std::vector *rawEvents() const override { return replay->events(); } inline const std::vector> getTimeline() override { return replay->getTimeline(); } private: diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index ffd0df0501..a44ac76059 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -1,5 +1,6 @@ #include "tools/cabana/tools/findsimilarbits.h" +#include #include #include #include @@ -16,20 +17,23 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi QVBoxLayout *main_layout = new QVBoxLayout(this); - QHBoxLayout *form_layout = new QHBoxLayout(); - bus_combo = new QComboBox(this); + QHBoxLayout *src_layout = new QHBoxLayout(); + src_bus_combo = new QComboBox(this); + find_bus_combo = new QComboBox(this); QSet bus_set; for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { bus_set << it.key().source; } - for (uint8_t bus : bus_set) { - bus_combo->addItem(QString::number(bus), bus); + for (auto cb : {src_bus_combo, find_bus_combo}) { + for (uint8_t bus : bus_set) { + cb->addItem(QString::number(bus), bus); + } + cb->model()->sort(0); + cb->setCurrentIndex(0); } - bus_combo->model()->sort(0); - bus_combo->setCurrentIndex(0); msg_cb = new QComboBox(this); - // TODO: update when bus_combo changes + // TODO: update when src_bus_combo changes for (auto &[id, msg] : dbc()->getMessages(0)) { msg_cb->addItem(msg.name, id.address); } @@ -37,29 +41,44 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi msg_cb->setCurrentIndex(0); byte_idx_sb = new QSpinBox(this); + byte_idx_sb->setFixedWidth(50); byte_idx_sb->setRange(0, 63); bit_idx_sb = new QSpinBox(this); + bit_idx_sb->setFixedWidth(50); bit_idx_sb->setRange(0, 7); - form_layout->addWidget(new QLabel("Bus")); - form_layout->addWidget(bus_combo); - form_layout->addWidget(msg_cb); - form_layout->addWidget(new QLabel("Byte Index")); - form_layout->addWidget(byte_idx_sb); - form_layout->addWidget(new QLabel("Bit Index")); - form_layout->addWidget(bit_idx_sb); - - + src_layout->addWidget(new QLabel(tr("Bus"))); + src_layout->addWidget(src_bus_combo); + src_layout->addWidget(msg_cb); + src_layout->addWidget(new QLabel(tr("Byte Index"))); + src_layout->addWidget(byte_idx_sb); + src_layout->addWidget(new QLabel(tr("Bit Index"))); + src_layout->addWidget(bit_idx_sb); + src_layout->addStretch(0); + + QHBoxLayout *find_layout = new QHBoxLayout(); + find_layout->addWidget(new QLabel(tr("Bus"))); + find_layout->addWidget(find_bus_combo); + find_layout->addWidget(new QLabel(tr("Equal"))); + equal_combo = new QComboBox(this); + equal_combo->addItems({"Yes", "No"}); + find_layout->addWidget(equal_combo); min_msgs = new QLineEdit(this); min_msgs->setValidator(new QIntValidator(this)); min_msgs->setText("100"); - form_layout->addWidget(new QLabel("Min msg count")); - form_layout->addWidget(min_msgs); + find_layout->addWidget(new QLabel(tr("Min msg count"))); + find_layout->addWidget(min_msgs); search_btn = new QPushButton(tr("&Find"), this); - form_layout->addWidget(search_btn); - form_layout->addStretch(1); - main_layout->addLayout(form_layout); + find_layout->addWidget(search_btn); + find_layout->addStretch(0); + + QGridLayout *grid_layout = new QGridLayout(); + grid_layout->addWidget(new QLabel("Find From:"), 0, 0); + grid_layout->addLayout(src_layout, 0, 1); + grid_layout->addWidget(new QLabel("Find In:"), 1, 0); + grid_layout->addLayout(find_layout, 1, 1); + main_layout->addLayout(grid_layout); table = new QTableWidget(this); table->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -70,10 +89,9 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi setMinimumSize({700, 500}); QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); - QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) { if (index.isValid()) { - MessageId msg_id = {.source = (uint8_t)bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; + MessageId msg_id = {.source = (uint8_t)find_bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; emit openMessage(msg_id); } }); @@ -83,7 +101,8 @@ void FindSimilarBitsDlg::find() { search_btn->setEnabled(false); table->clear(); uint32_t selected_address = msg_cb->currentData().toUInt(); - auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), min_msgs->text().toInt()); + auto msg_mismatched = calcBits(src_bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), + find_bus_combo->currentText().toUInt(), equal_combo->currentIndex() == 0, min_msgs->text().toInt()); table->setRowCount(msg_mismatched.size()); table->setColumnCount(6); table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total msgs", "% mismatched"}); @@ -94,32 +113,41 @@ void FindSimilarBitsDlg::find() { table->setItem(i, 2, new QTableWidgetItem(QString::number(m.bit_idx))); table->setItem(i, 3, new QTableWidgetItem(QString::number(m.mismatches))); table->setItem(i, 4, new QTableWidgetItem(QString::number(m.total))); - table->setItem(i, 5, new QTableWidgetItem(QString::number(m.perc))); + table->setItem(i, 5, new QTableWidgetItem(QString::number(m.perc, 'f', 2))); } search_btn->setEnabled(true); } -QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt) { +QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, + int bit_idx, uint8_t find_bus, bool equal, int min_msgs_cnt) { QHash> mismatches; QHash msg_count; + auto events = can->rawEvents(); int bit_to_find = -1; - for (const auto &[id, msg] : can->events()) { - if (id.source == bus) { - for (const auto &c : msg) { - if (id.address == selected_address && c.size > byte_idx) { - bit_to_find = ((c.dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + for (auto e : *events) { + if (e->which == cereal::Event::Which::CAN) { + for (const auto &c : e->event.getCan()) { + uint8_t src = c.getSrc(); + uint32_t address = c.getAddress(); + const auto dat = c.getDat(); + if (src == bus) { + if (address == selected_address && dat.size() > byte_idx) { + bit_to_find = ((dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + } } - ++msg_count[id.address]; - if (bit_to_find == -1) continue; + if (src == find_bus) { + ++msg_count[address]; + if (bit_to_find == -1) continue; - auto &mismatched = mismatches[id.address]; - if (mismatched.size() < c.size * 8) { - mismatched.resize(c.size * 8); - } - for (int i = 0; i < c.size; ++i) { - for (int j = 0; j < 8; ++j) { - int bit = ((c.dat[i] >> (7 - j)) & 1) != 0; - mismatched[i * 8 + j] += (bit != bit_to_find); + auto &mismatched = mismatches[address]; + if (mismatched.size() < dat.size() * 8) { + mismatched.resize(dat.size() * 8); + } + for (int i = 0; i < dat.size(); ++i) { + for (int j = 0; j < 8; ++j) { + int bit = ((dat[i] >> (7 - j)) & 1) != 0; + mismatched[i * 8 + j] += equal ? (bit != bit_to_find) : (bit == bit_to_find); + } } } } diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 53d7806a8f..a40e2cd8df 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -22,11 +22,12 @@ private: uint32_t address, byte_idx, bit_idx, mismatches, total; float perc; }; - QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt); + QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, uint8_t find_bus, + bool equal, int min_msgs_cnt); void find(); QTableWidget *table; - QComboBox *bus_combo, *msg_cb; + QComboBox *src_bus_combo, *find_bus_combo, *msg_cb, *equal_combo; QSpinBox *byte_idx_sb, *bit_idx_sb; QPushButton *search_btn; QLineEdit *min_msgs; From 8b8c4d810f84ae980f0a99c48e7fccc5888dc091 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Mar 2023 13:37:09 -0700 Subject: [PATCH 059/143] test lateral limits: remove Konas from blacklist (#27424) * remove konas from blacklist * update measured accel * remove * no longer needed --- selfdrive/car/tests/test_lateral_limits.py | 12 ------------ selfdrive/car/torque_data/params.yaml | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index 3efdd7404e..d3e4de1798 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -10,7 +10,6 @@ from common.realtime import DT_CTRL from selfdrive.car.car_helpers import interfaces from selfdrive.car.fingerprints import all_known_cars from selfdrive.car.interfaces import get_torque_params -from selfdrive.car.hyundai.values import CAR as HYUNDAI CAR_MODELS = all_known_cars() @@ -22,14 +21,6 @@ MAX_LAT_ACCEL = 3.0 # m/s^2 # jerk is measured over half a second JERK_MEAS_FRAMES = 0.5 / DT_CTRL -# TODO: update the max measured lateral accel for these cars -ABOVE_LIMITS_CARS = [ - HYUNDAI.KONA_EV, - HYUNDAI.KONA_HEV, - HYUNDAI.KONA, - HYUNDAI.KONA_EV_2022, -] - car_model_jerks: DefaultDict[str, Dict[str, float]] = defaultdict(dict) @@ -52,9 +43,6 @@ class TestLateralLimits(unittest.TestCase): if CP.notCar: raise unittest.SkipTest - if CP.carFingerprint in ABOVE_LIMITS_CARS: - raise unittest.SkipTest - CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams cls.control_params = CarControllerParams(CP) cls.torque_params = get_torque_params(cls.car_model) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 6f8cfe0ce6..cb423e1d87 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -30,7 +30,7 @@ HYUNDAI IONIQ 5 2022: [3.172929, 2.713050, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] HYUNDAI IONIQ PLUG-IN HYBRID 2019: [2.970807902012267, 1.6312321830002083, 0.1088964990357482] -HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 3.2961956260770484, 0.12359762054065548] +HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 2.307336938253934, 0.12359762054065548] HYUNDAI PALISADE 2020: [2.544642494803999, 1.8721703683337008, 0.1301424599248651] HYUNDAI SANTA FE 2019: [3.0787027729757632, 2.6173437483495565, 0.1207019341823945] HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963] From 25a7f87b424b2a4fd116aff5a5a83ecd1fd87f07 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 22 Mar 2023 13:44:29 -0700 Subject: [PATCH 060/143] camerad: reduce daytime HDR blur (#27644) * 60hz * be dynamic * cast --------- Co-authored-by: Comma Device --- system/camerad/cameras/camera_qcom2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 92b3bde413..94116b11cd 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -1175,7 +1175,7 @@ void CameraState::set_camera_exposure(float grey_frac) { // t_HCG&t_LCG + t_VS on LPD, t_SPD on SPD uint32_t hcg_time = exposure_time; uint32_t lcg_time = hcg_time; - uint32_t spd_time = exposure_time_max + VS_TIME_MAX_OX03C10; + uint32_t spd_time = std::min(std::max((uint32_t)exposure_time, (exposure_time_max + VS_TIME_MAX_OX03C10) / 3), exposure_time_max + VS_TIME_MAX_OX03C10); uint32_t vs_time = std::min(std::max((uint32_t)exposure_time / 40, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10); uint32_t real_gain = ox03c10_analog_gains_reg[new_exp_g]; From e05e7850e176c4a229608c3972c665b11510d9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 22 Mar 2023 19:10:19 -0700 Subject: [PATCH 061/143] Laika cleaner flow (#27633) * laika flow * test fixes * unexpected type * unexpected type * explicit type * ref commit * back to prev val * ref 2 --- selfdrive/locationd/laikad.py | 76 ++++++++++-------------- selfdrive/locationd/test/test_laikad.py | 15 +++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2e3ee1b7f0..59176c586b 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -7,7 +7,7 @@ from collections import defaultdict from concurrent.futures import Future, ProcessPoolExecutor from datetime import datetime from enum import IntEnum -from typing import List, Optional +from typing import List, Optional, Dict, Any import numpy as np @@ -241,12 +241,14 @@ class Laikad: new_meas = [m for m in new_meas if 1e7 < m.observables['C1C'] < 3e7] processed_measurements = process_measurements(new_meas, self.astro_dog) if self.last_fix_pos is not None: - corrected_measurements = correct_measurements(processed_measurements, self.last_fix_pos, self.astro_dog) - instant_fix = self.get_lsq_fix(t, corrected_measurements) - #instant_fix = self.get_lsq_fix(t, processed_measurements) + est_pos = self.last_fix_pos else: - corrected_measurements = [] - instant_fix = self.get_lsq_fix(t, processed_measurements) + est_pos = self.gnss_kf.x[GStates.ECEF_POS].tolist() + corrected_measurements = correct_measurements(processed_measurements, est_pos, self.astro_dog) + return corrected_measurements + + def calc_fix(self, t, measurements): + instant_fix = self.get_lsq_fix(t, measurements) if instant_fix is None: return None else: @@ -254,64 +256,52 @@ class Laikad: self.last_fix_t = t self.last_fix_pos = position_estimate self.lat_fix_pos_std = position_std - if (t*1e9) % 10 == 0: - cloudlog.debug(f"Measurements Incoming/Processed/Corrected: {len(new_meas), len(processed_measurements), len(corrected_measurements)}") - return position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, processed_measurements + return position_estimate, position_std, velocity_estimate, velocity_std def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") - out_msg.gnssMeasurements = { - "timeToFirstFix": self.ttff, - "ephemerisStatuses": self.create_ephem_statuses(), - } + t = gnss_mono_time * 1e-9 + msg_dict: Dict[str, Any] = {"measTime": gnss_mono_time} if self.first_log_time is None: self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) - return out_msg elif self.is_good_report(gnss_msg): week, tow, new_meas = self.read_report(gnss_msg) self.gps_week = week - if len(new_meas) == 0: - return out_msg - - t = gnss_mono_time * 1e-9 if week > 0: self.got_first_gnss_msg = True latest_msg_t = GPSTime(week, tow) if self.auto_fetch_navs: self.fetch_navs(latest_msg_t, block) - output = self.process_report(new_meas, t) - if output is None: - return out_msg - if self.ttff <= 0: - self.ttff = max(1e-3, t - self.first_log_time) - position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output + corrected_measurements = self.process_report(new_meas, t) + msg_dict['correctedMeasurements'] = [create_measurement_msg(m) for m in corrected_measurements] - self.update_localizer(position_estimate, t, corrected_measurements) - meas_msgs = [create_measurement_msg(m) for m in corrected_measurements] + fix = self.calc_fix(t, corrected_measurements) measurement_msg = log.LiveLocationKalman.Measurement.new_message - + if fix is not None: + position_estimate, position_std, velocity_estimate, velocity_std = fix + if self.ttff <= 0: + self.ttff = max(1e-3, t - self.first_log_time) + msg_dict["positionECEF"] = measurement_msg(value=position_estimate, std=position_std.tolist(), valid=bool(self.last_fix_t == t)) + msg_dict["velocityECEF"] = measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)) + + self.update_localizer(self.last_fix_pos, t, corrected_measurements) P_diag = self.gnss_kf.P.diagonal() kf_valid = all(self.kf_valid(t)) - out_msg.gnssMeasurements = { - "gpsWeek": week, - "gpsTimeOfWeek": tow, - "kalmanPositionECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), + msg_dict["kalmanPositionECEF"] = measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), std=np.sqrt(P_diag[GStates.ECEF_POS]).tolist(), - valid=kf_valid), - "kalmanVelocityECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_VELOCITY].tolist(), + valid=kf_valid) + msg_dict["kalmanVelocityECEF"] = measurement_msg(value=self.gnss_kf.x[GStates.ECEF_VELOCITY].tolist(), std=np.sqrt(P_diag[GStates.ECEF_VELOCITY]).tolist(), - valid=kf_valid), - "positionECEF": measurement_msg(value=position_estimate, std=position_std.tolist(), valid=bool(self.last_fix_t == t)), - "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), - - "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs, - "timeToFirstFix": self.ttff, - "ephemerisStatuses": self.create_ephem_statuses(), - } + valid=kf_valid) + + msg_dict['gpsWeek'] = self.last_report_time.week + msg_dict['gpsTimeOfWeek'] = self.last_report_time.tow + msg_dict['timeToFirstFix'] = self.ttff + msg_dict['ephemerisStatuses'] = self.create_ephem_statuses() + out_msg.gnssMeasurements = msg_dict return out_msg def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): @@ -324,7 +314,7 @@ class Laikad: cloudlog.error("Time gap of over 10s detected, gnss kalman reset") elif not valid[2]: cloudlog.error("Gnss kalman filter state is nan") - if len(est_pos) > 0: + if est_pos is not None and len(est_pos) > 0: cloudlog.info(f"Reset kalman filter with {est_pos}") self.init_gnss_localizer(est_pos) else: diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 265db50c6d..e184dc3ec4 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -180,7 +180,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 559 + correct_msgs_expected = 560 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -201,9 +201,11 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV, use_qcom=use_qcom) # Disable fetch_orbits to test NAV only correct_msgs = verify_messages(logs, laikad) - correct_msgs_expected = 42 if use_qcom else 559 + correct_msgs_expected = 44 if use_qcom else 560 + valid_fix_expected = 43 if use_qcom else 560 + self.assertEqual(correct_msgs_expected, len(correct_msgs)) - self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(valid_fix_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @mock.patch('laika.downloader.download_and_cache_file') def test_laika_offline(self, downloader_mock): @@ -216,8 +218,9 @@ class TestLaikad(unittest.TestCase): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(375, len(correct_msgs)) - self.assertEqual(375, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + expected_msgs = 376 + self.assertEqual(expected_msgs, len(correct_msgs)) + self.assertEqual(expected_msgs, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) @@ -325,7 +328,7 @@ class TestLaikad(unittest.TestCase): gm = msg.gnssMeasurements if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: cnt += 1 - self.assertEqual(cnt, 559) + self.assertEqual(cnt, 560) def dict_has_values(self, dct): self.assertGreater(len(dct), 0) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d20b7f5d7a..556781738d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a4ee2bfc9a9518a23a4f0fac4df124d1f12deb79 +50f1e873095fe2462d2aadb9c401bda76759c01c From 26541d9e7aa30b1705873e8360b806b52712fde7 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Wed, 22 Mar 2023 20:19:46 -0700 Subject: [PATCH 062/143] new model: trained on new dataset (#27637) * df733db3-fad2-4485-abe9-59a6a47f2233/449 946c0f55-247d-4790-a407-c07e4364b340/700 * fix reducel2 df733db3-fad2-4485-abe9-59a6a47f2233/449 946c0f55-247d-4790-a407-c07e4364b340/700 * update ref commit --- selfdrive/modeld/models/supercombo.onnx | 4 ++-- selfdrive/test/process_replay/model_replay_ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index a483fa4db4..13759c62f8 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:736ddc08497d7596bae4d9515a8efb996676be80e67a6d34d632bb8af2ed3fa9 -size 45962515 +oid sha256:5121deb0d5c683b0fbee4c1cad7bc625953bf127b1383fb7599a6b644efd0aea +size 46011200 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index ad09668a46..bd026f5710 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -ab64afd1abd1059c14f50c67b51e5ef89029f216 +82db08d52b155336e9a1dadd11485d5acdf2eba0 From 727a94cc7837e8556a243170111294440722a233 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Mar 2023 21:58:04 -0700 Subject: [PATCH 063/143] fw_versions: cleanup common types (#27658) * use common type * use it in fw_versions * add typing to queries --- selfdrive/car/ecu_addrs.py | 12 +++++++----- selfdrive/car/fw_versions.py | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index e5d550fac8..86bae91b06 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -9,6 +9,8 @@ from selfdrive.car import make_can_msg from selfdrive.boardd.boardd import can_list_to_can_capnp from system.swaglog import cloudlog +EcuAddrBusType = Tuple[int, Optional[int], int] + def make_tester_present_msg(addr, bus, subaddr=None): dat = [0x02, SERVICE_TYPE.TESTER_PRESENT, 0x0] @@ -33,16 +35,16 @@ def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subadd return False -def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> Set[Tuple[int, Optional[int], int]]: +def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> Set[EcuAddrBusType]: addr_list = [0x700 + i for i in range(256)] + [0x18da00f1 + (i << 8) for i in range(256)] - queries: Set[Tuple[int, Optional[int], int]] = {(addr, None, bus) for addr in addr_list} + queries: Set[EcuAddrBusType] = {(addr, None, bus) for addr in addr_list} responses = queries return get_ecu_addrs(logcan, sendcan, queries, responses, timeout=timeout, debug=debug) -def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, queries: Set[Tuple[int, Optional[int], int]], - responses: Set[Tuple[int, Optional[int], int]], timeout: float = 1, debug: bool = False) -> Set[Tuple[int, Optional[int], int]]: - ecu_responses: Set[Tuple[int, Optional[int], int]] = set() # set((addr, subaddr, bus),) +def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, queries: Set[EcuAddrBusType], + responses: Set[EcuAddrBusType], timeout: float = 1, debug: bool = False) -> Set[EcuAddrBusType]: + ecu_responses: Set[EcuAddrBusType] = set() # set((addr, subaddr, bus),) try: msgs = [make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries] diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 8092ac0b76..344d734038 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 from collections import defaultdict -from typing import Any, Optional, Set, Tuple +from typing import Any, List, Optional, Set from tqdm import tqdm import panda.python.uds as uds from cereal import car from common.params import Params -from selfdrive.car.ecu_addrs import get_ecu_addrs +from selfdrive.car.ecu_addrs import EcuAddrBusType, get_ecu_addrs from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery @@ -146,9 +146,9 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): return True, set() -def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[Tuple[int, Optional[int], int]]: - queries = list() - parallel_queries = list() +def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: + queries: List[List[EcuAddrBusType]] = list() + parallel_queries: List[EcuAddrBusType] = list() responses = set() for brand, r in REQUESTS: From 42449b482d46565242341ca2d7e3a7255572f6a2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 00:14:31 -0700 Subject: [PATCH 064/143] boardd: ability to switch between ELM safety params (#27656) * indecisive * rename to generic FW query * remove code and update comment * we need this to start off, unless we set multiplexing immediately * draft * draft 2 * try that * can't do this either, boardd might read Enabled after removing, but before setting new Request param * this should work * use one less param * fix params * match behavior (set all pandas to safety param of 1, disabling multiplexing for fingerprinting * clean up (some tests may temp break) * fix param name and sort * time it * yes it does matter * add to hyundai's bus 5 query * remove hyundai for now * this should work * clean up * clean up * flip argument around, clean up * fix test_startup * some clean up * rm line * comment makes more sense * required typing * clean up common type * comments * Update selfdrive/car/car_helpers.py * line * whoops, need to set before vin! * fix debug * annoying * more debugging * bug fix (needs both keys always) * debuGG debuGG * Revert "debuGG" This reverts commit 55b2f429324c0b92d5cfb2cabf8b20db1e166248. * Revert "more debugging" This reverts commit 02934c3403ad5270f03093508b704c151d1ccb2a. * Revert "annoying" This reverts commit 8b4e5e09989f9a0217e3ec1c0ba68735929b7366. * clean that up * bumpback * bumpback * every second write param * flip * stuff * move up? * fix timing out in CI * rm --- common/params.cc | 5 +- selfdrive/boardd/boardd.cc | 29 +++++----- .../boardd/tests/test_boardd_loopback.py | 2 +- selfdrive/car/car_helpers.py | 13 +++-- selfdrive/car/fw_query_definitions.py | 4 +- selfdrive/car/fw_versions.py | 57 +++++++++---------- selfdrive/car/honda/values.py | 2 +- selfdrive/controls/tests/test_startup.py | 5 +- .../test/process_replay/process_replay.py | 1 - 9 files changed, 62 insertions(+), 56 deletions(-) diff --git a/common/params.cc b/common/params.cc index c084e03d38..428830a112 100644 --- a/common/params.cc +++ b/common/params.cc @@ -111,7 +111,7 @@ std::unordered_map keys = { {"DoReboot", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START}, - {"FirmwareObdQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"ForcePowerDown", CLEAR_ON_MANAGER_START}, {"GitBranch", PERSISTENT}, {"GitCommit", PERSISTENT}, @@ -155,7 +155,8 @@ std::unordered_map keys = { {"NavSettingTime24h", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT}, {"NavdRender", PERSISTENT}, - {"ObdMultiplexingDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"OpenpilotEnabledToggle", PERSISTENT}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"PandaSignatures", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 5d885c2c79..3dc54b856a 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -113,32 +113,35 @@ bool safety_setter_thread(std::vector pandas) { return false; } - // set to ELM327 for fingerprinting + // initialize to ELM327 without OBD multiplexing for fingerprinting + bool obd_multiplexing_enabled = false; for (int i = 0; i < pandas.size(); i++) { - const uint16_t safety_param = (i > 0) ? 1U : 0U; - pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); + pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); } - // wait for FW query at OBD port to finish + // openpilot can switch between multiplexing modes for different FW queries while (true) { if (do_exit || !check_all_connected(pandas) || !ignition) { return false; } - if (p.getBool("FirmwareObdQueryDone")) { - LOGW("finished FW query at OBD port"); + bool obd_multiplexing_requested = p.getBool("ObdMultiplexingEnabled"); + if (obd_multiplexing_requested != obd_multiplexing_enabled) { + const uint16_t safety_param = obd_multiplexing_requested ? 0U : 1U; + for (int i = 0; i < pandas.size(); i++) { + pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); + } + obd_multiplexing_enabled = obd_multiplexing_requested; + p.putBool("ObdMultiplexingChanged", true); + } + + if (p.getBool("FirmwareQueryDone")) { + LOGW("finished FW query"); break; } util::sleep_for(20); } - // set to ELM327 to finish fingerprinting and for potential ECU knockouts - for (Panda *panda : pandas) { - panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); - } - - p.putBool("ObdMultiplexingDisabled", true); - std::string params; LOGW("waiting for params to set safety model"); while (true) { diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index b8ebbd88a3..d614f0b126 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -51,7 +51,7 @@ class TestBoardd(unittest.TestCase): cp.safetyConfigs = [safety_config]*num_pandas params = Params() - params.put_bool("FirmwareObdQueryDone", True) + params.put_bool("FirmwareQueryDone", True) params.put_bool("ControlsReady", True) params.put("CarParams", cp.to_bytes()) diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index dc82f56197..6a131c77de 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -8,7 +8,7 @@ from system.version import is_comma_remote, is_tested_branch from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from selfdrive.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN -from selfdrive.car.fw_versions import disable_obd_multiplexing, get_fw_versions_ordered, match_fw_to_car, get_present_ecus +from selfdrive.car.fw_versions import get_fw_versions_ordered, get_present_ecus, match_fw_to_car, set_obd_multiplexing from system.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.car import gen_empty_fingerprint @@ -80,12 +80,13 @@ def fingerprint(logcan, sendcan, num_pandas): fixed_fingerprint = os.environ.get('FINGERPRINT', "") skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) ecu_rx_addrs = set() + params = Params() if not skip_fw_query: # Vin query only reliably works through OBDII bus = 1 - cached_params = Params().get("CarParamsCache") + cached_params = params.get("CarParamsCache") if cached_params is not None: cached_params = car.CarParams.from_bytes(cached_params) if cached_params.carName == "mock": @@ -98,6 +99,7 @@ def fingerprint(logcan, sendcan, num_pandas): cached = True else: cloudlog.warning("Getting VIN & FW versions") + set_obd_multiplexing(params, True) vin_rx_addr, vin = get_vin(logcan, sendcan, bus) ecu_rx_addrs = get_present_ecus(logcan, sendcan, num_pandas=num_pandas) car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas) @@ -113,10 +115,11 @@ def fingerprint(logcan, sendcan, num_pandas): cloudlog.event("Malformed VIN", vin=vin, error=True) vin = VIN_UNKNOWN cloudlog.warning("VIN %s", vin) - - params = Params() params.put("CarVin", vin) - disable_obd_multiplexing(params) + + # disable OBD multiplexing for potential ECU knockouts + set_obd_multiplexing(params, False) + params.put_bool("FirmwareQueryDone", True) finger = gen_empty_fingerprint() candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index dd3b19f6de..4c2baa58d7 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -59,8 +59,8 @@ class Request: bus: int = 1 # FW responses from these queries will not be used for fingerprinting logging: bool = False - # These requests are done once OBD multiplexing is disabled, after all others - non_obd: bool = False + # boardd toggles OBD multiplexing on/off as needed + obd_multiplexing: bool = True @dataclass diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 344d734038..51bf99ebf4 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from collections import defaultdict -from typing import Any, List, Optional, Set +from typing import Any, Dict, List, Set from tqdm import tqdm import panda.python.uds as uds @@ -147,8 +147,10 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: - queries: List[List[EcuAddrBusType]] = list() - parallel_queries: List[EcuAddrBusType] = list() + params = Params() + # queries are split by OBD multiplexing mode + queries: Dict[bool, List[List[EcuAddrBusType]]] = {True: [], False: []} + parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []} responses = set() for brand, r in REQUESTS: @@ -163,21 +165,24 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: a = (addr, sub_addr, r.bus) # Build set of queries if sub_addr is None: - if a not in parallel_queries: - parallel_queries.append(a) + if a not in parallel_queries[r.obd_multiplexing]: + parallel_queries[r.obd_multiplexing].append(a) else: # subaddresses must be queried one by one - if [a] not in queries: - queries.append([a]) + if [a] not in queries[r.obd_multiplexing]: + queries[r.obd_multiplexing].append([a]) # Build set of expected responses to filter response_addr = uds.get_rx_addr_for_tx_addr(addr, r.rx_offset) responses.add((response_addr, sub_addr, r.bus)) - queries.insert(0, parallel_queries) + for obd_multiplexing in queries: + queries[obd_multiplexing].insert(0, parallel_queries[obd_multiplexing]) ecu_responses = set() - for query in queries: - ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) + for obd_multiplexing in queries: + set_obd_multiplexing(params, obd_multiplexing) + for query in queries[obd_multiplexing]: + ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) return ecu_responses @@ -198,13 +203,13 @@ def get_brand_ecu_matches(ecu_rx_addrs): return brand_matches -def disable_obd_multiplexing(params): - if not params.get_bool("ObdMultiplexingDisabled"): - params.put_bool("FirmwareObdQueryDone", True) - - cloudlog.warning("Waiting for OBD multiplexing to be disabled") - params.get_bool("ObdMultiplexingDisabled", block=True) - cloudlog.warning("OBD multiplexing disabled") +def set_obd_multiplexing(params: Params, obd_multiplexing: bool): + if params.get_bool("ObdMultiplexingEnabled") != obd_multiplexing: + cloudlog.warning(f"Setting OBD multiplexing to {obd_multiplexing}") + params.remove("ObdMultiplexingChanged") + params.put_bool("ObdMultiplexingEnabled", obd_multiplexing) + params.get_bool("ObdMultiplexingChanged", block=True) + 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): @@ -212,7 +217,6 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand all_car_fw = [] brand_matches = get_brand_ecu_matches(ecu_rx_addrs) - matched_brand: Optional[str] = None for brand in sorted(brand_matches, key=lambda b: len(brand_matches[b]), reverse=True): car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, debug=debug, progress=progress) @@ -220,21 +224,14 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand # Try to match using FW returned from this brand only matches = match_fw_to_car_exact(build_fw_dict(car_fw)) if len(matches) == 1: - matched_brand = brand break - disable_obd_multiplexing(Params()) - - # Do non-OBD queries for matched brand, or all if no match is found - for brand in FW_QUERY_CONFIGS.keys(): - if brand == matched_brand or matched_brand is None: - all_car_fw.extend(get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, obd_multiplexed=False, debug=debug, progress=progress)) - return all_car_fw -def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, obd_multiplexed=True, 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): versions = VERSIONS.copy() + params = Params() # Each brand can define extra ECUs to query for data collection for brand, config in FW_QUERY_CONFIGS.items(): @@ -281,9 +278,9 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue - # Or if request is not designated for current multiplexing mode - elif r.non_obd == obd_multiplexed: - continue + + # Toggle OBD multiplexing for each request + set_obd_multiplexing(params, r.obd_multiplexing) try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 0737bea147..009a549afd 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -186,7 +186,7 @@ FW_QUERY_CONFIG = FwQueryConfig( [StdQueries.UDS_VERSION_RESPONSE], bus=1, logging=True, - non_obd=True, + obd_multiplexing=False, ), ], extra_ecus=[ diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index 92fc2468bb..18c8e79026 100755 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -72,7 +72,6 @@ class TestStartup(unittest.TestCase): params.clear_all() params.put_bool("Passive", False) params.put_bool("OpenpilotEnabledToggle", True) - params.put_bool("ObdMultiplexingDisabled", True) # Build capnn version of FW array if fw_versions is not None: @@ -109,6 +108,10 @@ class TestStartup(unittest.TestCase): finger = _FINGERPRINTS[car_model][0] for _ in range(1000): + # controlsd waits for boardd to echo back that it has changed the multiplexing mode + if not params.get_bool("ObdMultiplexingChanged"): + params.put_bool("ObdMultiplexingChanged", True) + msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()] pm.send('can', can_list_to_can_capnp(msgs)) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 9c0225796d..2b9096b423 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -397,7 +397,6 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): params.put_bool("DisengageOnAccelerator", True) params.put_bool("WideCameraOnly", False) params.put_bool("DisableLogging", False) - params.put_bool("ObdMultiplexingDisabled", True) os.environ["NO_RADAR_SLEEP"] = "1" os.environ["REPLAY"] = "1" From 1a560a1a6c114352b85959f96190d97f49f48010 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 24 Mar 2023 01:19:39 +0800 Subject: [PATCH 065/143] cabana: fix button geometries (#27659) --- tools/cabana/signaledit.cc | 3 +-- tools/cabana/signaledit.h | 11 ++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d91f6c1401..4cd06e8a7d 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -415,7 +415,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), hl->addWidget(collapse_btn); // tree view - tree = new QTreeView(this); + tree = new TreeView(this); tree->setModel(model = new SignalModel(this)); tree->setItemDelegate(new SignalItemDelegate(this)); tree->setFrameShape(QFrame::NoFrame); @@ -439,7 +439,6 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(tree, &QTreeView::viewportEntered, [this]() { emit highlight(nullptr); }); QObject::connect(tree, &QTreeView::entered, [this](const QModelIndex &index) { emit highlight(model->getItem(index)->sig); }); QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); - QObject::connect(model, &QAbstractItemModel::rowsInserted, 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); }); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index ae73a7b3bc..d6bad6d88c 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -108,8 +108,17 @@ private: void rowsChanged(); void leaveEvent(QEvent *event); + struct TreeView : public QTreeView { + TreeView(QWidget *parent) : QTreeView(parent) {} + void rowsInserted(const QModelIndex &parent, int start, int end) override { + ((SignalView *)parentWidget())->rowsChanged(); + // update widget geometries in QTreeView::rowsInserted + QTreeView::rowsInserted(parent, start, end); + } + }; + MessageId msg_id; - QTreeView *tree; + TreeView *tree; QLineEdit *filter_edit; ChartsWidget *charts; QLabel *signal_count_lb; From a0e225e4afe971f92fa0980c3f89b1d9818f53a5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 21:14:57 -0700 Subject: [PATCH 066/143] FPv2: don't multiplex second panda (#27663) * fix this way * or can fix this way * simplify * fix --- selfdrive/boardd/boardd.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 3dc54b856a..4faa08d536 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -127,8 +127,8 @@ bool safety_setter_thread(std::vector pandas) { bool obd_multiplexing_requested = p.getBool("ObdMultiplexingEnabled"); if (obd_multiplexing_requested != obd_multiplexing_enabled) { - const uint16_t safety_param = obd_multiplexing_requested ? 0U : 1U; for (int i = 0; i < pandas.size(); i++) { + const uint16_t safety_param = (i > 0 || !obd_multiplexing_requested) ? 1U : 0U; pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); } obd_multiplexing_enabled = obd_multiplexing_requested; From 049fffb39f875152b2e03df13566fddbd0249a4f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 23:07:27 -0700 Subject: [PATCH 067/143] bump cereal --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 7492dc3f45..494cd28f3b 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 +Subproject commit 494cd28f3ba2eaf8e27180b357858f8441b6d90c From 5ab45890aa28e4d97044bb80564de1fb1c2b5492 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 23:31:38 -0700 Subject: [PATCH 068/143] Hyundai CAN FD: log hvac FW version (#27668) * add parking and hvac ecus * needs a new query sadly * move space * temp * comment * fix * mid-solution stash * pretty cleannnnnnn * everything seems to be working * bump cereal * this is a smaller diff, easier to merge * bump cereal * just hvac * bump to master --- cereal | 2 +- selfdrive/car/hyundai/values.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 494cd28f3b..d0ca2639d0 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 494cd28f3ba2eaf8e27180b357858f8441b6d90c +Subproject commit d0ca2639d057acda9ce56766f60658417ab6834a diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index fc0469ffed..55645f2050 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -359,18 +359,19 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar], + whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac], bus=4, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar], + whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar, Ecu.hvac], bus=5, ), ], extra_ecus=[ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms + (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], ) From ecbd7150eb68ca79737c43914e91dbc7c633c812 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 23:47:15 -0700 Subject: [PATCH 069/143] FwQueryConfig: auxiliary field to add requests for first aux panda (#27666) * mid-solution stash * pretty cleannnnnnn * everything seems to be working * rename * space * reduce obd multiplexing transitions from 3 to 1 (0.3s to 0.1s) --- selfdrive/car/fw_query_definitions.py | 10 ++++++++++ selfdrive/car/hyundai/values.py | 12 +++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index 4c2baa58d7..7ae9bee404 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import capnp +import copy from dataclasses import dataclass, field import struct from typing import Dict, List, Optional, Tuple @@ -57,6 +58,8 @@ class Request: whitelist_ecus: List[int] = field(default_factory=list) rx_offset: int = 0x8 bus: int = 1 + # Whether this query should be run on the first auxiliary panda (CAN FD cars for example) + auxiliary: bool = False # FW responses from these queries will not be used for fingerprinting logging: bool = False # boardd toggles OBD multiplexing on/off as needed @@ -71,3 +74,10 @@ 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) + + def __post_init__(self): + for i in range(len(self.requests)): + if self.requests[i].auxiliary: + new_request = copy.deepcopy(self.requests[i]) + new_request.bus += 4 + self.requests.append(new_request) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 55645f2050..5c677951b7 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -355,18 +355,24 @@ FW_QUERY_CONFIG = FwQueryConfig( [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar], ), - # CAN-FD queries (camera) + + # CAN-FD queries (from camera) + # TODO: combine shared whitelists with CAN requests Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac], - bus=4, + bus=0, + auxiliary=True, + obd_multiplexing=False, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar, Ecu.hvac], - bus=5, + bus=1, + auxiliary=True, + obd_multiplexing=False, ), ], extra_ecus=[ From 021661b316f488682c9e4c1b586c9fb51384cdf6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 00:12:25 -0700 Subject: [PATCH 070/143] Hyundai CAN FD: log ADAS parking ECU FW version (#27662) * add parking and hvac ecus * needs a new query sadly * move space * temp * comment * fix * mid-solution stash * pretty cleannnnnnn * everything seems to be working * bump cereal * bump to master * bump to master * don't multiplex when we don't need it --- cereal | 2 +- selfdrive/car/hyundai/values.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index d0ca2639d0..3c5ff1c6d0 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit d0ca2639d057acda9ce56766f60658417ab6834a +Subproject commit 3c5ff1c6d069be21b32e2ac202115f4ea5d21bc7 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 5c677951b7..57d306496b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -335,10 +335,15 @@ FINGERPRINTS = { HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ p16(0xf100) # Long description + +HYUNDAI_VERSION_REQUEST_ALT = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(0xf110) # Alt long description + HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_SPARE_PART_NUMBER) + \ p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + \ p16(0xf100) + HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) FW_QUERY_CONFIG = FwQueryConfig( @@ -374,9 +379,28 @@ FW_QUERY_CONFIG = FwQueryConfig( auxiliary=True, obd_multiplexing=False, ), + + # CAN-FD debugging queries + Request( + [HYUNDAI_VERSION_REQUEST_ALT], + [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.parking], + bus=0, + auxiliary=True, + obd_multiplexing=False, + ), + Request( + [HYUNDAI_VERSION_REQUEST_ALT], + [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.parking], + bus=1, + auxiliary=True, + obd_multiplexing=False, + ), ], extra_ecus=[ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms + (Ecu.parking, 0x7b1, None), # ADAS Parking ECU (may exist on all platforms) (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], From 2ad9eec882e6be5aff4ae6a55e3ffb6f76a3d85b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 00:25:37 -0700 Subject: [PATCH 071/143] FPv2: log OBD multiplexed requests (#27667) * log multiplexed requests * bump cereal * bump cereal to master --- cereal | 2 +- selfdrive/car/fw_versions.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index 3c5ff1c6d0..c516d5e985 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 3c5ff1c6d069be21b32e2ac202115f4ea5d21bc7 +Subproject commit c516d5e9856fdb1f5ca856e430ac69aebb2ff017 diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 51bf99ebf4..e71d161f7f 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -300,6 +300,7 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, f.brand = brand f.bus = r.bus f.logging = r.logging or ecu_key in logging_addrs + f.obdMultiplexing = r.obd_multiplexing if sub_addr is not None: f.subAddress = sub_addr From 9e023b3eadcf4d8ed0b59fd5fbe4041342be322f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 00:29:48 -0700 Subject: [PATCH 072/143] FPv2: only set multiplexing when needed (#27669) * only set multiplexing if bus matters * these don't matter anymore --- selfdrive/car/fw_versions.py | 3 ++- selfdrive/car/hyundai/values.py | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index e71d161f7f..9bb04ee821 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -280,7 +280,8 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, continue # Toggle OBD multiplexing for each request - set_obd_multiplexing(params, r.obd_multiplexing) + if r.bus % 4 == 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 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 57d306496b..bb26d68329 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -369,7 +369,6 @@ FW_QUERY_CONFIG = FwQueryConfig( whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac], bus=0, auxiliary=True, - obd_multiplexing=False, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], @@ -387,7 +386,6 @@ FW_QUERY_CONFIG = FwQueryConfig( whitelist_ecus=[Ecu.parking], bus=0, auxiliary=True, - obd_multiplexing=False, ), Request( [HYUNDAI_VERSION_REQUEST_ALT], From f08132475dc94214c6deda42add8bb4360220ea6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 25 Mar 2023 02:01:03 +0800 Subject: [PATCH 073/143] cabana: align signal value vcenter (#27675) --- tools/cabana/historylog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 3e80a6a697..4ebe8e0473 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -21,7 +21,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { } else if (role == BytesRole) { return m.data; } else if (role == Qt::TextAlignmentRole) { - return Qt::AlignRight; + return (uint32_t)(Qt::AlignRight | Qt::AlignVCenter); } return {}; } From 9c84af296c325f310bad23657bc35e725be45541 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 25 Mar 2023 02:01:26 +0800 Subject: [PATCH 074/143] cabana: clear the old timeline after opening a new route from menu (#27672) --- tools/cabana/videowidget.cc | 24 ++++++++++++++---------- tools/cabana/videowidget.h | 3 +++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 536ae7ba97..e36e62131f 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -8,11 +8,12 @@ #include #include #include -#include #include #include #include +const int MIN_VIDEO_HEIGHT = 100; + static const QColor timeline_colors[] = { [(int)TimelineType::None] = QColor(111, 143, 175), [(int)TimelineType::Engaged] = QColor(0, 163, 108), @@ -22,7 +23,7 @@ static const QColor timeline_colors[] = { [(int)TimelineType::AlertCritical] = QColor(199, 0, 57), }; -inline QString formatTime(int seconds) { +static inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } @@ -106,7 +107,7 @@ QWidget *VideoWidget::createCameraWidget() { slider_layout->addWidget(end_time_label); l->addLayout(slider_layout); - cam_widget->setMinimumHeight(100); + cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); @@ -164,16 +165,12 @@ void VideoWidget::updatePlayBtnState() { } // Slider -Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { - QTimer *timer = new QTimer(this); - timer->setInterval(2000); - timer->callOnTimeout([this]() { +Slider::Slider(QWidget *parent) : timer(this), QSlider(Qt::Horizontal, parent) { + timer.callOnTimeout([this]() { timeline = can->getTimeline(); update(); }); setMouseTracking(true); - - QObject::connect(can, SIGNAL(streamStarted()), timer, SLOT(start())); QObject::connect(can, &AbstractStream::streamStarted, this, &Slider::streamStarted); } @@ -187,11 +184,13 @@ void Slider::streamStarted() { 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(); + const auto &segments = can->route()->segments(); for (auto it = segments.rbegin(); it != segments.rend() && !abort_load_thumbnail; ++it) { std::string qlog = it->second.qlog.toStdString(); if (!qlog.empty()) { @@ -280,3 +279,8 @@ void Slider::mouseMoveEvent(QMouseEvent *e) { QToolTip::showText(pt, thumb, this, rect()); QSlider::mouseMoveEvent(e); } + +void Slider::leaveEvent(QEvent *event) { + QToolTip::hideText(); + QSlider::leaveEvent(event); +} diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index d10b09fec5..a5ce8c345f 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/qt/widgets/controls.h" @@ -24,6 +25,7 @@ public: private: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; + void leaveEvent(QEvent *event) override; void sliderChange(QAbstractSlider::SliderChange change) override; void paintEvent(QPaintEvent *ev) override; void streamStarted(); @@ -37,6 +39,7 @@ private: QMap thumbnails; QFuture thumnail_future; QSize thumbnail_size = {}; + QTimer timer; }; class VideoWidget : public QWidget { From 76319d02d843b9809a6d7bedec64db523fa12d68 Mon Sep 17 00:00:00 2001 From: mitchellgoffpc Date: Fri, 24 Mar 2023 16:16:38 -0700 Subject: [PATCH 075/143] Added tritonclient to xx deps --- poetry.lock | 303 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 303 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 4abd6777ba..b7554ac03a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -119,6 +119,7 @@ packaging = ">20.6" [package.source] type = "url" url = "https://github.com/commaai/apex/releases/download/pytorch2.0.0%2Bcu11.8/apex-0.1-cp38-cp38-linux_x86_64.whl" + [[package]] name = "appdirs" version = "1.4.4" @@ -459,6 +460,14 @@ python-versions = "*" docutils = ">=0.12" Sphinx = ">=4.0,<5.0.0 || >5.0.0,<6" +[[package]] +name = "brotli" +version = "1.0.9" +description = "Python bindings for the Brotli compression library" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "cachecontrol" version = "0.12.11" @@ -1193,6 +1202,20 @@ monitor = ["psutil (>=5.7.0)"] recommended = ["backports.socketpair", "cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "psutil (>=5.7.0)", "selectors2"] test = ["backports.socketpair", "cffi (>=1.12.2)", "contextvars (==2.4)", "coverage (>=5.0)", "coveralls (>=1.7.0)", "dnspython (>=1.16.0,<2.0)", "futures", "idna", "mock", "objgraph", "psutil (>=5.7.0)", "requests", "selectors2"] +[[package]] +name = "geventhttpclient" +version = "2.0.2" +description = "http client library for gevent" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +brotli = "*" +certifi = "*" +gevent = ">=0.13" +six = "*" + [[package]] name = "greenlet" version = "1.1.3.post0" @@ -2608,6 +2631,7 @@ numpy = [ [package.source] type = "url" url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu118/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" + [[package]] name = "osmium" version = "3.4.1" @@ -3359,6 +3383,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "python-rapidjson" +version = "1.10" +description = "Python wrapper around rapidjson" +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "python-socketio" version = "5.7.2" @@ -4260,6 +4292,7 @@ opt-einsum = ["opt-einsum (>=3.3)"] [package.source] type = "url" url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl" + [[package]] name = "torchsummary" version = "1.5.1" @@ -4288,6 +4321,7 @@ scipy = ["scipy"] [package.source] type = "url" url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.1%2Bcu118-cp38-cp38-linux_x86_64.whl" + [[package]] name = "tornado" version = "6.2" @@ -4343,6 +4377,25 @@ torch = "*" tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"] tutorials = ["matplotlib", "pandas", "tabulate"] +[[package]] +name = "tritonclient" +version = "2.28.0" +description = "Python client library and utilities for communicating with Triton Inference Server" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +aiohttp = {version = ">=3.8.1", optional = true, markers = "extra == \"http\""} +geventhttpclient = {version = ">=1.4.4,<=2.0.2", optional = true, markers = "extra == \"http\""} +numpy = ">=1.19.1" +python-rapidjson = ">=0.9.1" + +[package.extras] +all = ["aiohttp (>=3.8.1)", "geventhttpclient (>=1.4.4,<=2.0.2)", "grpcio (==1.41.0)", "numpy (>=1.19.1)", "protobuf (>=3.5.0,<3.20)", "python-rapidjson (>=0.9.1)"] +grpc = ["grpcio (==1.41.0)", "numpy (>=1.19.1)", "protobuf (>=3.5.0,<3.20)", "python-rapidjson (>=0.9.1)"] +http = ["aiohttp (>=3.8.1)", "geventhttpclient (>=1.4.4,<=2.0.2)", "numpy (>=1.19.1)", "python-rapidjson (>=0.9.1)"] + [[package]] name = "types-atomicwrites" version = "1.4.5.1" @@ -4606,7 +4659,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "a16ec604c5251dc860a44f7133289d0b7b16120757f8c903f3917329753c52d1" +content-hash = "b7cd75dfa0dcddff224696ccc7f41d87aac64652f744ab386321c1eee920fbe9" [metadata.files] adal = [ @@ -4916,6 +4969,90 @@ breathe = [ {file = "breathe-4.34.0-py3-none-any.whl", hash = "sha256:48804dcf0e607a89fb6ad88c729ef12743a42db03ae9489be4ef8f7c4011774a"}, {file = "breathe-4.34.0.tar.gz", hash = "sha256:ac0768a5e84addad3e632028fe67749c567aba2b29088493b64c2c1634bcdba1"}, ] +brotli = [ + {file = "Brotli-1.0.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70"}, + {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b"}, + {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6"}, + {file = "Brotli-1.0.9-cp27-cp27m-win32.whl", hash = "sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa"}, + {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452"}, + {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7"}, + {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031"}, + {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb"}, + {file = "Brotli-1.0.9-cp310-cp310-win32.whl", hash = "sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181"}, + {file = "Brotli-1.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2"}, + {file = "Brotli-1.0.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cc0283a406774f465fb45ec7efb66857c09ffefbe49ec20b7882eff6d3c86d3a"}, + {file = "Brotli-1.0.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:11d3283d89af7033236fa4e73ec2cbe743d4f6a81d41bd234f24bf63dde979df"}, + {file = "Brotli-1.0.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c1306004d49b84bd0c4f90457c6f57ad109f5cc6067a9664e12b7b79a9948ad"}, + {file = "Brotli-1.0.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1375b5d17d6145c798661b67e4ae9d5496920d9265e2f00f1c2c0b5ae91fbde"}, + {file = "Brotli-1.0.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cab1b5964b39607a66adbba01f1c12df2e55ac36c81ec6ed44f2fca44178bf1a"}, + {file = "Brotli-1.0.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ed6a5b3d23ecc00ea02e1ed8e0ff9a08f4fc87a1f58a2530e71c0f48adf882f"}, + {file = "Brotli-1.0.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cb02ed34557afde2d2da68194d12f5719ee96cfb2eacc886352cb73e3808fc5d"}, + {file = "Brotli-1.0.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b3523f51818e8f16599613edddb1ff924eeb4b53ab7e7197f85cbc321cdca32f"}, + {file = "Brotli-1.0.9-cp311-cp311-win32.whl", hash = "sha256:ba72d37e2a924717990f4d7482e8ac88e2ef43fb95491eb6e0d124d77d2a150d"}, + {file = "Brotli-1.0.9-cp311-cp311-win_amd64.whl", hash = "sha256:3ffaadcaeafe9d30a7e4e1e97ad727e4f5610b9fa2f7551998471e3736738679"}, + {file = "Brotli-1.0.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4"}, + {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296"}, + {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430"}, + {file = "Brotli-1.0.9-cp35-cp35m-win32.whl", hash = "sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1"}, + {file = "Brotli-1.0.9-cp35-cp35m-win_amd64.whl", hash = "sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea"}, + {file = "Brotli-1.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b"}, + {file = "Brotli-1.0.9-cp36-cp36m-win32.whl", hash = "sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14"}, + {file = "Brotli-1.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c"}, + {file = "Brotli-1.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d"}, + {file = "Brotli-1.0.9-cp37-cp37m-win32.whl", hash = "sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"}, + {file = "Brotli-1.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5"}, + {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb"}, + {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649"}, + {file = "Brotli-1.0.9-cp38-cp38-win32.whl", hash = "sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429"}, + {file = "Brotli-1.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f"}, + {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19"}, + {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c"}, + {file = "Brotli-1.0.9-cp39-cp39-win32.whl", hash = "sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3"}, + {file = "Brotli-1.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:73fd30d4ce0ea48010564ccee1a26bfe39323fde05cb34b5863455629db61dc7"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02177603aaca36e1fd21b091cb742bb3b305a569e2402f1ca38af471777fb019"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b43775532a5904bc938f9c15b77c613cb6ad6fb30990f3b0afaea82797a402d8"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5bf37a08493232fbb0f8229f1824b366c2fc1d02d64e7e918af40acd15f3e337"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:330e3f10cd01da535c70d09c4283ba2df5fb78e915bea0a28becad6e2ac010be"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e1abbeef02962596548382e393f56e4c94acd286bd0c5afba756cffc33670e8a"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3148362937217b7072cf80a2dcc007f09bb5ecb96dae4617316638194113d5be"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336b40348269f9b91268378de5ff44dc6fbaa2268194f85177b53463d313842a"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b8b09a16a1950b9ef495a0f8b9d0a87599a9d1f179e2d4ac014b2ec831f87e7"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c8e521a0ce7cf690ca84b8cc2272ddaf9d8a50294fd086da67e517439614c755"}, + {file = "Brotli-1.0.9.zip", hash = "sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438"}, +] cachecontrol = [ {file = "CacheControl-0.12.11-py2.py3-none-any.whl", hash = "sha256:2c75d6a8938cb1933c75c50184549ad42728a27e9f6b92fd677c3151aa72555b"}, {file = "CacheControl-0.12.11.tar.gz", hash = "sha256:a5b9fcc986b184db101aa280b42ecdcdfc524892596f606858e0b7a8b4d9e144"}, @@ -5700,6 +5837,86 @@ gevent = [ {file = "gevent-22.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0569e133bb620de1001ac807ad9a8abaadedd25349c6d695f80c9048a3f59d42"}, {file = "gevent-22.10.1.tar.gz", hash = "sha256:df3042349c9a4460eeaec8d0e56d737cb183eed055e75a6af9dbda94aaddaf4d"}, ] +geventhttpclient = [ + {file = "geventhttpclient-2.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd76acdc7e7ee5c54c7b279f806b28957a6b092f79c40db34adcfd972749343c"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:320a2c756d8a4f296de370476a1515485c186d9e22c3fc29e04f8f743a7d47bb"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36d3345c6585b09738195a7c45d279a87ccbab0350f1cce3679d3f0dce8577a1"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:407d54499556c2741b93691b86da93232590b013f4a0b773327d766fe3e5c0a9"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcf325131b0e4600b793643108cd85dddd66bbf532fd2eb498be5727ef532a1e"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5841dd02e6f792a4ef15dbd04fefe620c831ba0b78105808160bb779a31af4"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2ba69422d4e8670dd99803b1313ba574a4d41f52e92b512af51068c9c577bdc1"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e3af579c6b46b9caa515a8baf6a2cadeafcd1d41ad22ca5712851f074a40b47"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6ff7fc19f9a4fdd54a2b1c106a705ea2c679fa049685ed763051d417725bdab1"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-win32.whl", hash = "sha256:eec7c52e8eb817674a193e0124486b507215d9e86d34f2638bf9a9292d16f815"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:0e9f7283c01d970e643d89da81127869a8d94bb7a0081020dcad5b590bc007c4"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5ceb492d43a659b895794999dc40d0e7c23b1d41dd34040bbacd0dc264b57d5b"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95959c201d3151fa8f57e0f1ce184476d1173996bdde41dc7d600006023dc5be"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:31c7febba298ecf44838561074a3fb7a01523adca286469b5a82dcc90e8d6a07"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:996c5f453d810b3c592160193d6832a065cca0112e92adc74e62df0e4c564df6"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f817e226c02b5a71d86de3772d6accdf250288d1e6825e426c713759830162d"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c55b7ac0ba0e1e1afbf297b7608f0b3a0bbc34fb4b0c19b7869f32a77ddc6209"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6775bc81e25c48fa58b034444aecfa508b0c3d1bc1e4ae546cc17661be1f51aa"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a0156882c73537bbbbc7c693ae44c9808119963174078692613ffa4feea21fcf"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ebb582a291c4c5daaac2ea115b413f4be86874baa60def44d333301cee17bd7"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-win32.whl", hash = "sha256:716f1f72f50b841daf9c9511a01fc31a030866510a11863f27741e26e4f556a7"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:777fcdb72077dfbf70516ecb9e9022246dd337b83a4c1e96f17f3ab9e15f4547"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:379d90d8b1fcdda94e74d693806e0b0116c0610504e7f62d5576bac738dc66a5"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00b7b2b836294c091c53789a469c5671202d79420b5191931df4e3a767d607fa"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d075355862d7726eb3436f0136fce7650c884f2d04eaae7a39fed3aad9798bc"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa7b1a27f950d209fe223a97906fe41312dc12c92372424639b8a9b96f1adf91"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fe4e06313aad353b103950780b050d3958000464cc732d621ff8ea3cacbd2bc4"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:84d7be660b6bc53dd53e3f46b3bc5d275972a8116bd183a77139bb4d9d6d9fb1"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:81f839d6becd664d0972b488422f5dc821f8ad2f2196d53aa5e4d799a3a35a66"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:e707f62271a093e6e3af6f1bbd8cc398b414b8c508fe6b15505dd8e76c4409ac"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:28d7655d1d50bc75ece683a0ae8faf978821d4aeae358d77b59371548db07f1e"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58877b4440a580063571a23fbc616aed7c735c6bf9ef525c5129783df8b6966"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57c993c4b2bea551c4a71b75ae1e172e9f3e4352f704ff1b619a0f16aa762f76"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f67e789e31c7b1ce440cd1465dcdefeca29ba6108735eac0b1a593d3a55b7f"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3326e115ec7e7ce95a5d0d47698e8f3584944c4c434a7404937d56b17136b8"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ef328ee3e7dca5055b833fdf3c181647a335abf0249947b27f5df2d95390198c"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:27049ea40e3b559eee380310272aaa9b7c19e73c1d9e51e2ec137362be2caa70"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b88a10538341e33fed1682c0dd4579c655d49db5863e7456583085a1cd6bd9d4"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:d52aba2c38420b3fc518188449f1c2a46b1a99adf1c0266c68e72ee0422cd0fa"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3648626ca58ea4b340e695d78e5d533e6b8be78d375edbd42ff188bc3447e095"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fcf96e212b55b93490f3a5fcdfe7a2ef4995a0d13b7d9df398b11e319b7a86b1"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e9f2ff09706e3a64a99886d5f2595f3bf364821bc609f2865dbc3e499e21a36"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:721c3075897bfc81e918066f16ae3d1a88c7bb14eeeb831a4f89ea636474643e"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91615fed7931acd49cfe5fc30984acd5411dc1f2643b1544c879d1a537233c6d"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7adaa29e5699dea54e0224d1d2d9d8869668d8ad79f5b89433ff9c46f9424a6c"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9be5000ba57336a90b438782117c1e43205f51f49aa9b1499a82e210e8431b11"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:12d271cc53486efb3716e99855dc5cb84f2cd3fc9f3243721747bb39ec0fff8a"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b9c0c6b75b3905000d2490dc64b4c98a8bac155efbc0ff8917ac082ae0bad261"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e956a457d8831dc81d6f046ab09ebeec680f9a1e9c07e25a1906e77b287918ee"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-win32.whl", hash = "sha256:bc46d5479673dfb293ea428c057d2e23e48ebef5c5d44587cdbaada7f87553e4"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:f44153e4b3ef9b901edcd14be54145a0058bf5fa371b3e583153865fac866245"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ebf98db9435824cf0b80b5247be6c88b20bfafd6249f7ebaabb85297da37e380"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c8b7298eb1ebd015257bf4503e34f5fbbe64bd83324140f76b511046aba5a0d5"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:60b81a6d4e65db7c1a5350c9fb72ebf800b478849a7e8020d1ab93af237a3747"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad6c2fcbc3733785bd3b8c2bb43d1f605f9085b0a8b70ce354d198f37143f884"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94edb022fa50d576cf63f6dd0c437c1acd24a719872a5935991aaf08f8e88cb2"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca459cedb3827d960362e05ea3a4ae600a6d0d93de77eac2ac0f79828e5e18c"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7551b6db860b56411de1f96618e91b54f65e1a7be8d10255bd1adfb738bb6ee5"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bcb7e061c243308d9a44b02de5298001e917f1636a9f270c10da86601fcc8dfa"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96922d170ef8933f4c20036e8d70d4fbe861f54c543e32e7459ebdbaafa65a2e"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ebb3c993903d40fd4bb1f3e55b84c62c8fc1d14433ae6d4d477dd9a325354c94"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:dbccf1ba155dea3ea99ba0e67a835c05b4303f05298e85f5bb2a46700ccdf092"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8770b8ab9e8c31d2aaf8a6fbc63fbb7239c58db10bb49cee191ca5c141c61542"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daff1e977fccf98f27266d3891afdc101f1d705a48331754909e960bcae83f8a"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2435e0f2a60e00d977822ec4c12e7851deb7aa49a23d32d648e72c641aae3b05"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09acd03d0a8c1bb7d5a1cb6fcb77aaa19a907c1b4915ab58da5d283675edb0a5"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:5d0813d97050446dab2fb243312e6c446e4ef5e9591befd597ef8f2887f8e2a8"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:852da9bb0fc792cdca5ffc9327490094783e42415494b3569e5d532615027439"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79304a63a9d0512f2757c5862487b332b18a9c85feebecf6ebc3526c6dd1ba2"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c1c783fce45f16db448d7e34864f1e9c22fe60a7780d2c1c14edbb1fb7262e"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77c407c2b4bea817c6f752502db4ab0e9f9465b4fb85b459d1332b5f93a3096c"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f0d70a83ef4ab93102c6601477c13e9cdbc87205e5237fbf5797e30dc9d3ee8"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b03f298ec19b8a4717cce8112fe30322c9e5bfada84dde61a1a44d1eeffc1d3c"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2dc94b9a23eb6744a8c729aec2b1cdc4e39acf1d8f16ea85a62810aa6b2cae5"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:805554594bb29231fd990cc2cbbe493d223d76a6085fec891dd76bb4e0928933"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb23527d98f626ca7a4e8961ed9bdc6aed3388de306614c69a133b34262460f4"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a594ab319872a38fb7f16be4cfb107d3c63c43a081f2abe241834e9877f27401"}, + {file = "geventhttpclient-2.0.2.tar.gz", hash = "sha256:8135a85200b170def7293d01dd1557931fcd1bec1ac78c52ad7cedd22368b9ba"}, +] greenlet = [ {file = "greenlet-1.1.3.post0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3"}, {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589"}, @@ -6679,6 +6896,7 @@ onnx = [ ] onnx2torch = [ {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, + {file = "onnx2torch-1.5.4.tar.gz", hash = "sha256:df837b557a63540223d85fde4a1d679fde0ca8d8bb89d5379c030b01eddc9c24"}, ] onnxoptimizer = [ {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, @@ -7348,6 +7566,64 @@ python-engineio = [ python-logstash = [ {file = "python-logstash-0.4.8.tar.gz", hash = "sha256:d04e1ce11ecc107e4a4f3b807fc57d96811e964a554081b3bbb44732f74ef5f9"}, ] +python-rapidjson = [ + {file = "python-rapidjson-1.10.tar.gz", hash = "sha256:acfecbf5edb91ec72a20a125de7f56b8c2f6161eff4c65382c8ee6a2484d3540"}, + {file = "python_rapidjson-1.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1db7b0af882999f5685eb7046a0f3b3aca5d55a3e84b3089747d29a4ec6fdade"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87c8c8b615513f9dc414af1554140589036d14840f5e1f1845965e1c0a080e1"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0a2f5c4abe529ca2764343416e35710a263832533b7bdc76c3285efb5b5ecc8"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40467c3a6d8f070cc4d196fe46a79ed59d1a13a4d3fdc6a0325a21816600e5a7"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df4e7237a3e77666ccb9b437013294e6aa3968528f7c61f60f6f38eea0f8f79"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:99a5215f24ff1fa6cc67ee275a6852aa56d934d3b8cd7a40197feb632b54fd76"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3dbea0ee9fa1cd6ecc13a949f6bb94013639d39cdb56f58df4ab61130d35e57c"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:6d1d0c5da3bd5f701b1aed550e1e7bd59b16ae642877cddf18815006cf998f9a"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:072f76c1f1483bcc4056d7d3a8b0319bf841a73e955f188302094b62b2163bf9"}, + {file = "python_rapidjson-1.10-cp310-cp310-win32.whl", hash = "sha256:c95d466307a2140a7687a575103980c6e81c9f62d19556cafad3d6b2932b7eb1"}, + {file = "python_rapidjson-1.10-cp310-cp310-win_amd64.whl", hash = "sha256:454ffda58cc6fed64d983b1b8ae4b39a563b4fd671dae9132e06450025898539"}, + {file = "python_rapidjson-1.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fff343076fbeee0cd7e4e3fb9472f2d567a127ec7b8b5b7ecba6bf7960a3ce07"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:686482c67727edad4b6d0c753bc159f35134a5a623e9651c4b7c008ef2996252"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ef7d55688b7123d62690b193537cc048fa9f35cfa43d249fedc0d9fd398890a"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f27c0601792533ab6e98452961d61566480dc155da19d2a358a5fd9a85d9321"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95176e35e3bacb8a1a27f563e815b5b57c717992c871b1c25fd76a835fbba32c"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47a0ec20886b8be86af307c10d699a447e22979ed7dd1f2b7ed5cb7496b3d920"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f7968c0cb09d9a76aa2483556ba46ab42634baf216cb2f2c7cd6bf77119a33c1"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5faab270a4dd49216ceaca7169682680b2f5df8311c1ed259e4612d9d0cf61b7"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:81b797934dc037810f5f98af138b55a3b6f18dd569cc5e8f81fe79956a4717ca"}, + {file = "python_rapidjson-1.10-cp311-cp311-win32.whl", hash = "sha256:6c1d62cc58a61629fc5e216fb7b3a1b02787c98fded874a7b474b1e6325e377e"}, + {file = "python_rapidjson-1.10-cp311-cp311-win_amd64.whl", hash = "sha256:29d31fc4254f1a4dca420e58bd1331e990fc2959d09ff2daa7934d52732a8491"}, + {file = "python_rapidjson-1.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:718f4e217b511cfbf9166f55ccf4bf4e4538495bee403e390cf89791c0debc26"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:541bbb96353cf3fe2bdb29e727087226532be4e4573daad6f042cfdea533a564"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50f0402a6899c6a177d4a37152deefcd59c61e44bef56b71e8d006a186c86286"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c035e17744d6d6fba073b550b0040a74e55f2ad33fd798df206ff6879b41ad10"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da970bde42309a74a5556e696673ea11c4545b8bee5081b84265ded460b2e9ef"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7437a649821008aa456f2fbec737880d7f9bdda7ec94cc1743a43ccf32b5d26"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:362d969bbd277f78bf0b1ffaa810857ea40351146b827f896f8d49e9c25fc99c"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:409256e7748c4ab7f17b3793c7a78ca01914c487644fc42140d116ed4dec8c4f"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a34a7e2853456fe50ba2ee22e38e7841e55eee10021d4496cce62285f148e8e7"}, + {file = "python_rapidjson-1.10-cp37-cp37m-win32.whl", hash = "sha256:bc4a97940e5afa60a598483d0eb863b26e4810aaf030d92a4301f5fc183e1b6d"}, + {file = "python_rapidjson-1.10-cp37-cp37m-win_amd64.whl", hash = "sha256:89586b67f9c69b66885774acebf3d018e7b8f93cea2b3cffa306ec9d37877594"}, + {file = "python_rapidjson-1.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2e38082b1a8ce3e2bd55821852c0cd643cdabe6497fd9c054f6b47a099afbea0"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0955ef22fabb36b26fcad702ae54c1bce2bc2a74b1883c42d251d72011d0d426"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9db03c68ab0158bcdf80299b2c980186d148aa3e05d5650fea5148a425a29a"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde8ab0f06debaa06d93085f19dc3ec3db53f22883f1625dd32b96a87e7009de"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23539c9f7d85d64a00d3cb44c7d9ab3be2184d4da42a5f3263dcfd1d0203ee43"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bfd484285f3477acef0bb45abd2b80b6252e35a5a53395ce48f0327cbe43c23"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8b0ed643ebaa8ddf3f40422752efe83abda29aa30a9e6866ccd9dd591b5057d0"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:5aeca661a0f229f1312fb3ad3e1a5c6736d49942d80d4931810158559eb8f119"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8a68ed066e8f0878b7112f943cf35ba9e5217395bcdd8cb478cde01871e2701c"}, + {file = "python_rapidjson-1.10-cp38-cp38-win32.whl", hash = "sha256:d286be6f63446776c4958bb37824c683194b4878fc9cd5b7255134fb5a6ba536"}, + {file = "python_rapidjson-1.10-cp38-cp38-win_amd64.whl", hash = "sha256:aece5270c6e6d5c3d54586c9a5fb9677d70d7019744a59560c5c369c7b9bba25"}, + {file = "python_rapidjson-1.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc09c5ad0fe71f262cdcc5655409f132f1560a8af80e76e7757945ce401fdbab"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f6447bd7a8ff5135ab7e372b48a174d3c560d5b322e32bd465e8458e6e4593"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22ede69213885391b46cc14596bfd4cd1a5c6f34a2db6600fb08b03982dbc7b7"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a9425129623718a04b885a12190faa23e7997c4e8632054e18df7ea473f746d"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60e10f32e1a8d155448842934cbe71eb620b4b4a0cb3627ba4c4856e27556534"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8d23caab17b87ed5b82e28cdc19172ba1ca65c982e3fff387961d3f33710031f"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f07d4fcdcfd64bdad0143b9705c5d5089677ebddf60ac6c1f8074a34b1c70cf9"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:87b991c7ae435489c56a46cef228d2b65a3df689ee4fe24fab69c791c841f633"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3706a5c4f21073c04be133c36565efc6e3f5646a03c8d19af78c19d7c70eb708"}, + {file = "python_rapidjson-1.10-cp39-cp39-win32.whl", hash = "sha256:47f9078ea6884f700166a8728d863609fec62232e66a33b8fb4a7706ce7c731c"}, + {file = "python_rapidjson-1.10-cp39-cp39-win_amd64.whl", hash = "sha256:9e4921ab7002ae9faad7f439a7c50aa195039f177e9e51a76c34c97966c79a79"}, +] python-socketio = [ {file = "python-socketio-5.7.2.tar.gz", hash = "sha256:92395062d9db3c13d30e7cdedaa0e1330bba78505645db695415f9a3c628d097"}, {file = "python_socketio-5.7.2-py3-none-any.whl", hash = "sha256:d9a9f047e6fdd306c852fbac36516f4b495c2096f8ad9ceb8803b8e5ff5622e3"}, @@ -7721,6 +7997,18 @@ setproctitle = [ {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, + {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, + {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, @@ -8090,6 +8378,15 @@ traitlets = [ {file = "traitlets-5.5.0.tar.gz", hash = "sha256:b122f9ff2f2f6c1709dab289a05555be011c87828e911c0cf4074b85cb780a79"}, ] triton = [ + {file = "triton-2.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38806ee9663f4b0f7cd64790e96c579374089e58f49aac4a6608121aa55e2505"}, + {file = "triton-2.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:226941c7b8595219ddef59a1fdb821e8c744289a132415ddd584facedeb475b1"}, + {file = "triton-2.0.0-1-cp36-cp36m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4c9fc8c89874bc48eb7e7b2107a9b8d2c0bf139778637be5bfccb09191685cfd"}, + {file = "triton-2.0.0-1-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d2684b6a60b9f174f447f36f933e9a45f31db96cb723723ecd2dcfd1c57b778b"}, + {file = "triton-2.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d4978298b74fcf59a75fe71e535c092b023088933b2f1df933ec32615e4beef"}, + {file = "triton-2.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:74f118c12b437fb2ca25e1a04759173b517582fcf4c7be11913316c764213656"}, + {file = "triton-2.0.0-1-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9618815a8da1d9157514f08f855d9e9ff92e329cd81c0305003eb9ec25cc5add"}, + {file = "triton-2.0.0-1-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aca3303629cd3136375b82cb9921727f804e47ebee27b2677fef23005c3851a"}, + {file = "triton-2.0.0-1-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e3e13aa8b527c9b642e3a9defcc0fbd8ffbe1c80d8ac8c15a01692478dc64d8a"}, {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"}, {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"}, {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"}, @@ -8100,6 +8397,10 @@ triton = [ {file = "triton-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42a0d2c3fc2eab4ba71384f2e785fbfd47aa41ae05fa58bf12cb31dcbd0aeceb"}, {file = "triton-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c47b72c72693198163ece9d90a721299e4fb3b8e24fd13141e384ad952724f"}, ] +tritonclient = [ + {file = "tritonclient-2.28.0-py3-none-any.whl", hash = "sha256:1f58bbe09a88c35f7979de8ab6579a5337372951f723c0aba31e8bee3e8d79da"}, + {file = "tritonclient-2.28.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:47d93197a0876a743012db4c03f1100f7b225b9aaf8d5f8025bf4a5d9e61bfd2"}, +] types-atomicwrites = [ {file = "types-atomicwrites-1.4.5.1.tar.gz", hash = "sha256:9e9f0923ebf93524b28bcece5a23ac8c3820f39b060df29f671936d2e4bc04bc"}, {file = "types_atomicwrites-1.4.5.1-py3-none-any.whl", hash = "sha256:2f1febbdc78b55453b189fa5b136dce34bab7d1d82319163d470e404aab55c83"}, diff --git a/pyproject.toml b/pyproject.toml index 7506ee552d..47994779b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -174,6 +174,7 @@ Werkzeug = "^2.1.2" zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } omegaconf = "^2.3.0" osmnx = "==1.2.2" +tritonclient = {version = "2.28.0", extras = ["http"]} [build-system] From c25ce02639a86f6627314ecd3b3c101d82d7498f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 24 Mar 2023 16:48:07 -0700 Subject: [PATCH 076/143] tici: turn off fan after boot (#27680) * tici: turn off fan after boot * tmp if --------- Co-authored-by: Comma Device --- system/hardware/tici/hardware.py | 6 ++++++ system/hardware/tici/pins.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 9c1cc930c1..46db097da1 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -452,6 +452,12 @@ class Tici(HardwareBase): # Allow thermald to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") + # TODO: remove the if once agnos 7 ships + # Turn off fan, turned on by the ABL + if os.path.exists('/sys/class/gpio/gpio49/'): + gpio_init(GPIO.SOM_ST_IO, True) + gpio_set(GPIO.SOM_ST_IO, 0) + # *** IRQ config *** # move these off the default core diff --git a/system/hardware/tici/pins.py b/system/hardware/tici/pins.py index fe31b9311d..082a402f15 100644 --- a/system/hardware/tici/pins.py +++ b/system/hardware/tici/pins.py @@ -10,6 +10,8 @@ class GPIO: STM_RST_N = 124 STM_BOOT0 = 134 + SOM_ST_IO = 49 + LTE_RST_N = 50 LTE_PWRKEY = 116 LTE_BOOT = 52 From b2beb3792ec34dd1cc3bf554b845f5f496812343 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 17:44:49 -0700 Subject: [PATCH 077/143] Lexus: LSS is standard on ES (#27684) * standard on 17 and 18 https://dealerinspire-brochure.s3.amazonaws.com/834.pdf & https://www.lexus.com/content/dam/lexus/documents/brochures/models/2018/MY18-Lexus-ES-and-ES-Hybrid-Brochure.pdf * update docs --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 1f668dbe8b..d9eef56215 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -126,7 +126,7 @@ A supported vehicle is one that just works when you install a comma three. All s |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)](##)|Hyundai H|| |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)](##)|Toyota|| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|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)](##)|Toyota|| |Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |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)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 4edafc0c28..190f7faa61 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -168,7 +168,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { # Lexus CAR.LEXUS_CTH: ToyotaCarInfo("Lexus CT Hybrid 2017-18", "Lexus Safety System+"), - CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18", "Lexus Safety System+"), + CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18"), CAR.LEXUS_ES_TSS2: ToyotaCarInfo("Lexus ES 2019-22"), CAR.LEXUS_ESH_TSS2: ToyotaCarInfo("Lexus ES Hybrid 2019-23", video_link="https://youtu.be/BZ29osRVJeg?t=12"), CAR.LEXUS_IS: ToyotaCarInfo("Lexus IS 2017-19"), From c2bdbaa3462808bbe274d0adcb4f08ba9609dd90 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 17:48:31 -0700 Subject: [PATCH 078/143] Lexus: 2017 RC is not supported (#27678) we don't support 2017 --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index d9eef56215..3e23316bd8 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -133,7 +133,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |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)](##)|Toyota|| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |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)](##)|Toyota|| |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)](##)|Toyota|| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 190f7faa61..2398e012d6 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -176,7 +176,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19"), CAR.LEXUS_NX_TSS2: ToyotaCarInfo("Lexus NX 2020-21"), CAR.LEXUS_NXH_TSS2: ToyotaCarInfo("Lexus NX Hybrid 2020-21"), - CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2017-20"), + CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2018-20"), CAR.LEXUS_RX: [ ToyotaCarInfo("Lexus RX 2016", "Lexus Safety System+"), ToyotaCarInfo("Lexus RX 2017-19"), From d443d8f5e30e2d9110893c181d433fe9af2d91e9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 19:11:50 -0700 Subject: [PATCH 079/143] VW: add missing Arteon 2019 FW (#27671) * add missing arteon 2019 fw * duplicate --- selfdrive/car/volkswagen/values.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index e63975b0c0..bdd82088a1 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -293,6 +293,7 @@ FW_VERSIONS = { 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\x8709G927158L \xf1\x893611', @@ -304,17 +305,19 @@ FW_VERSIONS = { 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', ], (Ecu.eps, 0x712, None): [ b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571B41815A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571B00817A1', - b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\00567B0020800', + b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567B0020800', b'\xf1\x875WA907145M \xf1\x891051\xf1\x82\x002MB4092M7N', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572AA\xf1\x890396', b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x875Q0907572J \xf1\x890654', + b'\xf1\x875Q0907572R \xf1\x890771', ], }, CAR.ATLAS_MK1: { From b61a0b785af911d12816d405edc8e904416a6271 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 20:07:11 -0700 Subject: [PATCH 080/143] Toyota: use DBC for alt brake safety param (#27686) * use DBC * use DBC --- selfdrive/car/toyota/interface.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index e6476863c3..33a87451e9 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,7 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ +from selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -21,7 +21,8 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] - if candidate in (CAR.RAV4, CAR.PRIUS_V, CAR.COROLLA, CAR.LEXUS_ESH, CAR.LEXUS_CTH): + # BRAKE_MODULE is on a different address for these cars + if DBC[candidate]["pt"] == "toyota_new_mc_pt_generated": ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_ALT_BRAKE if candidate in ANGLE_CONTROL_CAR: From 33afefd346e4348aacb122a486066741731b7d05 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 25 Mar 2023 12:54:41 +0800 Subject: [PATCH 081/143] cabana: enables user to select the zoom area when the mouse press on the data point (#27679) zoom anywhere --- tools/cabana/chartswidget.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index c98ca3bc69..72c9e1ba91 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -9,8 +9,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -849,6 +850,13 @@ QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); + + // disables the delivery of mouse events to the opengl widget. + // this enables the user to select the zoom area when the mouse press on the data point. + auto glwidget = findChild(); + if (glwidget && !glwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) { + glwidget->setAttribute(Qt::WA_TransparentForMouseEvents); + } return series; } From 084e83cda1415189539755343e74e9342e7ec42d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 25 Mar 2023 01:02:11 -0700 Subject: [PATCH 082/143] FPv2: replace temporary variable with config (#27692) * query extra ecus (still need to match) * match against extra ecus * clean p * clean p * switch that around * can clean that up * values * rm * not used --- selfdrive/car/fw_versions.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 9bb04ee821..6918913f80 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -19,7 +19,7 @@ FW_QUERY_CONFIGS = get_interface_attr('FW_QUERY_CONFIG', ignore_none=True) VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True) MODEL_TO_BRAND = {c: b for b, e in VERSIONS.items() for c in e} -REQUESTS = [(brand, r) for brand, config in FW_QUERY_CONFIGS.items() for r in config.requests] +REQUESTS = [(brand, config, r) for brand, config in FW_QUERY_CONFIGS.items() for r in config.requests] def chunks(l, n=128): @@ -153,7 +153,7 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []} responses = set() - for brand, r in REQUESTS: + for brand, _, r in REQUESTS: # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue @@ -190,9 +190,9 @@ def get_brand_ecu_matches(ecu_rx_addrs): """Returns dictionary of brands and matches with ECUs in their FW versions""" brand_addrs = get_brand_addrs() - brand_matches = {brand: set() for brand, _ in REQUESTS} + brand_matches = {brand: set() for brand, _, _ in REQUESTS} - brand_rx_offsets = set((brand, r.rx_offset) for brand, r in REQUESTS) + brand_rx_offsets = set((brand, r.rx_offset) for brand, _, r in REQUESTS) for addr, sub_addr, _ in ecu_rx_addrs: # Since we can't know what request an ecu responded to, add matches for all possible rx offsets for brand, rx_offset in brand_rx_offsets: @@ -247,19 +247,15 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # ECUs using a subaddress need be queried one by one, the rest can be done in parallel addrs = [] parallel_addrs = [] - logging_addrs = [] ecu_types = {} for brand, brand_versions in versions.items(): - for candidate, ecu in brand_versions.items(): + for ecu in brand_versions.values(): for ecu_type, addr, sub_addr in ecu.keys(): a = (brand, addr, sub_addr) if a not in ecu_types: ecu_types[a] = ecu_type - if a not in logging_addrs and candidate == "debug": - logging_addrs.append(a) - if sub_addr is None: if a not in parallel_addrs: parallel_addrs.append(a) @@ -271,10 +267,10 @@ 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, r) for brand, r in REQUESTS if query_brand is None or brand == query_brand] + requests = [(brand, config, r) for brand, config, r in REQUESTS if query_brand is None or brand == query_brand] for addr in tqdm(addrs, disable=not progress): for addr_chunk in chunks(addr): - for brand, r in requests: + for brand, config, r in requests: # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue @@ -292,15 +288,14 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, for (tx_addr, sub_addr), version in query.get_data(timeout).items(): f = car.CarParams.CarFw.new_message() - ecu_key = (brand, tx_addr, sub_addr) - f.ecu = ecu_types.get(ecu_key, Ecu.unknown) + f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown) f.fwVersion = version f.address = tx_addr f.responseAddress = uds.get_rx_addr_for_tx_addr(tx_addr, r.rx_offset) f.request = r.request f.brand = brand f.bus = r.bus - f.logging = r.logging or ecu_key in logging_addrs + f.logging = r.logging or (f.ecu, tx_addr, sub_addr) in config.extra_ecus f.obdMultiplexing = r.obd_multiplexing if sub_addr is not None: From 6f35d23c062ab000af90f5a0d7704eab8682479d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 25 Mar 2023 01:07:58 -0700 Subject: [PATCH 083/143] FPv2: match brand against extra ecus (#27688) * query extra ecus (still need to match) * match against extra ecus * clean p * clean p * switch that around * can clean that up * values --- selfdrive/car/fw_versions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 6918913f80..f85b7f6b7d 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -39,6 +39,8 @@ def build_fw_dict(fw_versions, filter_brand=None): def get_brand_addrs(): brand_addrs = 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 @@ -153,13 +155,13 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []} responses = set() - for brand, _, r in REQUESTS: + for brand, config, r in REQUESTS: # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue for brand_versions in VERSIONS[brand].values(): - for ecu_type, addr, sub_addr in brand_versions: + for ecu_type, addr, sub_addr in list(brand_versions) + config.extra_ecus: # Only query ecus in whitelist if whitelist is not empty if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus: a = (addr, sub_addr, r.bus) From c77a0feab4e8474f73e47d7f111f3f41f0d68ff3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 06:38:41 +0800 Subject: [PATCH 084/143] cabana: fix high DPI issues in chart (#27694) --- tools/cabana/chartswidget.cc | 79 +++++++++++++++++++----------------- tools/cabana/chartswidget.h | 6 +-- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 72c9e1ba91..a6eabfd1ae 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -21,7 +21,7 @@ static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; } // ChartsWidget -ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { +ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -89,6 +89,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { range_slider->setValue(max_chart_range); updateToolBar(); + align_timer.setSingleShot(true); + QObject::connect(&align_timer, &QTimer::timeout, this, &ChartsWidget::alignCharts); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &AbstractStream::updated, this, &ChartsWidget::updateState); @@ -200,7 +202,7 @@ ChartView *ChartsWidget::createChart() { QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); - QObject::connect(chart, &ChartView::axisYLabelWidthChanged, this, &ChartsWidget::alignCharts); + QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start)); charts.push_back(chart); updateLayout(); return chart; @@ -312,7 +314,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { axis_y = new QValueAxis(this); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); - chart->legend()->layout()->setContentsMargins(16, 0, 40, 0); + chart->legend()->layout()->setContentsMargins(0, 0, 0, 0); chart->legend()->setShowToolTips(true); chart->setMargins({0, 0, 0, 0}); @@ -438,24 +440,34 @@ void ChartView::manageSeries() { } void ChartView::resizeEvent(QResizeEvent *event) { - updatePlotArea(align_to); - int top_margin = style()->pixelMetric(QStyle::PM_LayoutTopMargin); - int spacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); - int x = event->size().width() - close_btn_proxy->size().width() - style()->pixelMetric(QStyle::PM_LayoutRightMargin); - close_btn_proxy->setPos(x, top_margin); - manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - spacing, top_margin); - move_icon->setPos(style()->pixelMetric(QStyle::PM_LayoutLeftMargin), top_margin); + qreal left, top, right, bottom; + chart()->layout()->getContentsMargins(&left, &top, &right, &bottom); + move_icon->setPos(left, top); + close_btn_proxy->setPos(rect().right() - right - close_btn_proxy->size().width(), top); + int x = close_btn_proxy->pos().x() - manage_btn_proxy->size().width() - style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + manage_btn_proxy->setPos(x, top); + chart()->legend()->setGeometry({move_icon->sceneBoundingRect().topRight(), manage_btn_proxy->sceneBoundingRect().bottomLeft()}); + if (align_to > 0) { + updatePlotArea(align_to); + } QChartView::resizeEvent(event); } -void ChartView::updatePlotArea(int left) { - QRect r = rect(); - if (align_to != left || r != background->rect()) { - align_to = left; - background->setRect(r); - chart()->legend()->setGeometry(QRect(r.left(), r.top(), r.width(), 45)); - chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 36, r.height() - 80)); +void ChartView::updatePlotArea(int left_pos) { + if (align_to != left_pos || rect() != background->rect()) { + align_to = left_pos; + background->setRect(rect()); + + qreal left, top, right, bottom; + chart()->layout()->getContentsMargins(&left, &top, &right, &bottom); + QSizeF x_label_size = QFontMetrics(axis_x->labelsFont()).size(Qt::TextSingleLine, QString::number(axis_x->max(), 'f', 2)); + x_label_size += QSizeF{5 * devicePixelRatioF(), 5 * devicePixelRatioF()}; + int adjust_top = chart()->legend()->geometry().height() + style()->pixelMetric(QStyle::PM_LayoutTopMargin); + chart()->setPlotArea(rect().adjusted(align_to + left, adjust_top + top, -x_label_size.width() / 2 - right, -x_label_size.height() - bottom)); chart()->layout()->invalidate(); + if (can->isPaused()) { + update(); + } } } @@ -476,7 +488,6 @@ void ChartView::updatePlot(double cur, double min, double max) { updateAxisY(); updateSeriesPoints(); } - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } @@ -490,7 +501,7 @@ void ChartView::updateSeriesPoints() { int pixels_per_point = width() / num_points; if (series_type == SeriesType::Scatter) { - ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8)); + ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8) * devicePixelRatioF()); } else { s.series->setPointsVisible(pixels_per_point > 20); } @@ -508,7 +519,7 @@ void ChartView::updateSeries(const cabana::Signal *sig) { s.series->setColor(getColor(s.sig)); auto msgs = can->events().at(s.msg_id); - auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time=s.last_value_mono_time}); + auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = s.last_value_mono_time}); int new_size = std::max(s.vals.size() + std::distance(first, msgs.cend()), settings.max_cached_minutes * 60 * 100); if (s.vals.capacity() <= new_size) { s.vals.reserve(new_size * 2); @@ -569,7 +580,7 @@ void ChartView::updateAxisY() { if (axis_y->titleText() != unit) { axis_y->setTitleText(unit); - y_label_width = 0;// recalc width + y_label_width = 0; // recalc width } double delta = std::abs(max - min) < 1e-3 ? 1 : (max - min) * 0.05; @@ -578,10 +589,10 @@ void ChartView::updateAxisY() { axis_y->setRange(min_y, max_y); axis_y->setTickCount(tick_count); + int title_spacing = unit.isEmpty() ? 0 : QFontMetrics(axis_y->titleFont()).size(Qt::TextSingleLine, unit).height(); QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; - int title_spacing = axis_y->titleText().isEmpty() ? 0 : 20; - y_label_width = title_spacing + qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 + y_label_width = title_spacing + qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; axis_y->setLabelFormat(QString("%.%1f").arg(n)); emit axisYLabelWidthChanged(y_label_width); } @@ -628,10 +639,7 @@ void ChartView::mousePressEvent(QMouseEvent *event) { drag->setMimeData(mimeData); drag->setPixmap(grab()); drag->setHotSpot(event->pos()); - Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction); - if (dropAction == Qt::MoveAction) { - return; - } + drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction); } else if (event->button() == Qt::LeftButton && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { if (!can->liveStreaming()) { // Save current playback state when scrubbing @@ -639,7 +647,6 @@ void ChartView::mousePressEvent(QMouseEvent *event) { if (resume_after_scrub) { can->pause(true); } - is_scrubbing = true; } } else { @@ -687,20 +694,18 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } void ChartView::mouseMoveEvent(QMouseEvent *ev) { + const auto plot_area = chart()->plotArea(); // Scrubbing if (is_scrubbing && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { - if (chart()->plotArea().contains(ev->pos())) { - double t = chart()->mapToValue(ev->pos()).x(); - // Prevent seeking past the end of the route - t = std::clamp(t, 0., can->totalSeconds()); - can->seekTo(t); + if (plot_area.contains(ev->pos())) { + can->seekTo(std::clamp(chart()->mapToValue(ev->pos()).x(), 0., can->totalSeconds())); } return; } auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); - const auto plot_area = chart()->plotArea(); + is_scrubbing = false; clearTrackPoints(); if (!is_zooming && plot_area.contains(ev->pos())) { @@ -838,8 +843,8 @@ QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { chart()->legend()->setMarkerShape(QLegend::MarkerShapeCircle); } series->setColor(color); - // TODO: Due to a bug in CameraWidget the camera frames - // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed + // TODO: Due to a bug in CameraWidget the camera frames + // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed #ifndef __APPLE__ series->setUseOpenGL(true); // Qt doesn't properly apply device pixel ratio in OpenGL mode @@ -939,7 +944,7 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) QObject::connect(available_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::add); QObject::connect(selected_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::remove); QObject::connect(add_btn, &QPushButton::clicked, [this]() { if (auto item = available_list->currentItem()) add(item); }); - QObject::connect(remove_btn, &QPushButton::clicked, [this]() { if (auto item = selected_list->currentItem()) remove(item);}); + QObject::connect(remove_btn, &QPushButton::clicked, [this]() { if (auto item = selected_list->currentItem()) remove(item); }); QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index c7470a6f12..731be47d06 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -1,12 +1,11 @@ #pragma once -#include #include #include #include #include #include -#include +#include #include #include #include @@ -122,7 +121,7 @@ private: void resizeEvent(QResizeEvent *event) override; void alignCharts(); void newChart(); - ChartView * createChart(); + ChartView *createChart(); void removeChart(ChartView *chart); void eventsMerged(); void updateState(); @@ -154,6 +153,7 @@ private: QAction *columns_action; int column_count = 1; int current_column_count = 0; + QTimer align_timer; }; class SeriesSelector : public QDialog { From 8150e4a4b864e266bac4a0f4cc95816424f0d463 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 06:38:55 +0800 Subject: [PATCH 085/143] cabana: support qlogs (#27689) --- tools/cabana/streams/replaystream.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 140a795d3a..8bc9af8ab2 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -33,11 +33,6 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir) { QObject::connect(replay.get(), &Replay::streamStarted, this, &AbstractStream::streamStarted); QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments); if (replay->load()) { - const auto &segments = replay->route()->segments(); - if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { - qWarning() << "no rlogs in route" << route; - return false; - } replay->start(); return true; } From 8bd4c0f5103d09ef90313ba4b6a55d51ff27744d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 06:39:21 +0800 Subject: [PATCH 086/143] cabana: update state after creating new signal (#27690) --- tools/cabana/signaledit.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 4cd06e8a7d..99ec09195b 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -279,6 +279,7 @@ void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) { beginInsertRows({}, i, i); insertItem(root.get(), i, sig); endInsertRows(); + updateState(nullptr); } } From 583c4a031f433fb4b48c5dc0a522b71cdbd6f23c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 07:03:16 +0800 Subject: [PATCH 087/143] cabana: improve LogSlider (#27673) * improve logslider * fix code indentation --- tools/cabana/util.cc | 28 ++++++++++++---------------- tools/cabana/util.h | 23 ++++++++++++++++------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index b37b7911ed..e5a9749103 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -4,10 +4,8 @@ #include #include #include -#include - -#include #include +#include #include "selfdrive/ui/qt/util.h" @@ -42,7 +40,7 @@ void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { } // Track bit level changes - for (int bit = 0; bit < 8; bit++){ + for (int bit = 0; bit < 8; bit++) { if ((cur ^ last) & (1 << bit)) { bit_change_counts[i][bit] += 1; } @@ -67,7 +65,6 @@ void ChangeTracker::clear() { colors.clear(); } - // SegmentTree void SegmentTree::build(const QVector &arr) { @@ -116,7 +113,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); QRect rc{option.rect.left() + h_margin, option.rect.top() + v_margin, byte_width, option.rect.height() - 2 * v_margin}; - auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText: QPalette::Text; + auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text; painter->setPen(option.palette.color(color_role)); painter->setFont(fixed_font); for (int i = 0; i < byte_list.size(); ++i) { @@ -139,7 +136,7 @@ QColor getColor(const cabana::Signal *sig) { return QColor::fromHsvF(h, s, v); } -NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) { } +NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) {} QValidator::State NameValidator::validate(QString &input, int &pos) const { input.replace(' ', '_'); @@ -175,7 +172,6 @@ QToolButton *toolButton(const QString &icon, const QString &tooltip) { return btn; }; - QString toHex(uint8_t byte) { static std::array hex = []() { std::array ret; @@ -186,11 +182,11 @@ 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(); - } - } + const QString string = QString::number(num); + const QStringList split = string.split('.'); + if (split.size() == 1) { + return 0; + } else { + return split[1].size(); + } +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 3cf14982a9..330da77179 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -36,17 +36,26 @@ class LogSlider : public QSlider { public: LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {}; - void setRange(double min, double max) { QSlider::setRange(logScale(min), logScale(max)); } - int value() const { return invLogScale(QSlider::value()); } - void setValue(int value) { QSlider::setValue(logScale(value)); } + void setRange(double min, double max) { + log_min = factor * std::log10(min); + log_max = factor * std::log10(max); + QSlider::setRange(min, max); + setValue(QSlider::value()); + } + int value() const { + double v = log_min + (log_max - log_min) * ((QSlider::value() - minimum()) / double(maximum() - minimum())); + return std::lround(std::pow(10, v / factor)); + } + void setValue(int v) { + double log_v = std::clamp(factor * std::log10(v), log_min, log_max); + v = minimum() + (maximum() - minimum()) * ((log_v - log_min) / (log_max - log_min)); + QSlider::setValue(v); + } private: - double factor; - int logScale(int value) const { return factor * std::log10(value); } - int invLogScale(int value) const { return std::pow(10, value / factor); } + double factor, log_min = 0, log_max = 1; }; - enum { ColorsRole = Qt::UserRole + 1, BytesRole = Qt::UserRole + 2 From 083f008d94a037174f27417c6e2d1698f7ee897f Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Sun, 26 Mar 2023 21:06:33 -0300 Subject: [PATCH 088/143] caban: fix typo (#27700) --- tools/cabana/mainwin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index b7cfd9dc2a..c739e26744 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -336,7 +336,7 @@ void MainWindow::loadDBCFromFingerprint() { if (can->liveStreaming()) { video_dock->setWindowTitle(can->routeName()); } else { - video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPRINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); } if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; From b418cbcbcfd5d51fd802477345255645941c0d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 26 Mar 2023 22:17:30 -0700 Subject: [PATCH 089/143] Laikad: catch and log ephemerides parsing errors (#27698) * Laikad: catch and log ephemerides parsing errors * exception instead of error --- selfdrive/locationd/laikad.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 59176c586b..098b79d2e2 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -220,18 +220,30 @@ class Laikad: # TODO this is not robust to gps week rollover if self.gps_week is None: return - ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) - self.astro_dog.add_qcom_polys({ephem.prn: [ephem]}) + try: + ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) + self.astro_dog.add_qcom_polys({ephem.prn: [ephem]}) + except Exception as e: + cloudlog.exception(f"Error parsing qcom svPoly ephemeris from qcom module: {e}") + return else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct, file_name='ublox') + try: + ephem = GPSEphemeris(data_struct, file_name='ublox') + except Exception as e: + cloudlog.exception(f"Error parsing GPS ephemeris from ublox: {e}") + return elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct, file_name='ublox') + try: + ephem = GLONASSEphemeris(data_struct, file_name='ublox') + except Exception as e: + cloudlog.exception(f"Error parsing GLONASS ephemeris from ublox: {e}") + return else: - cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") + cloudlog.exception(f"Unsupported ephemeris type: {gnss_msg.which()}") return self.astro_dog.add_navs({ephem.prn: [ephem]}) self.cache_ephemeris() From 28cd8fc402bf47b119f960bd2bb511468f43d230 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 26 Mar 2023 23:06:09 -0700 Subject: [PATCH 090/143] laikad: clean up cloudlog usage (#27701) make an error, no need to pass e --- selfdrive/locationd/laikad.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 098b79d2e2..0c0bcbf7ef 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -223,8 +223,8 @@ class Laikad: try: ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) self.astro_dog.add_qcom_polys({ephem.prn: [ephem]}) - except Exception as e: - cloudlog.exception(f"Error parsing qcom svPoly ephemeris from qcom module: {e}") + except Exception: + cloudlog.exception("Error parsing qcom svPoly ephemeris from qcom module") return else: @@ -232,18 +232,18 @@ class Laikad: data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) try: ephem = GPSEphemeris(data_struct, file_name='ublox') - except Exception as e: - cloudlog.exception(f"Error parsing GPS ephemeris from ublox: {e}") + except Exception: + cloudlog.exception("Error parsing GPS ephemeris from ublox") return elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) try: ephem = GLONASSEphemeris(data_struct, file_name='ublox') - except Exception as e: - cloudlog.exception(f"Error parsing GLONASS ephemeris from ublox: {e}") + except Exception: + cloudlog.exception("Error parsing GLONASS ephemeris from ublox") return else: - cloudlog.exception(f"Unsupported ephemeris type: {gnss_msg.which()}") + cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return self.astro_dog.add_navs({ephem.prn: [ephem]}) self.cache_ephemeris() From 4ab2131ec9e21d9784f2f423bd6b21c9914cd661 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Mon, 27 Mar 2023 19:29:44 +0200 Subject: [PATCH 091/143] cabana: add support for multiple DBC files (#27435) * split out dbc file logic into separate file * emit dbc file changed * change to list of dbc files * handle missing DBC file * dbcmanager emits signal * close existing files before loading new one * add placeholder open for bus menu * implement open dbc for bus * emit signals relevant for current dbc * move logic into findDBC * fix use after free * show currently loaded names in load dialog * enable/disable load save menus * handle saving * add save as to recents * handle file already open * do not assert * fix return and throw on file open error * fix test maybe * remove todo * typo * fix new dbc * fix loading fingerprint on macos * handle replacing a currently open dbc * fix reference and handle exception * fix indendation --- tools/cabana/SConscript | 2 +- tools/cabana/dbcfile.cc | 283 ++++++++++++++++++++++++ tools/cabana/dbcfile.h | 55 +++++ tools/cabana/dbcmanager.cc | 305 +++++++++++++------------- tools/cabana/dbcmanager.h | 61 +++--- tools/cabana/mainwin.cc | 200 ++++++++++++----- tools/cabana/mainwin.h | 18 +- tools/cabana/streams/abstractstream.h | 4 +- tools/cabana/tests/test_cabana.cc | 15 +- tools/cabana/tools/findsimilarbits.cc | 2 +- 10 files changed, 686 insertions(+), 259 deletions(-) create mode 100644 tools/cabana/dbcfile.cc create mode 100644 tools/cabana/dbcfile.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 3cb5913c01..5f4f7fc524 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -28,7 +28,7 @@ cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "asset prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbc.cc', 'dbcmanager.cc', +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbc.cc', 'dbcfile.cc', 'dbcmanager.cc', 'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) diff --git a/tools/cabana/dbcfile.cc b/tools/cabana/dbcfile.cc new file mode 100644 index 0000000000..14a98347e2 --- /dev/null +++ b/tools/cabana/dbcfile.cc @@ -0,0 +1,283 @@ +#include "tools/cabana/dbcfile.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + + +DBCFile::DBCFile(const QString &dbc_file_name, QObject *parent) : QObject(parent) { + QFile file(dbc_file_name); + if (file.open(QIODevice::ReadOnly)) { + name_ = QFileInfo(dbc_file_name).baseName(); + + // Remove auto save file extension + if (dbc_file_name.endsWith(AUTO_SAVE_EXTENSION)) { + filename = dbc_file_name.left(dbc_file_name.length() - AUTO_SAVE_EXTENSION.length()); + } else { + filename = dbc_file_name; + } + open(file.readAll()); + } else { + throw std::runtime_error("Failed to open file."); + } +} + +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.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(); + } + } + parseExtraInfo(content); + + delete dbc; +} + +bool DBCFile::save() { + assert (!filename.isEmpty()); + if (writeContents(filename)) { + cleanupAutoSaveFile(); + return true; + } else { + return false; + } +} + +bool DBCFile::saveAs(const QString &new_filename) { + filename = new_filename; + return save(); +} + +bool DBCFile::autoSave() { + if (!filename.isEmpty()) { + return writeContents(filename + AUTO_SAVE_EXTENSION); + } else { + return false; + } +} + +void DBCFile::cleanupAutoSaveFile() { + if (!filename.isEmpty()) { + QFile::remove(filename + AUTO_SAVE_EXTENSION); + } +} + +bool DBCFile::writeContents(const QString &fn) { + QFile file(fn); + if (file.open(QIODevice::WriteOnly)) { + file.write(generateDBC().toUtf8()); + return true; + } else { + 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); + 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; + return s; + } + } + + return nullptr; +} + +cabana::Signal *DBCFile::getSignal(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()) { + return &(*it); + } + } + return 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); + } + } +} + +void DBCFile::updateMsg(const MessageId &id, const QString &name, uint32_t size) { + auto &m = msgs[id.address]; + m.name = name; + m.size = size; +} + +void DBCFile::removeMsg(const MessageId &id) { + msgs.erase(id.address); +} + +std::map DBCFile::getMessages() { + return msgs; +} + +const cabana::Msg *DBCFile::msg(const MessageId &id) const { + return msg(id.address); +} + +const cabana::Msg *DBCFile::msg(uint32_t address) const { + auto it = msgs.find(address); + return it != msgs.end() ? &it->second : nullptr; +} + +const cabana::Msg* DBCFile::msg(const QString &name) { + for (auto &[_, msg] : msgs) { + if (msg.name == name) { + return &msg; + } + } + + return 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::msgCount() const { + return msgs.size(); +} + +QString DBCFile::name() const { + return name_; +} + +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 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 * { + auto m = (cabana::Msg *)msg(address); + return m ? (cabana::Signal *)m->sig(name) : nullptr; + }; + + QTextStream stream((QString *)&content); + uint32_t address = 0; + while (!stream.atEnd()) { + QString line = stream.readLine().trimmed(); + if (line.startsWith("BO_ ")) { + if (auto match = bo_regexp.match(line); match.hasMatch()) { + address = match.captured(1).toUInt(); + } + } else if (line.startsWith("SG_ ")) { + int offset = 0; + auto match = sg_regexp.match(line); + if (!match.hasMatch()) { + 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); + s->max = match.captured(9 + offset); + 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}); + } + } + } + } + } 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(); + } + } + } + } +} + +QString DBCFile::generateDBC() { + QString dbc_string, signal_comment, val_desc; + for (auto &[address, m] : msgs) { + dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); + for (auto sig : m.getSignals()) { + dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") + .arg(sig->name) + .arg(sig->start_bit) + .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(sig->min) + .arg(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); + } + if (!sig->val_desc.isEmpty()) { + QStringList text; + for (auto &[val, desc] : sig->val_desc) { + text << QString("%1 \"%2\"").arg(val, desc); + } + val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig->name).arg(text.join(" ")); + } + } + dbc_string += "\n"; + } + return dbc_string + signal_comment + val_desc; +} diff --git a/tools/cabana/dbcfile.h b/tools/cabana/dbcfile.h new file mode 100644 index 0000000000..b8fa3ea41b --- /dev/null +++ b/tools/cabana/dbcfile.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "tools/cabana/dbc.h" + +const QString AUTO_SAVE_EXTENSION = ".tmp"; + + +class DBCFile : public QObject { + Q_OBJECT + +public: + DBCFile(const QString &dbc_file_name, QObject *parent=nullptr); + 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(); + bool writeContents(const QString &fn); + 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); + void removeMsg(const MessageId &id); + + std::map getMessages(); + const cabana::Msg *msg(const MessageId &id) const; + const cabana::Msg *msg(uint32_t address) const; + const cabana::Msg* msg(const QString &name); + QStringList signalNames() const; + int msgCount() const; + QString name() const; + + QString filename; + +private: + void parseExtraInfo(const QString &content); + std::map msgs; + QString name_; +}; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 49aac5c18b..26c9105b43 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -1,5 +1,4 @@ #include "tools/cabana/dbcmanager.h" -#include #include #include @@ -8,206 +7,210 @@ #include #include -bool DBCManager::open(const QString &dbc_file_name, QString *error) { - QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, dbc_file_name); - QFile file(opendbc_file_path); - if (file.open(QIODevice::ReadOnly)) { - return open(dbc_file_name, file.readAll(), error); + +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) { + ss |= s; + emit DBCFileChanged(); + return true; + } + + // Check if there is already a file for this sourceset, then replace it + if (ss == s) { + try { + dbc_files[i] = {s, new DBCFile(dbc_file_name, this)}; + delete dbc_file; + + emit DBCFileChanged(); + return true; + } catch (std::exception &e) { + if (error) *error = e.what(); + return false; + } + } } - return false; + + try { + dbc_files.push_back({s, new DBCFile(dbc_file_name, this)}); + } catch (std::exception &e) { + if (error) *error = e.what(); + return false; + } + + emit DBCFileChanged(); + return true; } -bool DBCManager::open(const QString &name, const QString &content, QString *error) { +bool DBCManager::open(SourceSet s, const QString &name, const QString &content, QString *error) { try { - 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.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(); - } - } - parseExtraInfo(content); - name_ = name; - emit DBCFileChanged(); - delete dbc; + dbc_files.push_back({s, new DBCFile(name, content, this)}); } catch (std::exception &e) { if (error) *error = e.what(); return false; } + + emit DBCFileChanged(); return true; } -void DBCManager::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 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 * { - auto m = (cabana::Msg *)msg(address); - return m ? (cabana::Signal *)m->sig(name) : nullptr; - }; - - QTextStream stream((QString *)&content); - uint32_t address = 0; - while (!stream.atEnd()) { - QString line = stream.readLine().trimmed(); - if (line.startsWith("BO_ ")) { - if (auto match = bo_regexp.match(line); match.hasMatch()) { - address = match.captured(1).toUInt(); - } - } else if (line.startsWith("SG_ ")) { - int offset = 0; - auto match = sg_regexp.match(line); - if (!match.hasMatch()) { - 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); - s->max = match.captured(9 + offset); - 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}); - } - } - } - } - } 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(); - } - } - } +void DBCManager::closeAll() { + while (dbc_files.size()) { + DBCFile *dbc_file = dbc_files.back().second; + dbc_files.pop_back(); + delete dbc_file; } + emit DBCFileChanged(); } -QString DBCManager::generateDBC() { - QString dbc_string, signal_comment, val_desc; - for (auto &[address, m] : msgs) { - dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); - for (auto sig : m.getSignals()) { - dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") - .arg(sig->name) - .arg(sig->start_bit) - .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(sig->min) - .arg(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); - } - if (!sig->val_desc.isEmpty()) { - QStringList text; - for (auto &[val, desc] : sig->val_desc) { - text << QString("%1 \"%2\"").arg(val, desc); - } - val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig->name).arg(text.join(" ")); - } + +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) { + for (uint8_t source : dbc_sources) { + emit signalAdded({.source = source, .address = id.address}, s); } - dbc_string += "\n"; } - return dbc_string + signal_comment + val_desc; +} + +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); + } +} + +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); + } } void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size) { - auto &m = msgs[id.address]; - m.name = name; - m.size = size; + auto sources_dbc_file = findDBCFile(id); + assert(sources_dbc_file); // This should be impossible + auto [dbc_sources, dbc_file] = *sources_dbc_file; - // This DBC applies to all active sources, emit for every source - for (uint8_t source : sources) { + dbc_file->updateMsg(id, name, size); + + for (uint8_t source : dbc_sources) { emit msgUpdated({.source = source, .address = id.address}); } } void DBCManager::removeMsg(const MessageId &id) { - msgs.erase(id.address); + auto sources_dbc_file = findDBCFile(id); + assert(sources_dbc_file); // This should be impossible + auto [dbc_sources, dbc_file] = *sources_dbc_file; + + dbc_file->removeMsg(id); - // This DBC applies to all active sources, emit for every source - for (uint8_t source : sources) { + for (uint8_t source : dbc_sources) { emit msgRemoved({.source = source, .address = id.address}); } } -void DBCManager::addSignal(const MessageId &id, const cabana::Signal &sig) { - if (auto m = const_cast(msg(id.address))) { - m->sigs.push_back(sig); - auto s = &m->sigs.last(); +std::map DBCManager::getMessages(uint8_t source) { + std::map ret; - // This DBC applies to all active sources, emit for every source - for (uint8_t source : sources) { - emit signalAdded({.source = source, .address = id.address}, s); - } + 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; } -void DBCManager::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; - emit signalUpdated(s); - } +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); } -void DBCManager::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()) { - emit signalRemoved(&(*it)); - m->sigs.erase(it); - } +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); } -QStringList DBCManager::signalNames() { - // Used for autocompletion +QStringList DBCManager::signalNames() const { QStringList ret; - for (auto const& [_, msg] : msgs) { - for (auto sig: msg.getSignals()) { - ret << sig->name; - } + + for (auto &[_, dbc_file] : dbc_files) { + ret << dbc_file->signalNames(); } + ret.sort(); ret.removeDuplicates(); return ret; } -void DBCManager::updateSources(const QSet &s) { +int DBCManager::msgCount() const { + int ret = 0; + + for (auto &[_, dbc_file] : dbc_files) { + ret += dbc_file->msgCount(); + } + + return ret; +} + +int DBCManager::dbcCount() const { + return dbc_files.size(); +} + +void DBCManager::updateSources(const SourceSet &s) { sources = s; } +std::optional> DBCManager::findDBCFile(const uint8_t source) const { + // 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 {}; +} + +std::optional> DBCManager::findDBCFile(const MessageId &id) const { + return findDBCFile(id.source); +} + DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index dd3d9811c7..2a5aa6da25 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -9,6 +9,10 @@ #include #include "tools/cabana/dbc.h" +#include "tools/cabana/dbcfile.h" + +typedef QSet SourceSet; +const SourceSet SOURCE_ALL = {}; class DBCManager : public QObject { Q_OBJECT @@ -16,39 +20,35 @@ class DBCManager : public QObject { public: DBCManager(QObject *parent) {} ~DBCManager() {} - bool open(const QString &dbc_file_name, QString *error = nullptr); - bool open(const QString &name, const QString &content, QString *error = nullptr); - QString generateDBC(); + 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 closeAll(); + void addSignal(const MessageId &id, const cabana::Signal &sig); void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig); void removeSignal(const MessageId &id, const QString &sig_name); - inline int msgCount() const { return msgs.size(); } - inline QString name() const { return name_; } void updateMsg(const MessageId &id, const QString &name, uint32_t size); void removeMsg(const MessageId &id); - inline std::map getMessages(uint8_t source) { - std::map ret; - for (auto &[address, msg] : msgs) { - MessageId id = {.source = source, .address = address}; - ret[id] = msg; - } - return ret; - } - inline const cabana::Msg *msg(const MessageId &id) const { return msg(id.address); } - inline const cabana::Msg* msg(uint8_t source, const QString &name) { - for (auto &[_, msg] : msgs) { - if (msg.name == name) { - return &msg; - } - } - - return nullptr; - } - QStringList signalNames(); + + 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() const; + int msgCount() const; + int dbcCount() const; + + std::optional> findDBCFile(const uint8_t source) const; + std::optional> findDBCFile(const MessageId &id) const; + + QList> dbc_files; + +private: + SourceSet sources; public slots: - void updateSources(const QSet &s); + void updateSources(const SourceSet &s); signals: void signalAdded(MessageId id, const cabana::Signal *sig); @@ -57,17 +57,6 @@ signals: void msgUpdated(MessageId id); void msgRemoved(MessageId id); void DBCFileChanged(); - -private: - void parseExtraInfo(const QString &content); - std::map msgs; - QString name_; - QSet sources; - - inline const cabana::Msg *msg(uint32_t address) const { - auto it = msgs.find(address); - return it != msgs.end() ? &it->second : nullptr; - } }; DBCManager *dbc(); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index c739e26744..3b1edce236 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -42,7 +42,7 @@ MainWindow::MainWindow() : QMainWindow() { messages_widget->restoreHeaderState(settings.message_header_state); qRegisterMetaType("uint64_t"); - qRegisterMetaType>("QSet"); + qRegisterMetaType("SourceSet"); qRegisterMetaType("ReplyMsgType"); installMessageHandler([this](ReplyMsgType type, const std::string msg) { // use queued connection to recv the log messages from replay. @@ -54,9 +54,13 @@ MainWindow::MainWindow() : QMainWindow() { main_win = this; qInstallMessageHandler(qLogMessageHandler); - QFile json_file("./car_fingerprint_to_dbc.json"); - if (json_file.open(QIODevice::ReadOnly)) { - fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); + + for (const QString &fn : {"./car_fingerprint_to_dbc.json", "./tools/cabana/car_fingerprint_to_dbc.json"}) { + QFile json_file(fn); + if (json_file.open(QIODevice::ReadOnly)) { + fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); + break; + } } setStyleSheet(QString(R"(QMainWindow::separator { @@ -72,6 +76,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::updateStatus); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(can, &AbstractStream::sourcesUpdated, dbc(), &DBCManager::updateSources); + QObject::connect(can, &AbstractStream::sourcesUpdated, this, &MainWindow::updateSources); 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); @@ -87,6 +92,9 @@ void MainWindow::createActions() { file_menu->addAction(tr("New DBC File"), this, &MainWindow::newFile)->setShortcuts(QKeySequence::New); file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::openFile)->setShortcuts(QKeySequence::Open); + open_dbc_for_source = file_menu->addMenu(tr("Open &DBC File for Bus")); + open_dbc_for_source->setEnabled(false); + open_recent_menu = file_menu->addMenu(tr("Open &Recent")); for (int i = 0; i < MAX_RECENT_FILES; ++i) { recent_files_acts[i] = new QAction(this); @@ -108,9 +116,14 @@ void MainWindow::createActions() { file_menu->addAction(tr("Load DBC From Clipboard"), this, &MainWindow::loadDBCFromClipboard); file_menu->addSeparator(); - file_menu->addAction(tr("Save DBC..."), this, &MainWindow::save)->setShortcuts(QKeySequence::Save); - file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAs)->setShortcuts(QKeySequence::SaveAs); - file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveDBCToClipboard); + save_dbc = file_menu->addAction(tr("Save DBC..."), this, &MainWindow::save); + save_dbc->setShortcuts(QKeySequence::Save); + + save_dbc_as = file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAs); + save_dbc_as->setShortcuts(QKeySequence::SaveAs); + + copy_dbc_to_clipboard = file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveDBCToClipboard); + file_menu->addSeparator(); file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption)->setShortcuts(QKeySequence::Preferences); @@ -231,7 +244,7 @@ void MainWindow::undoStackCleanChanged(bool clean) { void MainWindow::DBCFileChanged() { UndoStack::instance()->clear(); - setWindowFilePath(QString("%1").arg(dbc()->name())); + updateLoadSaveMenus(); } void MainWindow::openRoute() { @@ -247,7 +260,9 @@ void MainWindow::openRoute() { void MainWindow::newFile() { remindSaveChanges(); - dbc()->open("untitled.dbc", ""); + dbc()->closeAll(); + dbc()->open(SOURCE_ALL, "", ""); + updateLoadSaveMenus(); } void MainWindow::openFile() { @@ -258,7 +273,19 @@ void MainWindow::openFile() { } } -void MainWindow::loadFile(const QString &fn) { +void MainWindow::openFileForSource() { + if (auto action = qobject_cast(sender())) { + uint8_t source = action->data().value(); + assert(source < 64); + + QString fn = QFileDialog::getOpenFileName(this, tr("Open File"), settings.last_dir, "DBC (*.dbc)"); + if (!fn.isEmpty()) { + loadFile(fn, {source, uint8_t(source + 128), uint8_t(source + 192)}, false); + } + } +} + +void MainWindow::loadFile(const QString &fn, SourceSet s, bool close_all) { if (!fn.isEmpty()) { QString dbc_fn = fn; @@ -271,20 +298,24 @@ void MainWindow::loadFile(const QString &fn) { } } - QFile file(dbc_fn); - if (file.open(QIODevice::ReadOnly)) { - auto dbc_name = QFileInfo(fn).baseName(); - QString error; - bool ret = dbc()->open(dbc_name, file.readAll(), &error); - if (ret) { - setCurrentFile(fn); - statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); - } else { - QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC file"), tr("Failed to parse DBC file %1").arg(fn)); - msg_box.setDetailedText(error); - msg_box.exec(); - } + auto dbc_name = QFileInfo(fn).baseName(); + QString error; + + if (close_all) { + dbc()->closeAll(); } + + bool ret = dbc()->open(s, dbc_fn, &error); + if (ret) { + updateRecentFiles(fn); + statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); + } else { + QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC file"), tr("Failed to parse DBC file %1").arg(fn)); + msg_box.setDetailedText(error); + msg_box.exec(); + } + + updateLoadSaveMenus(); } } @@ -303,17 +334,23 @@ void MainWindow::openRecentFile() { } void MainWindow::loadDBCFromOpendbc(const QString &name) { - if (name != dbc()->name()) { - remindSaveChanges(); - dbc()->open(name); - } + remindSaveChanges(); + + QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, name); + + dbc()->closeAll(); + dbc()->open(SOURCE_ALL, opendbc_file_path); + + updateLoadSaveMenus(); } void MainWindow::loadDBCFromClipboard() { remindSaveChanges(); QString dbc_str = QGuiApplication::clipboard()->text(); QString error; - bool ret = dbc()->open("clipboard", dbc_str, &error); + + dbc()->closeAll(); + bool ret = dbc()->open(SOURCE_ALL, "", dbc_str, &error); if (ret && dbc()->msgCount() > 0) { QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); } else { @@ -327,7 +364,7 @@ void MainWindow::loadDBCFromClipboard() { void MainWindow::loadDBCFromFingerprint() { // Don't overwrite already loaded DBC - if (!dbc()->name().isEmpty()) { + if (dbc()->msgCount()) { return; } @@ -349,54 +386,110 @@ void MainWindow::loadDBCFromFingerprint() { } void MainWindow::save() { - if (current_file.isEmpty()) { - saveAs(); - } else { - saveFile(current_file); - } + saveFile(); } void MainWindow::autoSave() { - if (!current_file.isEmpty() && !UndoStack::instance()->isClean()) { - QFile file(current_file + AUTO_SAVE_EXTENSION); - if (file.open(QIODevice::WriteOnly)) { - file.write(dbc()->generateDBC().toUtf8()); + if (!UndoStack::instance()->isClean()) { + for (auto &[_, dbc_file] : dbc()->dbc_files) { + if (!dbc_file->filename.isEmpty()) { + dbc_file->autoSave(); + } } } } void MainWindow::cleanupAutoSaveFile() { - if (!current_file.isEmpty()) { - QFile::remove(current_file + AUTO_SAVE_EXTENSION); + for (auto &[_, dbc_file] : dbc()->dbc_files) { + dbc_file->cleanupAutoSaveFile(); } } -void MainWindow::saveFile(const QString &fn) { - cleanupAutoSaveFile(); - QFile file(fn); - if (file.open(QIODevice::WriteOnly)) { - file.write(dbc()->generateDBC().toUtf8()); - UndoStack::instance()->setClean(); - setCurrentFile(fn); - statusBar()->showMessage(tr("File saved"), 2000); +void MainWindow::saveFile() { + // Save all open DBC files + for (auto &[s, dbc_file] : dbc()->dbc_files) { + if (!dbc_file->filename.isEmpty()) { + dbc_file->save(); + updateRecentFiles(dbc_file->filename); + } else { + QString fn = QFileDialog::getSaveFileName(this, tr("Save File"), QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); + if (!fn.isEmpty()) { + dbc_file->saveAs(fn); + updateRecentFiles(fn); + } + } } + + UndoStack::instance()->setClean(); + statusBar()->showMessage(tr("File saved"), 2000); } void MainWindow::saveAs() { + // Assume only one file is open + assert(dbc()->dbcCount() > 0); + auto &[_, dbc_file] = dbc()->dbc_files.first(); + QString fn = QFileDialog::getSaveFileName(this, tr("Save File"), QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); if (!fn.isEmpty()) { - saveFile(fn); + dbc_file->saveAs(fn); } } void MainWindow::saveDBCToClipboard() { - QGuiApplication::clipboard()->setText(dbc()->generateDBC()); + // Assume only one file is open + assert(dbc()->dbcCount() > 0); + + auto &[_, dbc_file] = dbc()->dbc_files.first(); + QGuiApplication::clipboard()->setText(dbc_file->generateDBC()); QMessageBox::information(this, tr("Copy To Clipboard"), tr("DBC Successfully copied!")); } -void MainWindow::setCurrentFile(const QString &fn) { - current_file = fn; - setWindowFilePath(QString("%1").arg(fn)); +void MainWindow::updateSources(const SourceSet &s) { + sources = s; + updateLoadSaveMenus(); +} + +void MainWindow::updateLoadSaveMenus() { + if (dbc()->dbcCount() > 1) { + save_dbc->setText(tr("Save %1 DBCs...").arg(dbc()->dbcCount())); + } else { + save_dbc->setText(tr("Save DBC...")); + } + + // TODO: Support save as for multiple files + save_dbc_as->setEnabled(dbc()->dbcCount() == 1); + + // TODO: Support clipboard for multiple files + copy_dbc_to_clipboard->setEnabled(dbc()->dbcCount() == 1); + + + QList sources_sorted = sources.toList(); + std::sort(sources_sorted.begin(), sources_sorted.end()); + + open_dbc_for_source->setEnabled(sources.size() > 0); + open_dbc_for_source->clear(); + + for (uint8_t source : sources_sorted) { + if (source >= 64) continue; // Sent and blocked buses are handled implicitly + QAction *action = new QAction(this); + + auto d = dbc()->findDBCFile(source); + QString name = tr("no DBC"); + if (d && !d->second->name().isEmpty()) { + name = tr("%1").arg(d->second->name()); + } else if (d) { + name = "untitled"; + } + + action->setText(tr("Bus %1 (current: %2)").arg(source).arg(name)); + action->setData(source); + + QObject::connect(action, &QAction::triggered, this, &MainWindow::openFileForSource); + open_dbc_for_source->addAction(action); + } +} + +void MainWindow::updateRecentFiles(const QString &fn) { settings.recent_files.removeAll(fn); settings.recent_files.prepend(fn); while (settings.recent_files.size() > MAX_RECENT_FILES) { @@ -434,7 +527,6 @@ void MainWindow::remindSaveChanges() { } } UndoStack::instance()->clear(); - current_file = ""; } void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool success) { diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 3258b95cde..349fa3b28d 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -8,13 +8,12 @@ #include #include "tools/cabana/chartswidget.h" +#include "tools/cabana/dbcmanager.h" #include "tools/cabana/detailwidget.h" #include "tools/cabana/messageswidget.h" #include "tools/cabana/videowidget.h" #include "tools/cabana/tools/findsimilarbits.h" -const QString AUTO_SAVE_EXTENSION = ".tmp"; - class MainWindow : public QMainWindow { Q_OBJECT @@ -22,12 +21,13 @@ public: MainWindow(); void dockCharts(bool dock); void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); } - void loadFile(const QString &fn); + void loadFile(const QString &fn, SourceSet s = SOURCE_ALL, bool close_all = true); public slots: void openRoute(); void newFile(); void openFile(); + void openFileForSource(); void openRecentFile(); void openOpendbcFile(); void loadDBCFromOpendbc(const QString &name); @@ -36,6 +36,7 @@ public slots: void save(); void saveAs(); void saveDBCToClipboard(); + void updateSources(const SourceSet &s); signals: void showMessage(const QString &msg, int timeout); @@ -43,10 +44,10 @@ signals: protected: void remindSaveChanges(); - void saveFile(const QString &fn); + void saveFile(); void autoSave(); void cleanupAutoSaveFile(); - void setCurrentFile(const QString &fn); + void updateRecentFiles(const QString &fn); void updateRecentFileActions(); void createActions(); void createDockWindows(); @@ -62,6 +63,7 @@ protected: void onlineHelp(); void toggleFullScreen(); void updateStatus(); + void updateLoadSaveMenus(); VideoWidget *video_widget = nullptr; QDockWidget *video_dock; @@ -74,12 +76,16 @@ protected: QLabel *status_label; QJsonDocument fingerprint_to_dbc; QSplitter *video_splitter;; - QString current_file = ""; enum { MAX_RECENT_FILES = 15 }; QAction *recent_files_acts[MAX_RECENT_FILES] = {}; QMenu *open_recent_menu = nullptr; + QMenu *open_dbc_for_source = nullptr; + QAction *save_dbc = nullptr; + QAction *save_dbc_as = nullptr; + QAction *copy_dbc_to_clipboard = nullptr; int prev_undostack_index = 0; int prev_undostack_count = 0; + SourceSet sources; friend class OnlineHelp; }; diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 8e19f69d2a..37490d0ec6 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -64,11 +64,11 @@ signals: void updated(); void msgsReceived(const QHash *); void received(QHash *); - void sourcesUpdated(const QSet &s); + void sourcesUpdated(const SourceSet &s); public: QHash last_msgs; - QSet sources; + SourceSet sources; protected: virtual void process(QHash *); diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 8445867acb..3a5d64f0a5 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -9,15 +9,14 @@ // demo route, first segment 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("DBCManager::generateDBC") { - DBCManager dbc_origin(nullptr); - dbc_origin.open("toyota_new_mc_pt_generated"); - DBCManager dbc_from_generated(nullptr); - dbc_from_generated.open("", dbc_origin.generateDBC()); +TEST_CASE("DBCFile::generateDBC") { + QString fn = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, "toyota_new_mc_pt_generated"); + DBCFile dbc_origin(fn); + DBCFile dbc_from_generated("", dbc_origin.generateDBC()); REQUIRE(dbc_origin.msgCount() == dbc_from_generated.msgCount()); - auto msgs = dbc_origin.getMessages(0); - auto new_msgs = dbc_from_generated.getMessages(0); + 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); @@ -33,7 +32,7 @@ TEST_CASE("DBCManager::generateDBC") { TEST_CASE("Parse can messages") { DBCManager dbc(nullptr); - dbc.open("toyota_new_mc_pt_generated"); + dbc.open({0}, "toyota_new_mc_pt_generated"); CANParser can_parser(0, "toyota_new_mc_pt_generated", {}, {}); LogReader log; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index a44ac76059..e40498f045 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -20,7 +20,7 @@ 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); - QSet bus_set; + SourceSet bus_set; for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { bus_set << it.key().source; } From daeb502031fc5c261c56dad530e63661530e4a8a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 27 Mar 2023 11:53:40 -0700 Subject: [PATCH 092/143] bump cereal --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index c516d5e985..e276226dbe 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit c516d5e9856fdb1f5ca856e430ac69aebb2ff017 +Subproject commit e276226dbe38c811a4c1f3a9b689cd3ecbd05a20 From 4439e285db115b7e03192af47f45e07efa1ba4f1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 27 Mar 2023 12:45:13 -0700 Subject: [PATCH 093/143] Revert "bump cereal" This reverts commit daeb502031fc5c261c56dad530e63661530e4a8a. --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index e276226dbe..c516d5e985 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit e276226dbe38c811a4c1f3a9b689cd3ecbd05a20 +Subproject commit c516d5e9856fdb1f5ca856e430ac69aebb2ff017 From e4348dc45d383c5ef0622b3bbf5dcd659081e5bb Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Mon, 27 Mar 2023 21:45:55 +0200 Subject: [PATCH 094/143] cabana: go to previous zoom window (#27702) * cabana: go to previous zoom level * zoom undo on right click * catch mousepress event on linux --- tools/cabana/chartswidget.cc | 49 ++++++++++++++++++++++++++++++++---- tools/cabana/chartswidget.h | 8 +++++- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index a6eabfd1ae..303b873faa 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -56,6 +56,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent) range_slider->setPageStep(60); // 1 min range_slider_action = toolbar->addWidget(range_slider); + undo_zoom_action = toolbar->addAction(utils::icon("arrow-counterclockwise"), tr("Previous zoom")); + qobject_cast(toolbar->widgetForAction(undo_zoom_action))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + reset_zoom_action = toolbar->addAction(utils::icon("zoom-out"), tr("Reset Zoom")); qobject_cast(toolbar->widgetForAction(reset_zoom_action))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -97,6 +100,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent) QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); + QObject::connect(undo_zoom_action, &QAction::triggered, this, &ChartsWidget::zoomUndo); QObject::connect(reset_zoom_action, &QAction::triggered, this, &ChartsWidget::zoomReset); QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged); QObject::connect(dock_btn, &QAction::triggered, [this]() { @@ -123,7 +127,7 @@ void ChartsWidget::eventsMerged() { } } -void ChartsWidget::zoomIn(double min, double max) { +void ChartsWidget::setZoom(double min, double max) { zoomed_range = {min, max}; is_zoomed = zoomed_range != display_range; updateToolBar(); @@ -131,8 +135,25 @@ void ChartsWidget::zoomIn(double min, double max) { emit rangeChanged(min, max, is_zoomed); } +void ChartsWidget::zoomIn(double min, double max) { + // Save previous zoom on undo stack + if (is_zoomed) { + zoom_stack.push({zoomed_range.first, zoomed_range.second}); + } + setZoom(min, max); +} + void ChartsWidget::zoomReset() { - zoomIn(display_range.first, display_range.second); + setZoom(display_range.first, display_range.second); +} + +void ChartsWidget::zoomUndo() { + if (!zoom_stack.isEmpty()) { + auto r = zoom_stack.pop(); + setZoom(r.first, r.second); + } else { + zoomReset(); + } } void ChartsWidget::updateState() { @@ -148,7 +169,7 @@ void ChartsWidget::updateState() { display_range.first = std::max(0.0, max_sec - max_chart_range); display_range.second = display_range.first + max_chart_range; } else if (cur_sec < zoomed_range.first || cur_sec >= zoomed_range.second) { - // loop in zoommed range + // loop in zoomed range can->seekTo(zoomed_range.first); } @@ -170,6 +191,7 @@ void ChartsWidget::updateToolBar() { range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); range_lb_action->setVisible(!is_zoomed); range_slider_action->setVisible(!is_zoomed); + undo_zoom_action->setVisible(is_zoomed); reset_zoom_action->setVisible(is_zoomed); reset_zoom_action->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : ""); remove_all_btn->setEnabled(!charts.isEmpty()); @@ -199,7 +221,7 @@ ChartView *ChartsWidget::createChart() { chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); QObject::connect(chart, &ChartView::remove, [=]() { removeChart(chart); }); QObject::connect(chart, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); - QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); + QObject::connect(chart, &ChartView::zoomUndo, this, &ChartsWidget::zoomUndo); QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start)); @@ -304,6 +326,23 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { return false; } +bool ChartsWidget::event(QEvent *event) { + bool back_button = false; + if (event->type() == QEvent::MouseButtonPress) { + QMouseEvent *ev = static_cast(event); + back_button = ev->button() == Qt::BackButton; + } else if (event->type() == QEvent::NativeGesture) { // MacOS emulates a back swipe on pressing the mouse back button + QNativeGestureEvent *ev = static_cast(event); + back_button = (ev->value() == 180); + } + + if (back_button) { + zoomUndo(); + return true; + } + return QFrame::event(event); +} + // ChartView ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { @@ -679,7 +718,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } event->accept(); } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { - emit zoomReset(); + emit zoomUndo(); event->accept(); } else { QGraphicsView::mouseReleaseEvent(event); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 731be47d06..de6cfc56b1 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ signals: void seriesRemoved(const MessageId &id, const cabana::Signal *sig); void seriesAdded(const MessageId &id, const cabana::Signal *sig); void zoomIn(double min, double max); - void zoomReset(); + void zoomUndo(); void remove(); void axisYLabelWidthChanged(int w); @@ -119,6 +120,7 @@ signals: private: void resizeEvent(QResizeEvent *event) override; + bool event(QEvent *event) override; void alignCharts(); void newChart(); ChartView *createChart(); @@ -127,6 +129,8 @@ private: void updateState(); void zoomIn(double min, double max); void zoomReset(); + void zoomUndo(); + void setZoom(double min, double max); void updateToolBar(); void setMaxChartRange(int value); void updateLayout(); @@ -141,6 +145,7 @@ private: QAction *range_slider_action; bool docking = true; QAction *dock_btn; + QAction *undo_zoom_action; QAction *reset_zoom_action; QAction *remove_all_btn; QGridLayout *charts_layout; @@ -149,6 +154,7 @@ private: bool is_zoomed = false; std::pair display_range; std::pair zoomed_range; + QStack> zoom_stack; bool use_dark_theme = false; QAction *columns_action; int column_count = 1; From d9487ab901763f310192bfeb0b8116daaa1cf540 Mon Sep 17 00:00:00 2001 From: Igor Biletskyy Date: Mon, 27 Mar 2023 13:24:56 -0700 Subject: [PATCH 095/143] boardd: fix uninitialized can_header (#27685) --- selfdrive/boardd/panda.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 647a0d9c78..4ad4b5e652 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -203,7 +203,7 @@ void Panda::pack_can_buffer(const capnp::List::Reader &can_data assert(can_data.size() <= 64); assert(can_data.size() == dlc_to_len[data_len_code]); - can_header header; + can_header header = {}; header.addr = cmsg.getAddress(); header.extended = (cmsg.getAddress() >= 0x800) ? 1 : 0; header.data_len_code = data_len_code; From 86f6c315bc3712c924ef709a4de59dade6d05070 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 27 Mar 2023 13:30:22 -0700 Subject: [PATCH 096/143] bump cereal (#27704) --- cereal | 2 +- selfdrive/car/hyundai/values.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cereal b/cereal index c516d5e985..e276226dbe 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit c516d5e9856fdb1f5ca856e430ac69aebb2ff017 +Subproject commit e276226dbe38c811a4c1f3a9b689cd3ecbd05a20 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index bb26d68329..24ee7321f4 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -383,14 +383,14 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [HYUNDAI_VERSION_REQUEST_ALT], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.parking], + whitelist_ecus=[Ecu.parkingAdas], bus=0, auxiliary=True, ), Request( [HYUNDAI_VERSION_REQUEST_ALT], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.parking], + whitelist_ecus=[Ecu.parkingAdas], bus=1, auxiliary=True, obd_multiplexing=False, @@ -398,7 +398,7 @@ FW_QUERY_CONFIG = FwQueryConfig( ], extra_ecus=[ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms - (Ecu.parking, 0x7b1, None), # ADAS Parking ECU (may exist on all platforms) + (Ecu.parkingAdas, 0x7b1, None), # ADAS Parking ECU (may exist on all platforms) (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], From 8a36887dfbef0da9a754d7b9a8decb564ce277ab Mon Sep 17 00:00:00 2001 From: pugdaddys <50273961+pugdaddys@users.noreply.github.com> Date: Mon, 27 Mar 2023 16:58:30 -0400 Subject: [PATCH 097/143] VW: add missing Audi A3 2016 FW (#27699) * Update values.py * Update values.py * Update values.py * missing radar * convert to hex --------- Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index bdd82088a1..9873b628cd 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -866,6 +866,7 @@ FW_VERSIONS = { b'\xf1\x878V0906264B \xf1\x890003', b'\xf1\x878V0907115B \xf1\x890007', b'\xf1\x878V0907404A \xf1\x890005', + b'\xf1\x875G0906259D \xf1\x890002', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870CW300044T \xf1\x895245', @@ -873,6 +874,7 @@ FW_VERSIONS = { b'\xf1\x870D9300012 \xf1\x894912', b'\xf1\x870D9300012 \xf1\x894931', b'\xf1\x870D9300012K \xf1\x894513', + b'\xf1\x870D9300013B \xf1\x894902', b'\xf1\x870D9300013B \xf1\x894931', b'\xf1\x870D9300041N \xf1\x894512', b'\xf1\x870D9300043T \xf1\x899699', @@ -910,11 +912,13 @@ FW_VERSIONS = { b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00803A0', b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\x0503G0G803A0', b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\00516G00804A1', + b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516G00804A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521G00807A1', ], (Ecu.fwdRadar, 0x757, None): [ - b'\xf1\x875Q0907567N \xf1\x890400\xf1\x82\00101', - b'\xf1\x875Q0907572D \xf1\x890304\xf1\x82\00101', + b'\xf1\x875Q0907567N \xf1\x890400\xf1\x82\x0101', + b'\xf1\x875Q0907572F \xf1\x890400\xf1\x82\x0101', + b'\xf1\x875Q0907572D \xf1\x890304\xf1\x82\x0101', b'\xf1\x875Q0907572G \xf1\x890571', b'\xf1\x875Q0907572H \xf1\x890620', b'\xf1\x875Q0907572P \xf1\x890682', From 12e46e5d4abd8d2a00af6370c275ad4c8462a15a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 27 Mar 2023 14:22:25 -0700 Subject: [PATCH 098/143] Toyota: add missing FW versions for C-HR Hybrid 2021 (#27687) add another 2021 CHR H --- selfdrive/car/toyota/values.py | 36 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 2398e012d6..38fb8dfbd1 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -727,22 +727,26 @@ FW_VERSIONS = { ], }, CAR.CHRH_TSS2: { - (Ecu.eps, 0x7a1, None): [ - b'8965B10092\x00\x00\x00\x00\x00\x00', - ], - (Ecu.abs, 0x7b0, None): [ - b'F152610041\x00\x00\x00\x00\x00\x00', - ], - (Ecu.engine, 0x700, None): [ - b'\x0189663F438000\x00\x00\x00\x00', - ], - (Ecu.fwdRadar, 0x750, 15): [ - b'\x018821FF410500\x00\x00\x00\x00', - ], - (Ecu.fwdCamera, 0x750, 109): [ - b'\x028646FF413100\x00\x00\x00\x008646GF411100\x00\x00\x00\x00', - ], - }, + (Ecu.eps, 0x7a1, None): [ + b'8965B10092\x00\x00\x00\x00\x00\x00', + b'8965B10091\x00\x00\x00\x00\x00\x00', + ], + (Ecu.abs, 0x7b0, None): [ + b'F152610041\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x0189663F438000\x00\x00\x00\x00', + b'\x0289663F453000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 15): [ + b'\x018821FF410500\x00\x00\x00\x00', + b'\x018821FF410300\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 109): [ + b'\x028646FF413100\x00\x00\x00\x008646GF411100\x00\x00\x00\x00', + b'\x028646FF411100\x00\x00\x00\x008646GF409000\x00\x00\x00\x00', + ], + }, CAR.COROLLA: { (Ecu.engine, 0x7e0, None): [ b'\x0230ZC2000\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', From 7284969eb8c098efce07bdd6937b2a1a3f50f0ad Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Mon, 27 Mar 2023 17:06:47 -0500 Subject: [PATCH 099/143] Add missing TUCSON_4TH_GEN fwdCamera/fwdRadar f/w (#27708) `chodochodo#7177` 2022 Hyundai Tucson 2.4L ICE DongleID/route c5ba26f7af98e5d1|2023-03-27--14-33-34 --- 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 24ee7321f4..3c31bfb1e6 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1602,9 +1602,11 @@ FW_VERSIONS = { }, CAR.TUCSON_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9210 14G', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T', ], (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ', ], }, From c0b2e15a60f5c5592a5097ab79c309bc2b0fb2f6 Mon Sep 17 00:00:00 2001 From: erotisch <128647582+erotisch@users.noreply.github.com> Date: Mon, 27 Mar 2023 18:37:54 -0400 Subject: [PATCH 100/143] HKG: add missing 2019 Genesis G70 FW (#27676) * Update values.py * Update values.py * Update values.py * fix FW --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 3c31bfb1e6..dcc3a0fc0f 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1054,11 +1054,23 @@ FW_VERSIONS = { ], }, CAR.GENESIS_G70: { - (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ', ], - (Ecu.engine, 0x7e0, None): [b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00', ], - (Ecu.eps, 0x7d4, None): [b'\xf1\x00IK MDPS R 1.00 1.06 57700-G9420 4I4VL106', ], - (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00IK MFC AT USA LHD 1.00 1.01 95740-G9000 170920', ], - (Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDJLT17895112DN4\x88fVf\x99\x88\x88\x88\x87fVe\x88vhwwUFU\x97eFex\x99\xff\xb7\x82\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda', ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ', + b'\xf1\x00IK__ SCC F-CUP 1.00 1.01 96400-G9100 ', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00IK MDPS R 1.00 1.06 57700-G9420 4I4VL106', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00IK MFC AT USA LHD 1.00 1.01 95740-G9000 170920', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda', + b'\xf1\x87VDJLT17895112DN4\x88fVf\x99\x88\x88\x88\x87fVe\x88vhwwUFU\x97eFex\x99\xff\xb7\x82\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda', + ], }, CAR.GENESIS_G70_2020: { (Ecu.eps, 0x7d4, None): [ From 3555a08c17af6c1ef22d75345a78ff6f670b1d66 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 27 Mar 2023 16:11:59 -0700 Subject: [PATCH 101/143] Nissan: add missing FW for 2020 Leaf (IC) (#27670) add nissan leaf ic fp --- selfdrive/car/nissan/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index e9af828e2b..358cf0d0cd 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -126,18 +126,22 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x707, None): [ b'5SH1BDB\x04\x18\x00\x00\x00\x00\x00_-?\x04\x91\xf2\x00\x00\x00\x80', b'5SK0ADB\x04\x18\x00\x00\x00\x00\x00_(5\x07\x9aQ\x00\x00\x00\x80', + b'5SH4BDB\x04\x18\x00\x00\x00\x00\x00_-?\x04\x91\xf2\x00\x00\x00\x80', ], (Ecu.abs, 0x740, None): [ b'476605SH1D', b'476605SK2A', + b'476605SD2E', ], (Ecu.eps, 0x742, None): [ b'5SH2A\x99A\x05\x02N123F\x15\x81\x00\x00\x00\x00\x00\x00\x00\x80', b'5SK3A\x99A\x05\x02N123F\x15u\x00\x00\x00\x00\x00\x00\x00\x80', + b'5SH2C\xb7A\x05\x02N123F\x15\xa3\x00\x00\x00\x00\x00\x00\x00\x80', ], (Ecu.gateway, 0x18dad0f1, None): [ b'284U25SH3A', b'284U25SK2D', + b'284U25SF0C', ], }, CAR.XTRAIL: { From e65bd1a7039d885e016cbc6ca5a5d2dd31d6979c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 28 Mar 2023 00:21:08 -0700 Subject: [PATCH 102/143] bump panda (#27713) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index d70fa4e120..db6c50cd09 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d70fa4e1200ad47c66587c78fd90030a3be1cc43 +Subproject commit db6c50cd09f773c231f962fc0e31b4612c572b08 From fb03e225fd5b815f1600ec71848e94ddb55eb597 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 28 Mar 2023 15:25:20 +0800 Subject: [PATCH 103/143] isotp_parallel_query: use drain_sock_raw (#27714) use drain_sock_raw --- selfdrive/car/isotp_parallel_query.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index d9c658a14c..70f8b5f50d 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -60,7 +60,7 @@ class IsoTpParallelQuery: return msgs def _drain_rx(self): - messaging.drain_sock(self.logcan) + messaging.drain_sock_raw(self.logcan) self.msg_buffer = defaultdict(list) def _create_isotp_msg(self, tx_addr, sub_addr, rx_addr): From 1853d6f40edc07a49a910f6fb8cedab96e9f3521 Mon Sep 17 00:00:00 2001 From: royjr Date: Tue, 28 Mar 2023 04:53:48 -0400 Subject: [PATCH 104/143] Honda Bosch Radarless: experimental longitudinal support (#25364) * civic22_long * Stock requests -4 * add standstill bit * bump * fix standstill * bump * bump * bump panda * Update hondacan.py * bump panda * add docs * bump panda * bump panda * fix control_on value * set control_off * fix cars.md * Update panda * Update opendbc * Update panda * Update panda * allow more braking * Revert "allow more braking" This reverts commit ecd2493a436a095b621d815e8b0c7591fa6b93a9. * Update panda * fix speed mismatch * Revert "fix speed mismatch" This reverts commit ca795dc5bd9d6e841225e1ac1ff93a1f78618513. * Update panda * fix speed mismatch and standstill * delay stopped message to match stock behavior * green cruise only when enabled * Update panda * Revert "green cruise only when enabled" This reverts commit d21aa5b541a42fa6d1c87e3b065f720af28ff38b. * lesser nester * simplify * simplify control_on * simplify common signals * simplify CONTROL_ON * lessest nester * hide speed on gas_override to match stock behavior * tiny simplification, lesser nester * flip common acc control values around * move magic number to global variable * Revert "move magic number to global variable" This reverts commit 160be0e0872dc08a8786d97fc2125b2eb131362d. * remove stopped logic * remove unused variable * looks ok * looks better * simplify override * clarify CONTROL_OFF signal comment * civic22_long_bettercontroloff shorten delay init selfless whoops move to carcontroller selfmore lower time, currently take 5s to kick in just right deline * Rename CONTROL_OFF -> IDLESTOP_ALLOW This tells the car its ready to turn off the engine, which does so when the car is standstill. * Update panda * Update opendbc * Update panda * fix docs * Update panda * Update panda * Update opendbc * Update panda * Update panda * Update panda * Update panda * bump panda * idlestop in another PR * radarless doesn't need tester present * simplify that * helper * one line is fine * test bump * bumpback * disallow * reduce diff --------- Co-authored-by: sshane --- docs/CARS.md | 4 +-- selfdrive/car/honda/carcontroller.py | 6 ++-- selfdrive/car/honda/carstate.py | 5 ++- selfdrive/car/honda/hondacan.py | 48 ++++++++++++++++++---------- selfdrive/car/honda/interface.py | 14 ++++---- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 3e23316bd8..7c8170c275 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -44,9 +44,9 @@ A supported vehicle is one that just works when you install a comma three. All s |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)](##)|Honda Bosch A|| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| |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)](##)|Honda Bosch A|| -|Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| +|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| |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)](##)|Honda Bosch A|| -|Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| +|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)](##)|Honda Bosch B|| |Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| |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)](##)|Honda Bosch A|| |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)](##)|Honda Bosch A|| diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 4dc1dc8131..f6d328131b 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -1,7 +1,6 @@ from collections import namedtuple from cereal import car -from common.conversions import Conversions as CV from common.numpy_fast import clip, interp from common.realtime import DT_CTRL from opendbc.can.packer import CANPacker @@ -127,7 +126,8 @@ class CarController: def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl - hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH if hud_control.speedVisible else 255 + conversion = hondacan.get_cruise_speed_conversion(self.CP.carFingerprint, CS.is_metric) + hud_v_cruise = hud_control.setSpeed / conversion if hud_control.speedVisible else 255 pcm_cancel_cmd = CC.cruiseControl.cancel if CC.longActive: @@ -161,7 +161,7 @@ class CarController: can_sends = [] # tester present - w/ no response (keeps radar disabled) - if self.CP.carFingerprint in HONDA_BOSCH and self.CP.openpilotLongitudinalControl: + if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl: if self.frame % 10 == 0: can_sends.append((0x18DAB0F1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 1)) diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 16880d1b1f..8189800368 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -5,7 +5,7 @@ from common.conversions import Conversions as CV from common.numpy_fast import interp from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from selfdrive.car.honda.hondacan import get_pt_bus +from selfdrive.car.honda.hondacan import get_cruise_speed_conversion, get_pt_bus from selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL, HONDA_BOSCH_RADARLESS from selfdrive.car.interfaces import CarStateBase @@ -246,8 +246,7 @@ class CarState(CarStateBase): ret.cruiseState.nonAdaptive = acc_hud["CRUISE_CONTROL_LABEL"] != 0 ret.cruiseState.standstill = acc_hud["CRUISE_SPEED"] == 252. - # on certain cars, CRUISE_SPEED changes to imperial with car's unit setting - conversion = CV.MPH_TO_MS if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS and not self.is_metric else CV.KPH_TO_MS + conversion = get_cruise_speed_conversion(self.CP.carFingerprint, self.is_metric) # On set, cruise set speed pulses between 254~255 and the set speed prev is set to avoid this. ret.cruiseState.speed = self.v_cruise_pcm_prev if acc_hud["CRUISE_SPEED"] > 160.0 else acc_hud["CRUISE_SPEED"] * conversion self.v_cruise_pcm_prev = ret.cruiseState.speed diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py index 17681444af..b7c448d1d3 100644 --- a/selfdrive/car/honda/hondacan.py +++ b/selfdrive/car/honda/hondacan.py @@ -21,6 +21,11 @@ def get_lkas_cmd_bus(car_fingerprint, radar_disabled=False): return 0 +def get_cruise_speed_conversion(car_fingerprint: str, is_metric: bool) -> float: + # on certain cars, CRUISE_SPEED changes to imperial with car's unit setting + return CV.MPH_TO_MS if car_fingerprint in HONDA_BOSCH_RADARLESS and not is_metric else CV.KPH_TO_MS + + def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, car_fingerprint, stock_brake): # TODO: do we loose pressure if we keep pump off for long? brakelights = apply_brake > 0 @@ -58,27 +63,36 @@ def create_acc_commands(packer, enabled, active, accel, gas, stopping, car_finge standstill = 1 if active and stopping else 0 standstill_release = 1 if active and not stopping else 0 + # common ACC_CONTROL values acc_control_values = { - # setting CONTROL_ON causes car to set POWERTRAIN_DATA->ACC_STATUS = 1 - "CONTROL_ON": control_on, - "GAS_COMMAND": gas_command, # used for gas - "ACCEL_COMMAND": accel_command, # used for brakes - "BRAKE_LIGHTS": braking, - "BRAKE_REQUEST": braking, - "STANDSTILL": standstill, - "STANDSTILL_RELEASE": standstill_release, + 'ACCEL_COMMAND': accel_command, + 'STANDSTILL': standstill, } - commands.append(packer.make_can_msg("ACC_CONTROL", bus, acc_control_values)) - acc_control_on_values = { - "SET_TO_3": 0x03, - "CONTROL_ON": enabled, - "SET_TO_FF": 0xff, - "SET_TO_75": 0x75, - "SET_TO_30": 0x30, - } - commands.append(packer.make_can_msg("ACC_CONTROL_ON", bus, acc_control_on_values)) + if car_fingerprint in HONDA_BOSCH_RADARLESS: + acc_control_values.update({ + "CONTROL_ON": enabled, + "IDLESTOP_ALLOW": 0, # disallows idle stop + }) + else: + acc_control_values.update({ + # setting CONTROL_ON causes car to set POWERTRAIN_DATA->ACC_STATUS = 1 + "CONTROL_ON": control_on, + "GAS_COMMAND": gas_command, # used for gas + "BRAKE_LIGHTS": braking, + "BRAKE_REQUEST": braking, + "STANDSTILL_RELEASE": standstill_release, + }) + acc_control_on_values = { + "SET_TO_3": 0x03, + "CONTROL_ON": enabled, + "SET_TO_FF": 0xff, + "SET_TO_75": 0x75, + "SET_TO_30": 0x30, + } + commands.append(packer.make_can_msg("ACC_CONTROL_ON", bus, acc_control_on_values)) + commands.append(packer.make_can_msg("ACC_CONTROL", bus, acc_control_values)) return commands diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index d3cf9fa891..7314afd50a 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -37,13 +37,11 @@ class CarInterface(CarInterfaceBase): if candidate in HONDA_BOSCH: ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaBosch)] ret.radarUnavailable = True - - if candidate not in HONDA_BOSCH_RADARLESS: - # Disable the radar and let openpilot control longitudinal - # WARNING: THIS DISABLES AEB! - ret.experimentalLongitudinalAvailable = True - ret.openpilotLongitudinalControl = experimental_long - + # Disable the radar and let openpilot control longitudinal + # WARNING: THIS DISABLES AEB! + # If Bosch radarless, this blocks ACC messages from the camera + ret.experimentalLongitudinalAvailable = True + ret.openpilotLongitudinalControl = experimental_long ret.pcmCruise = not ret.openpilotLongitudinalControl else: ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaNidec)] @@ -75,6 +73,8 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kpV = [0.25] ret.longitudinalTuning.kiV = [0.05] ret.longitudinalActuatorDelayUpperBound = 0.5 # s + if candidate in HONDA_BOSCH_RADARLESS: + ret.stopAccel = -4.0 else: # default longitudinal tuning for all hondas ret.longitudinalTuning.kpBP = [0., 5., 35.] From 2f954a50e3b34b8a38878bf8dbd37e359c0c6d3f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 29 Mar 2023 02:50:19 +0800 Subject: [PATCH 105/143] cabana: clear zoom stack after reset zoom (#27716) --- tools/cabana/chartswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 303b873faa..63a18094fc 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -145,6 +145,7 @@ void ChartsWidget::zoomIn(double min, double max) { void ChartsWidget::zoomReset() { setZoom(display_range.first, display_range.second); + zoom_stack.clear(); } void ChartsWidget::zoomUndo() { From 8903e03c8844df03783ae78d97e1294d0869ffea Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 29 Mar 2023 02:52:28 +0800 Subject: [PATCH 106/143] cabana: move dbc related files to dbc/ (#27712) * move dbc related files to dbc/ * move generate_dbc_json.py to dbc/ --- tools/cabana/.gitignore | 2 +- tools/cabana/SConscript | 5 +++-- tools/cabana/binaryview.h | 2 +- tools/cabana/chartswidget.h | 2 +- tools/cabana/commands.h | 2 +- tools/cabana/{ => dbc}/dbc.cc | 2 +- tools/cabana/{ => dbc}/dbc.h | 0 tools/cabana/{ => dbc}/dbcfile.cc | 2 +- tools/cabana/{ => dbc}/dbcfile.h | 2 +- tools/cabana/{ => dbc}/dbcmanager.cc | 2 +- tools/cabana/{ => dbc}/dbcmanager.h | 4 ++-- tools/cabana/{ => dbc}/generate_dbc_json.py | 0 tools/cabana/historylog.h | 2 +- tools/cabana/mainwin.cc | 2 +- tools/cabana/mainwin.h | 2 +- tools/cabana/messageswidget.h | 2 +- tools/cabana/streams/abstractstream.h | 2 +- tools/cabana/tests/test_cabana.cc | 2 +- tools/cabana/tools/findsimilarbits.cc | 2 +- tools/cabana/tools/findsimilarbits.h | 2 +- tools/cabana/util.h | 2 +- tools/cabana/videowidget.h | 2 +- 22 files changed, 23 insertions(+), 22 deletions(-) rename tools/cabana/{ => dbc}/dbc.cc (98%) rename tools/cabana/{ => dbc}/dbc.h (100%) rename tools/cabana/{ => dbc}/dbcfile.cc (99%) rename tools/cabana/{ => dbc}/dbcfile.h (97%) rename tools/cabana/{ => dbc}/dbcmanager.cc (99%) rename tools/cabana/{ => dbc}/dbcmanager.h (96%) rename tools/cabana/{ => dbc}/generate_dbc_json.py (100%) diff --git a/tools/cabana/.gitignore b/tools/cabana/.gitignore index 73879ab05d..c74ab7483c 100644 --- a/tools/cabana/.gitignore +++ b/tools/cabana/.gitignore @@ -3,5 +3,5 @@ moc_* _cabana settings -car_fingerprint_to_dbc.json +dbc/car_fingerprint_to_dbc.json tests/_test_cabana diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 5f4f7fc524..d9156f229a 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -28,7 +28,8 @@ cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "asset prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbc.cc', 'dbcfile.cc', 'dbcmanager.cc', +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', + 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc', 'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) @@ -39,5 +40,5 @@ if GetOption('test'): cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) def generate_dbc_json(target, source, env): - env.Execute('tools/cabana/generate_dbc_json.py --out tools/cabana/car_fingerprint_to_dbc.json') + env.Execute('tools/cabana/dbc/generate_dbc_json.py --out tools/cabana/dbc/car_fingerprint_to_dbc.json') cabana_env.Command('generate_dbc_json', [], generate_dbc_json) diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index f677d11941..8598fe490b 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -6,7 +6,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" class BinaryItemDelegate : public QStyledItemDelegate { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index de6cfc56b1..7f757f0211 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -13,7 +13,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" using namespace QtCharts; diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 2a5f40d584..84d1a6e2a1 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -3,7 +3,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" class EditMsgCommand : public QUndoCommand { diff --git a/tools/cabana/dbc.cc b/tools/cabana/dbc/dbc.cc similarity index 98% rename from tools/cabana/dbc.cc rename to tools/cabana/dbc/dbc.cc index 38002af06c..46302ad789 100644 --- a/tools/cabana/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -1,4 +1,4 @@ -#include "tools/cabana/dbc.h" +#include "tools/cabana/dbc/dbc.h" #include "tools/cabana/util.h" uint qHash(const MessageId &item) { diff --git a/tools/cabana/dbc.h b/tools/cabana/dbc/dbc.h similarity index 100% rename from tools/cabana/dbc.h rename to tools/cabana/dbc/dbc.h diff --git a/tools/cabana/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc similarity index 99% rename from tools/cabana/dbcfile.cc rename to tools/cabana/dbc/dbcfile.cc index 14a98347e2..8b4f98508c 100644 --- a/tools/cabana/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -1,4 +1,4 @@ -#include "tools/cabana/dbcfile.h" +#include "tools/cabana/dbc/dbcfile.h" #include diff --git a/tools/cabana/dbcfile.h b/tools/cabana/dbc/dbcfile.h similarity index 97% rename from tools/cabana/dbcfile.h rename to tools/cabana/dbc/dbcfile.h index b8fa3ea41b..082ee773b1 100644 --- a/tools/cabana/dbcfile.h +++ b/tools/cabana/dbc/dbcfile.h @@ -8,7 +8,7 @@ #include #include -#include "tools/cabana/dbc.h" +#include "tools/cabana/dbc/dbc.h" const QString AUTO_SAVE_EXTENSION = ".tmp"; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc similarity index 99% rename from tools/cabana/dbcmanager.cc rename to tools/cabana/dbc/dbcmanager.cc index 26c9105b43..0cc51989cd 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -1,4 +1,4 @@ -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include #include diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h similarity index 96% rename from tools/cabana/dbcmanager.h rename to tools/cabana/dbc/dbcmanager.h index 2a5aa6da25..31183e8199 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -8,8 +8,8 @@ #include #include -#include "tools/cabana/dbc.h" -#include "tools/cabana/dbcfile.h" +#include "tools/cabana/dbc/dbc.h" +#include "tools/cabana/dbc/dbcfile.h" typedef QSet SourceSet; const SourceSet SOURCE_ALL = {}; diff --git a/tools/cabana/generate_dbc_json.py b/tools/cabana/dbc/generate_dbc_json.py similarity index 100% rename from tools/cabana/generate_dbc_json.py rename to tools/cabana/dbc/generate_dbc_json.py diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 119b61a0e8..8b8d1b06d2 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -7,7 +7,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" #include "tools/cabana/util.h" diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 3b1edce236..c979a20f16 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -55,7 +55,7 @@ MainWindow::MainWindow() : QMainWindow() { main_win = this; qInstallMessageHandler(qLogMessageHandler); - for (const QString &fn : {"./car_fingerprint_to_dbc.json", "./tools/cabana/car_fingerprint_to_dbc.json"}) { + for (const QString &fn : {"./dbc/car_fingerprint_to_dbc.json", "./tools/cabana/dbc/car_fingerprint_to_dbc.json"}) { QFile json_file(fn); if (json_file.open(QIODevice::ReadOnly)) { fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 349fa3b28d..991a34931d 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -8,7 +8,7 @@ #include #include "tools/cabana/chartswidget.h" -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/detailwidget.h" #include "tools/cabana/messageswidget.h" #include "tools/cabana/videowidget.h" diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 08dac0d69a..d4ef896519 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -6,7 +6,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" class MessageListModel : public QAbstractTableModel { diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 37490d0ec6..0515f7c7e8 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -6,7 +6,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/settings.h" #include "tools/cabana/util.h" #include "tools/replay/replay.h" diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 3a5d64f0a5..4bc01a6a81 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -3,7 +3,7 @@ #undef INFO #include "catch2/catch.hpp" #include "tools/replay/logreader.h" -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" // demo route, first segment diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index e40498f045..7fe5b26671 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -8,7 +8,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) { diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index a40e2cd8df..77bfac19ca 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -6,7 +6,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" class FindSimilarBitsDlg : public QDialog { Q_OBJECT diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 330da77179..7f40c42352 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -12,7 +12,7 @@ #include #include -#include "tools/cabana/dbc.h" +#include "tools/cabana/dbc/dbc.h" class ChangeTracker { public: diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index a5ce8c345f..40a85662b6 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -12,7 +12,7 @@ #include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/qt/widgets/controls.h" -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" class Slider : public QSlider { From a1fb8d248022e7c47010fe7a91d84f12adc12114 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 29 Mar 2023 04:24:54 +0800 Subject: [PATCH 107/143] cabana: improve video thumbnail (#27711) --- tools/cabana/videowidget.cc | 119 +++++++++++++++--------------------- tools/cabana/videowidget.h | 21 ++++--- 2 files changed, 62 insertions(+), 78 deletions(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index e36e62131f..0e9714994e 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -1,18 +1,15 @@ #include "tools/cabana/videowidget.h" -#include #include #include #include #include -#include #include -#include -#include #include #include const int MIN_VIDEO_HEIGHT = 100; +const int THUMBNAIL_MARGIN = 3; static const QColor timeline_colors[] = { [(int)TimelineType::None] = QColor(111, 143, 175), @@ -27,16 +24,11 @@ static inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } -VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - QFrame *frame = new QFrame(this); - frame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); - main_layout->addWidget(frame); - - QVBoxLayout *frame_layout = new QVBoxLayout(frame); +VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { + setFrameStyle(QFrame::StyledPanel | QFrame::Plain); + auto main_layout = new QVBoxLayout(this); if (!can->liveStreaming()) { - frame_layout->addWidget(createCameraWidget()); + main_layout->addWidget(createCameraWidget()); } // btn controls @@ -57,7 +49,8 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { group->addButton(btn); if (speed == 1.0) btn->setChecked(true); } - frame_layout->addLayout(control_layout); + main_layout->addLayout(control_layout); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); @@ -91,12 +84,13 @@ QWidget *VideoWidget::createCameraWidget() { QVBoxLayout *l = new QVBoxLayout(w); l->setContentsMargins(0, 0, 0, 0); cam_widget = new CameraWidget("camerad", can->visionStreamType(), false); + cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); + cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); l->addWidget(cam_widget); // slider controls slider_layout = new QHBoxLayout(); - time_label = new ElidedLabel("00:00"); - time_label->setToolTip(tr("Click to set current time")); + time_label = new QLabel("00:00"); slider_layout->addWidget(time_label); slider = new Slider(this); @@ -106,12 +100,6 @@ QWidget *VideoWidget::createCameraWidget() { end_time_label = new QLabel(this); slider_layout->addWidget(end_time_label); l->addLayout(slider_layout); - - cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); - cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); - - QObject::connect(time_label, &ElidedLabel::clicked, this, &VideoWidget::timeLabelClicked); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); }); QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); @@ -123,29 +111,7 @@ QWidget *VideoWidget::createCameraWidget() { return w; } -void VideoWidget::timeLabelClicked() { - auto time_edit = new QTimeEdit(this); - auto init_date_time = can->currentDateTime(); - time_edit->setDateTime(init_date_time); - time_edit->setDisplayFormat("hh:mm:ss"); - time_label->setVisible(false); - slider_layout->insertWidget(0, time_edit); - QTimer::singleShot(0, [=]() { time_edit->setFocus(); }); - - QObject::connect(time_edit, &QTimeEdit::editingFinished, [=]() { - if (time_edit->dateTime() != init_date_time) { - int seconds = can->route()->datetime().secsTo(time_edit->dateTime()); - can->seekTo(seconds); - } - time_edit->setVisible(false); - time_label->setVisible(true); - time_edit->deleteLater(); - }); -} - void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { - if (can->liveStreaming()) return; - if (!is_zoomed) { min = 0; max = can->totalSeconds(); @@ -165,7 +131,7 @@ void VideoWidget::updatePlayBtnState() { } // Slider -Slider::Slider(QWidget *parent) : timer(this), QSlider(Qt::Horizontal, parent) { +Slider::Slider(QWidget *parent) : timer(this), thumbnail_label(this), QSlider(Qt::Horizontal, parent) { timer.callOnTimeout([this]() { timeline = can->getTimeline(); update(); @@ -198,29 +164,18 @@ void Slider::loadThumbnails() { if (log.load(qlog, &abort_load_thumbnail, {cereal::Event::Which::THUMBNAIL}, true, 0, 3)) { for (auto ev = log.events.cbegin(); ev != log.events.cend() && !abort_load_thumbnail; ++ev) { auto thumb = (*ev)->event.getThumbnail(); - QString str = getThumbnailString(thumb.getThumbnail()); - std::lock_guard lk(thumbnail_lock); - thumbnails[thumb.getTimestampEof()] = str; + auto data = thumb.getThumbnail(); + if (QPixmap pm; pm.loadFromData(data.begin(), data.size(), "jpeg")) { + pm = pm.scaledToHeight(MIN_VIDEO_HEIGHT - THUMBNAIL_MARGIN * 2, Qt::SmoothTransformation); + std::lock_guard lk(thumbnail_lock); + thumbnails[thumb.getTimestampEof()] = pm; + } } } } } } -QString Slider::getThumbnailString(const capnp::Data::Reader &data) { - QPixmap thumb; - if (thumb.loadFromData(data.begin(), data.size(), "jpeg")) { - thumb = thumb.scaled({thumb.width()/3, thumb.height()/3}, Qt::KeepAspectRatio); - thumbnail_size = thumb.size(); - QByteArray bytes; - QBuffer buffer(&bytes); - buffer.open(QIODevice::WriteOnly); - thumb.save(&buffer, "png"); - return QString("").arg(QString(bytes.toBase64())); - } - return {}; -} - void Slider::sliderChange(QAbstractSlider::SliderChange change) { if (change == QAbstractSlider::SliderValueChange) { int x = width() * ((value() - minimum()) / double(maximum() - minimum())); @@ -266,21 +221,45 @@ void Slider::mousePressEvent(QMouseEvent *e) { } void Slider::mouseMoveEvent(QMouseEvent *e) { - QString thumb; + QPixmap thumb; + double seconds = (minimum() + e->pos().x() * ((maximum() - minimum()) / (double)width())) / 1000.0; { - double seconds = (minimum() + e->pos().x() * ((maximum() - minimum()) / (double)width())) / 1000.0; std::lock_guard lk(thumbnail_lock); auto it = thumbnails.lowerBound((seconds + can->routeStartTime()) * 1e9); - if (it != thumbnails.end()) { - thumb = it.value(); - } + if (it != thumbnails.end()) thumb = it.value(); } - QPoint pt = mapToGlobal({e->pos().x() - thumbnail_size.width() / 2, -thumbnail_size.height() - 30}); - QToolTip::showText(pt, thumb, this, rect()); + int x = std::clamp(e->pos().x() - thumb.width() / 2, THUMBNAIL_MARGIN, rect().right() - thumb.width() - THUMBNAIL_MARGIN); + int y = -thumb.height() - THUMBNAIL_MARGIN - style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing); + thumbnail_label.showPixmap(mapToGlobal({x, y}), formatTime(seconds), thumb); QSlider::mouseMoveEvent(e); } void Slider::leaveEvent(QEvent *event) { - QToolTip::hideText(); + thumbnail_label.hide(); QSlider::leaveEvent(event); } + +// ThumbnailLabel + +ThumbnailLabel::ThumbnailLabel(QWidget *parent) : QWidget(parent, Qt::Tool | Qt::FramelessWindowHint) { + setAttribute(Qt::WA_ShowWithoutActivating); + setVisible(false); +} + +void ThumbnailLabel::showPixmap(const QPoint &pt, const QString &sec, const QPixmap &pm) { + pixmap = pm; + second = sec; + setVisible(!pm.isNull()); + if (isVisible()) { + setGeometry({pt, pm.size()}); + update(); + } +} + +void ThumbnailLabel::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.drawPixmap(0, 0, pixmap); + p.setPen(QPen(Qt::white, 2)); + p.drawRect(rect()); + p.drawText(rect().adjusted(0, 0, 0, -THUMBNAIL_MARGIN), second, Qt::AlignHCenter | Qt::AlignBottom); +} diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 40a85662b6..00b059428d 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -11,10 +11,17 @@ #include #include "selfdrive/ui/qt/widgets/cameraview.h" -#include "selfdrive/ui/qt/widgets/controls.h" -#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +class ThumbnailLabel : public QWidget { +public: + ThumbnailLabel(QWidget *parent); + void showPixmap(const QPoint &pt, const QString &sec, const QPixmap &pm); + void paintEvent(QPaintEvent *event) override; + QPixmap pixmap; + QString second; +}; + class Slider : public QSlider { Q_OBJECT @@ -30,19 +37,18 @@ private: void paintEvent(QPaintEvent *ev) override; void streamStarted(); void loadThumbnails(); - QString getThumbnailString(const capnp::Data::Reader &data); int slider_x = -1; std::vector> timeline; std::mutex thumbnail_lock; std::atomic abort_load_thumbnail = false; - QMap thumbnails; + QMap thumbnails; QFuture thumnail_future; - QSize thumbnail_size = {}; + ThumbnailLabel thumbnail_label; QTimer timer; }; -class VideoWidget : public QWidget { +class VideoWidget : public QFrame { Q_OBJECT public: @@ -52,12 +58,11 @@ public: protected: void updateState(); void updatePlayBtnState(); - void timeLabelClicked(); QWidget *createCameraWidget(); CameraWidget *cam_widget; QLabel *end_time_label; - ElidedLabel *time_label; + QLabel *time_label; QHBoxLayout *slider_layout; QPushButton *play_btn; Slider *slider; From eee3c8ee6007918d8a5ebf80ab236659a4738356 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 29 Mar 2023 04:25:13 +0800 Subject: [PATCH 108/143] cabana: add sparkline to signal view (#27717) * display small line chart beside signal * TODO * 1 px width * auto stretch * static lines * use std::vector * cleanup * use ts from last message * remove hardcorded size --- tools/cabana/chartswidget.cc | 2 +- tools/cabana/signaledit.cc | 64 +++++++++++++++++++++++++++++------- tools/cabana/signaledit.h | 4 ++- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 63a18094fc..ef8524be37 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -558,7 +558,7 @@ void ChartView::updateSeries(const cabana::Signal *sig) { } s.series->setColor(getColor(s.sig)); - auto msgs = can->events().at(s.msg_id); + const auto &msgs = can->events().at(s.msg_id); auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = s.last_value_mono_time}); int new_size = std::max(s.vals.size() + std::distance(first, msgs.cend()), settings.max_cached_minutes * 60 * 100); if (s.vals.capacity() <= new_size) { diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 99ec09195b..a2455a0317 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -62,14 +62,11 @@ void SignalModel::updateState(const QHash *msgs) { auto &dat = can->lastMessage(msg_id).dat; int row = 0; for (auto item : root->children) { - QString value = QString::number(get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig), 'f', item->sig->precision); - if (!item->sig->unit.isEmpty()){ - value += " " + item->sig->unit; - } - if (value != item->sig_val) { - item->sig_val = value; - emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); + item->sig_val = QString::number(get_raw_value((uint8_t *)dat.constData(), dat.size(), *item->sig), 'f', item->sig->precision); + if (!item->sig->unit.isEmpty()) { + item->sig_val += " " + item->sig->unit; } + emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); ++row; } } @@ -321,6 +318,8 @@ QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo } void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); auto item = (SignalModel::Item *)index.internalPointer(); if (index.column() == 0 && item && item->type == SignalModel::Item::Sig) { painter->save(); @@ -331,8 +330,6 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // color label auto bg_color = getColor(item->sig); - int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; - int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); QRect rc{option.rect.left() + h_margin, option.rect.top(), color_label_width, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); @@ -351,19 +348,62 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); } else if (index.column() == 1 && item && item->type == SignalModel::Item::Sig) { - // draw signal value if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } - painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); - QRect rc = option.rect.adjusted(0, 0, -70, 0); + + drawSparkline(painter, option, index); + // draw signal value + int right_offset = ((SignalView *)parent())->tree->indexWidget(index)->sizeHint().width() + 2 * h_margin; + QRect rc = option.rect.adjusted(0, 0, -right_offset, 0); auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); + painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); } else { QStyledItemDelegate::paint(painter, option, index); } } +void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + static std::vector points; + // TODO: get seconds from settings. + const uint64_t chart_seconds = 15; // seconds + const auto &msg_id = ((SignalView *)parent())->msg_id; + const auto &msgs = can->events().at(msg_id); + uint64_t ts = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9; + auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = (uint64_t)std::max(ts - chart_seconds * 1e9, 0)}); + if (first != msgs.cend()) { + double min = std::numeric_limits::max(); + double max = std::numeric_limits::lowest(); + const auto sig = ((SignalModel::Item *)index.internalPointer())->sig; + auto last = std::lower_bound(first, msgs.cend(), CanEvent{.mono_time = ts}); + points.clear(); + for (auto it = first; it != last; ++it) { + double value = get_raw_value(it->dat, it->size, *sig); + points.emplace_back((it->mono_time - first->mono_time) / 1e9, value); + min = std::min(min, value); + max = std::max(max, value); + } + if (min == max) { + min -= 1; + max += 1; + } + + int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + int v_margin = std::max(option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 2, 4); + const double xscale = (option.rect.width() - 175.0 * option.widget->devicePixelRatioF() - h_margin * 2) / chart_seconds; + const double yscale = (option.rect.height() - v_margin * 2) / (max - min); + const int left = option.rect.left(); + const int top = option.rect.top() + v_margin; + for (auto &pt : points) { + pt.rx() = left + pt.x() * xscale; + pt.ry() = top + std::abs(pt.y() - max) * yscale; + } + painter->setPen(getColor(sig)); + painter->drawPolyline(points.data(), points.size()); + } +} + 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 || diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index d6bad6d88c..163edcad69 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -82,6 +82,7 @@ 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; + void drawSparkline(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QValidator *name_validator, *double_validator; QFont small_font; const int color_label_width = 18; @@ -99,6 +100,7 @@ public: void selectSignal(const cabana::Signal *sig, bool expand = false); void rowClicked(const QModelIndex &index); SignalModel *model = nullptr; + MessageId msg_id; signals: void highlight(const cabana::Signal *sig); @@ -117,9 +119,9 @@ private: } }; - MessageId msg_id; TreeView *tree; QLineEdit *filter_edit; ChartsWidget *charts; QLabel *signal_count_lb; + friend SignalItemDelegate; }; From 32da60c551594247bb04b179d95357a15370519a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 28 Mar 2023 13:26:01 -0700 Subject: [PATCH 109/143] Update RELEASES.md --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index 55b0dbad7e..55edc47c27 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,6 @@ Version 0.9.2 (2023-03-XX) ======================== +* New driving model, trained on a new dataset * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. * Buick LaCrosse 2017-19 support thanks to koch-cf! * Škoda Fabia 2022-23 support thanks to jyoung8607! From 267974e00200324805c76ef2e8ae279efa7757a1 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 28 Mar 2023 19:04:14 -0400 Subject: [PATCH 110/143] remove accFaultedTemp, add steerTimeLimit (#27720) * remove accFaultedTemp * retry CI * bump cereal * grab the new steerTimeLimit Event * bump cereal to updated master --- cereal | 2 +- selfdrive/controls/lib/events.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cereal b/cereal index e276226dbe..1f0d21df73 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit e276226dbe38c811a4c1f3a9b689cd3ecbd05a20 +Subproject commit 1f0d21df7307228218a4b874a3fdcd819b1558af diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index e4ddfb5326..67a4735e14 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -658,6 +658,11 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { ET.NO_ENTRY: NoEntryAlert("Steering Temporarily Unavailable"), }, + EventName.steerTimeLimit: { + ET.SOFT_DISABLE: soft_disable_alert("Vehicle Steering Time Limit"), + ET.NO_ENTRY: NoEntryAlert("Vehicle Steering Time Limit"), + }, + EventName.outOfSpace: { ET.PERMANENT: out_of_space_alert, ET.NO_ENTRY: NoEntryAlert("Out of Storage"), @@ -811,10 +816,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), }, - EventName.accFaultedTemp: { - ET.NO_ENTRY: NoEntryAlert("Cruise Temporarily Faulted"), - }, - EventName.controlsMismatch: { ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch"), ET.NO_ENTRY: NoEntryAlert("Controls Mismatch"), From 85908f7e2bd96cb52ad7a52e3b9a1cf94b5b197b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 28 Mar 2023 17:48:16 -0700 Subject: [PATCH 111/143] process replay: fix socket-ful replay flakiness (#27721) * process replay: fix socket-ful replay flakiness * bump up laikad timeout * bump * bump again * revert that --- .../test/process_replay/process_replay.py | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 2b9096b423..43b329e916 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -5,7 +5,8 @@ import sys import threading import time import signal -from collections import namedtuple +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Callable import capnp @@ -28,7 +29,20 @@ TIMEOUT = 15 PROC_REPLAY_DIR = os.path.dirname(os.path.abspath(__file__)) FAKEDATA = os.path.join(PROC_REPLAY_DIR, "fakedata/") -ProcessConfig = namedtuple('ProcessConfig', ['proc_name', 'pub_sub', 'ignore', 'init_callback', 'should_recv_callback', 'tolerance', 'fake_pubsubmaster', 'submaster_config', 'environ', 'subtest_name', "field_tolerances"], defaults=({}, {}, "", {})) +@dataclass +class ProcessConfig: + proc_name: str + pub_sub: Dict[str, List[str]] + ignore: List[str] + 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) + environ: Dict[str, str] = field(default_factory=dict) + subtest_name: str = "" + field_tolerances: Dict[str, float] = field(default_factory=dict) + timeout: int = 30 def wait_for_event(evt): @@ -365,6 +379,7 @@ CONFIGS = [ should_recv_callback=None, tolerance=NUMPY_TOLERANCE, fake_pubsubmaster=False, + timeout=60*10, # first messages are blocked on internet assistance ), ProcessConfig( proc_name="torqued", @@ -532,8 +547,9 @@ def python_replay_process(cfg, lr, fingerprint=None): def replay_process_with_sockets(cfg, lr, fingerprint=None): - sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] 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())] @@ -556,22 +572,26 @@ def replay_process_with_sockets(cfg, lr, fingerprint=None): while not any(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): time.sleep(0) - # Make sure all subscribers are connected - sockets = {s: messaging.sub_sock(s, timeout=2000) for s in sub_sockets} - for s in sub_sockets: - messaging.recv_one_or_none(sockets[s]) + for s in sockets.values(): + messaging.recv_one_or_none(s) # Do the replay cnt = 0 for msg in pub_msgs: - with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): + with Timeout(cfg.timeout, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): + 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) + + # 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) - 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) for s in resp_sockets: m = messaging.recv_one_retry(sockets[s]) m = m.as_builder() From d6961152b824518f584d2ffad831312447d79d5f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 30 Mar 2023 03:43:43 +0800 Subject: [PATCH 112/143] cabana: add a slider to set sparkline time range (#27727) * add slider to set sparkline time range * rename signaleedit to signalview * default is 15s * util::formatSeconds * update() is faster than invalidate * draw points * fix scatter width --- tools/cabana/SConscript | 2 +- tools/cabana/binaryview.cc | 2 +- tools/cabana/chartswidget.cc | 30 +++++++------ tools/cabana/detailwidget.h | 2 +- tools/cabana/settings.cc | 2 + tools/cabana/settings.h | 3 +- tools/cabana/{signaledit.cc => signalview.cc} | 45 +++++++++++++++---- tools/cabana/{signaledit.h => signalview.h} | 5 +++ tools/cabana/util.h | 4 ++ tools/cabana/videowidget.cc | 13 ++---- 10 files changed, 73 insertions(+), 35 deletions(-) rename tools/cabana/{signaledit.cc => signalview.cc} (94%) rename tools/cabana/{signaledit.h => signalview.h} (96%) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index d9156f229a..7d5129fc16 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -28,7 +28,7 @@ cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "asset prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signalview.cc', 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc', 'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 0a4f6fc999..84225bb96c 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -11,7 +11,7 @@ #include #include "tools/cabana/commands.h" -#include "tools/cabana/signaledit.h" +#include "tools/cabana/signalview.h" // BinaryView diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index ef8524be37..24415c6f95 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -189,7 +189,7 @@ void ChartsWidget::setMaxChartRange(int value) { void ChartsWidget::updateToolBar() { title_label->setText(tr("Charts: %1").arg(charts.size())); columns_action->setText(tr("Column: %1").arg(column_count)); - range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); + range_lb->setText(QString("Range: %1 ").arg(utils::formatSeconds(max_chart_range))); range_lb_action->setVisible(!is_zoomed); range_slider_action->setVisible(!is_zoomed); undo_zoom_action->setVisible(is_zoomed); @@ -528,7 +528,7 @@ void ChartView::updatePlot(double cur, double min, double max) { updateAxisY(); updateSeriesPoints(); } - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); + update(); } void ChartView::updateSeriesPoints() { @@ -536,14 +536,16 @@ void ChartView::updateSeriesPoints() { for (auto &s : sigs) { auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); auto end = std::lower_bound(begin, s.vals.end(), axis_x->max(), xLessThan); - - int num_points = std::max(end - begin, 1); - int pixels_per_point = width() / num_points; - - if (series_type == SeriesType::Scatter) { - ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8) * devicePixelRatioF()); - } else { - s.series->setPointsVisible(pixels_per_point > 20); + if (begin != end) { + int num_points = std::max((end - begin), 1); + QPointF right_pt = end == s.vals.end() ? s.vals.back() : *end; + double pixels_per_point = (chart()->mapToPosition(right_pt).x() - chart()->mapToPosition(*begin).x()) / num_points; + + if (series_type == SeriesType::Scatter) { + ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 2.0, 2.0, 8.0) * devicePixelRatioF()); + } else { + s.series->setPointsVisible(pixels_per_point > 20); + } } } } @@ -715,7 +717,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { // zoom in if selected range is greater than 0.5s emit zoomIn(min_rounded, max_rounded); } else { - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); + update(); } event->accept(); } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { @@ -773,7 +775,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); QPointF tooltip_pt(x + 12, plot_area.top() - 20); QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), text_list.join("
"), this, plot_area.toRect()); - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); + update(); } else { QToolTip::hideText(); } @@ -786,7 +788,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (rubber_rect != rubber->geometry()) { rubber->setGeometry(rubber_rect); } - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); + update(); } } @@ -847,8 +849,8 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { if (s.series->useOpenGL() && s.series->isVisible() && s.series->pointsVisible()) { auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), xLessThan); + painter->setBrush(s.series->color()); for (auto it = first; it != last; ++it) { - painter->setBrush(s.series->color()); painter->drawEllipse(chart()->mapToPosition(*it), 4, 4); } } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index cc5bffd534..2794d41b99 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -8,7 +8,7 @@ #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" #include "tools/cabana/historylog.h" -#include "tools/cabana/signaledit.h" +#include "tools/cabana/signalview.h" class EditMessageDialog : public QDialog { public: diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 00bbb94de5..9e829708b1 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -27,6 +27,7 @@ void Settings::save() { s.setValue("recent_files", recent_files); s.setValue("message_header_state", message_header_state); s.setValue("chart_series_type", chart_series_type); + s.setValue("sparkline_range", sparkline_range); } void Settings::load() { @@ -44,6 +45,7 @@ void Settings::load() { recent_files = s.value("recent_files").toStringList(); message_header_state = s.value("message_header_state").toByteArray(); chart_series_type = s.value("chart_series_type", 0).toInt(); + sparkline_range = s.value("sparkline_range", 15).toInt(); } // SettingsDlg diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index c3ba906576..a8b6d189a5 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -17,8 +17,9 @@ public: int max_cached_minutes = 30; int chart_height = 200; int chart_column_count = 1; - int chart_range = 3 * 60; // e minutes + int chart_range = 3 * 60; // 3 minutes int chart_series_type = 0; + int sparkline_range = 15; // 15 seconds QString last_dir; QString last_route_dir; QByteArray geometry; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signalview.cc similarity index 94% rename from tools/cabana/signaledit.cc rename to tools/cabana/signalview.cc index a2455a0317..3f8a38825a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signalview.cc @@ -1,4 +1,4 @@ -#include "tools/cabana/signaledit.h" +#include "tools/cabana/signalview.h" #include #include @@ -366,17 +366,15 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { static std::vector points; - // TODO: get seconds from settings. - const uint64_t chart_seconds = 15; // seconds const auto &msg_id = ((SignalView *)parent())->msg_id; const auto &msgs = can->events().at(msg_id); uint64_t ts = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9; - auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = (uint64_t)std::max(ts - chart_seconds * 1e9, 0)}); - if (first != msgs.cend()) { + auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = (uint64_t)std::max(ts - settings.sparkline_range * 1e9, 0)}); + auto last = std::upper_bound(first, msgs.cend(), CanEvent{.mono_time = ts}); + if (first != last) { double min = std::numeric_limits::max(); double max = std::numeric_limits::lowest(); const auto sig = ((SignalModel::Item *)index.internalPointer())->sig; - auto last = std::lower_bound(first, msgs.cend(), CanEvent{.mono_time = ts}); points.clear(); for (auto it = first; it != last; ++it) { double value = get_raw_value(it->dat, it->size, *sig); @@ -391,7 +389,7 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionView int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); int v_margin = std::max(option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 2, 4); - const double xscale = (option.rect.width() - 175.0 * option.widget->devicePixelRatioF() - h_margin * 2) / chart_seconds; + const double xscale = (option.rect.width() - 175.0 * option.widget->devicePixelRatioF() - h_margin * 2) / settings.sparkline_range; const double yscale = (option.rect.height() - v_margin * 2) / (max - min); const int left = option.rect.left(); const int top = option.rect.top() + v_margin; @@ -401,6 +399,13 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionView } painter->setPen(getColor(sig)); painter->drawPolyline(points.data(), points.size()); + if ((points.back().x() - points.front().x()) / points.size() > 10) { + painter->setPen(Qt::NoPen); + painter->setBrush(getColor(sig)); + for (const auto &pt : points) { + painter->drawEllipse(pt, 2, 2); + } + } } } @@ -451,6 +456,17 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), filter_edit->setPlaceholderText(tr("filter signals")); hl->addWidget(filter_edit); hl->addStretch(1); + + // WARNING: increasing the maximum range can result in severe performance degradation. + // 30s is a reasonable value at present. + const int max_range = 30; // 30s + settings.sparkline_range = std::clamp(settings.sparkline_range, 1, max_range); + hl->addWidget(sparkline_label = new QLabel()); + hl->addWidget(sparkline_range_slider = new QSlider(Qt::Horizontal, this)); + sparkline_range_slider->setRange(1, max_range); + sparkline_range_slider->setValue(settings.sparkline_range); + sparkline_range_slider->setToolTip(tr("Sparkline time range")); + auto collapse_btn = toolButton("dash-square", tr("Collapse All")); collapse_btn->setIconSize({12, 12}); hl->addWidget(collapse_btn); @@ -473,8 +489,10 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), main_layout->setSpacing(0); main_layout->addWidget(title_bar); main_layout->addWidget(tree); + updateToolBar(); QObject::connect(filter_edit, &QLineEdit::textEdited, model, &SignalModel::setFilter); + QObject::connect(sparkline_range_slider, &QSlider::valueChanged, this, &SignalView::setSparklineRange); QObject::connect(collapse_btn, &QPushButton::clicked, tree, &QTreeView::collapseAll); QObject::connect(tree, &QAbstractItemView::clicked, this, &SignalView::rowClicked); QObject::connect(tree, &QTreeView::viewportEntered, [this]() { emit highlight(nullptr); }); @@ -521,7 +539,7 @@ void SignalView::rowsChanged() { }); } } - signal_count_lb->setText(tr("Signals: %1").arg(model->rowCount())); + updateToolBar(); updateChartState(); } @@ -569,6 +587,17 @@ void SignalView::signalHovered(const cabana::Signal *sig) { } } +void SignalView::updateToolBar() { + signal_count_lb->setText(tr("Signals: %1").arg(model->rowCount())); + sparkline_label->setText(QString("Range: %1 ").arg(utils::formatSeconds(settings.sparkline_range))); +} + +void SignalView::setSparklineRange(int value) { + settings.sparkline_range = value; + updateToolBar(); + model->updateState(nullptr); +} + void SignalView::leaveEvent(QEvent *event) { emit highlight(nullptr); QWidget::leaveEvent(event); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signalview.h similarity index 96% rename from tools/cabana/signaledit.h rename to tools/cabana/signalview.h index 163edcad69..50ba4e06b8 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signalview.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,8 @@ signals: private: void rowsChanged(); void leaveEvent(QEvent *event); + void updateToolBar(); + void setSparklineRange(int value); struct TreeView : public QTreeView { TreeView(QWidget *parent) : QTreeView(parent) {} @@ -120,6 +123,8 @@ private: }; TreeView *tree; + QLabel *sparkline_label; + QSlider *sparkline_range_slider; QLineEdit *filter_edit; ChartsWidget *charts; QLabel *signal_count_lb; diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 7f40c42352..e90a838af8 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -97,6 +98,9 @@ public: namespace utils { QPixmap icon(const QString &id); +inline QString formatSeconds(int seconds) { + return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); +} } QToolButton *toolButton(const QString &icon, const QString &tooltip); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 0e9714994e..fe9e00bc45 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -1,7 +1,6 @@ #include "tools/cabana/videowidget.h" #include -#include #include #include #include @@ -20,10 +19,6 @@ static const QColor timeline_colors[] = { [(int)TimelineType::AlertCritical] = QColor(199, 0, 57), }; -static inline QString formatTime(int seconds) { - return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); -} - VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); auto main_layout = new QVBoxLayout(this); @@ -101,11 +96,11 @@ QWidget *VideoWidget::createCameraWidget() { slider_layout->addWidget(end_time_label); l->addLayout(slider_layout); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); }); - QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); + QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(utils::formatSeconds(value / 1000)); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); QObject::connect(can, &AbstractStream::streamStarted, [this]() { - end_time_label->setText(formatTime(can->totalSeconds())); + end_time_label->setText(utils::formatSeconds(can->totalSeconds())); slider->setRange(0, can->totalSeconds() * 1000); }); return w; @@ -116,7 +111,7 @@ void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { min = 0; max = can->totalSeconds(); } - end_time_label->setText(formatTime(max)); + end_time_label->setText(utils::formatSeconds(max)); slider->setRange(min * 1000, max * 1000); } @@ -230,7 +225,7 @@ void Slider::mouseMoveEvent(QMouseEvent *e) { } int x = std::clamp(e->pos().x() - thumb.width() / 2, THUMBNAIL_MARGIN, rect().right() - thumb.width() - THUMBNAIL_MARGIN); int y = -thumb.height() - THUMBNAIL_MARGIN - style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing); - thumbnail_label.showPixmap(mapToGlobal({x, y}), formatTime(seconds), thumb); + thumbnail_label.showPixmap(mapToGlobal({x, y}), utils::formatSeconds(seconds), thumb); QSlider::mouseMoveEvent(e); } From e0afaa4eeec1dd36ede1aea809d34637ef968385 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 29 Mar 2023 22:17:46 +0200 Subject: [PATCH 113/143] cabana: fix merging sources for already open DBC file (#27715) * fix build * fix merging sources --- tools/cabana/dbc/dbcmanager.cc | 3 ++- tools/cabana/dbc/dbcmanager.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/cabana/dbc/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc index 0cc51989cd..49527765a8 100644 --- a/tools/cabana/dbc/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -14,7 +14,8 @@ bool DBCManager::open(SourceSet s, const QString &dbc_file_name, QString *error) // Check if file is already open, and merge sources if (dbc_file->filename == dbc_file_name) { - ss |= s; + dbc_files[i] = {ss | s, dbc_file}; + emit DBCFileChanged(); return true; } diff --git a/tools/cabana/dbc/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h index 31183e8199..f9af96516c 100644 --- a/tools/cabana/dbc/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -1,6 +1,8 @@ #pragma once #include +#include + #include #include #include From 18253982db08434f42a660689144a1d4eafd1a1b Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 29 Mar 2023 16:56:45 -0400 Subject: [PATCH 114/143] torqued: reset LiveTorqueParameters on calibration reset (#27732) --- selfdrive/ui/qt/offroad/settings.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 63b87149d4..5222dcca8f 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -193,6 +193,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { connect(resetCalibBtn, &ButtonControl::clicked, [&]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), tr("Reset"), this)) { params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters") } }); addItem(resetCalibBtn); From 46069738d6f4a5c40e4aededbba797b38f8d4bcb Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 29 Mar 2023 14:01:22 -0700 Subject: [PATCH 115/143] Revert "torqued: reset LiveTorqueParameters on calibration reset" (#27736) Revert "torqued: reset LiveTorqueParameters on calibration reset (#27732)" This reverts commit 18253982db08434f42a660689144a1d4eafd1a1b. --- selfdrive/ui/qt/offroad/settings.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 5222dcca8f..63b87149d4 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -193,7 +193,6 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { connect(resetCalibBtn, &ButtonControl::clicked, [&]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), tr("Reset"), this)) { params.remove("CalibrationParams"); - params.remove("LiveTorqueParameters") } }); addItem(resetCalibBtn); From 8e3ed8f10b5e9eae52b1374a81d46dcd022e3598 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:30:27 -0400 Subject: [PATCH 116/143] torqued: reset LiveTorqueParameters on calibration reset (#27737) * torqued: reset LiveTorqueParameters on calibration reset * gotta have this --- selfdrive/ui/qt/offroad/settings.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 63b87149d4..c22484167c 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -193,6 +193,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { connect(resetCalibBtn, &ButtonControl::clicked, [&]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), tr("Reset"), this)) { params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); } }); addItem(resetCalibBtn); From 15b880c0ea6fb306e916a2ec015b5f03cec22b20 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 29 Mar 2023 15:10:39 -0700 Subject: [PATCH 117/143] Bolt EUV: Non-linear torque function (#27696) * add erf based ff * silly bug; diff of nonlinear != nonlinear of diff * add sigmoid based ff, ensure slope at 0 > 1 * reduce steer down limit and increase driver allowance * rebase panda * atry without friction, and with tanh nonlinear * finalize the nonlinear function * do not disable friction compensation in the ff * bump panda * bump panda * update refs * update refs * resolve comments * Add type hints --------- Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/car/gm/interface.py | 28 +++++++++++++++++++-- selfdrive/car/gm/values.py | 4 +-- selfdrive/car/interfaces.py | 16 +++++------- selfdrive/controls/lib/drive_helpers.py | 10 ++++++++ selfdrive/controls/lib/latcontrol_torque.py | 6 +++-- selfdrive/test/process_replay/ref_commit | 2 +- 7 files changed, 50 insertions(+), 18 deletions(-) diff --git a/panda b/panda index db6c50cd09..a1e1451d1c 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit db6c50cd09f773c231f962fc0e31b4612c572b08 +Subproject commit a1e1451d1c2f23b953d82eea7691a657c9a8a75a diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index f501c8c7dd..6e2797ce24 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -1,13 +1,14 @@ #!/usr/bin/env python3 from cereal import car -from math import fabs +from math import fabs, exp from panda import Panda from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus -from selfdrive.car.interfaces import CarInterfaceBase +from selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD +from selfdrive.controls.lib.drive_helpers import get_friction ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -44,6 +45,29 @@ class CarInterface(CarInterfaceBase): else: return CarInterfaceBase.get_steer_feedforward_default + @staticmethod + def torque_from_lateral_accel_bolt(lateral_accel_value: float, torque_params: car.CarParams.LateralTorqueTuning, + lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool) -> float: + friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation) + + def sig(val): + return 1 / (1 + exp(-val)) - 0.5 + + # The "lat_accel vs torque" relationship is assumed to be the sum of "sigmoid + linear" curves + # An important thing to consider is that the slope at 0 should be > 0 (ideally >1) + # This has big effect on the stability about 0 (noise when going straight) + # ToDo: To generalize to other GMs, explore tanh function as the nonlinear + a, b, c, _ = [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178] # weights computed offline + + steer_torque = (sig(lateral_accel_value * a) * b) + (lateral_accel_value * c) + return float(steer_torque) + friction + + def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: + if self.CP.carFingerprint == CAR.BOLT_EUV: + return self.torque_from_lateral_accel_bolt + else: + return self.torque_from_lateral_accel_linear + @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "gm" diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 0d13cb9827..1b814e00b2 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -14,8 +14,8 @@ class CarControllerParams: STEER_STEP = 3 # Active control frames per command (~33hz) INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) STEER_DELTA_UP = 10 # Delta rates require review due to observed EPS weakness - STEER_DELTA_DOWN = 25 - STEER_DRIVER_ALLOWANCE = 50 + STEER_DELTA_DOWN = 15 + STEER_DRIVER_ALLOWANCE = 65 STEER_DRIVER_MULTIPLIER = 4 STEER_DRIVER_FACTOR = 100 NEAR_STOP_BRAKE_PHASE = 0.5 # m/s diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 249818369c..cf6d7280fa 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -8,10 +8,10 @@ from cereal import car from common.basedir import BASEDIR from common.conversions import Conversions as CV from common.kalman.simple_kalman import KF1D -from common.numpy_fast import clip, interp +from common.numpy_fast import clip from common.realtime import DT_CTRL from selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness -from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_center_deadzone +from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, get_friction from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.vehicle_model import VehicleModel @@ -131,15 +131,11 @@ class CarInterfaceBase(ABC): return self.get_steer_feedforward_default @staticmethod - def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, friction_compensation): + def torque_from_lateral_accel_linear(lateral_accel_value: float, torque_params: car.CarParams.LateralTorqueTuning, + lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool) -> float: # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) - friction_interp = interp( - apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), - [-FRICTION_THRESHOLD, FRICTION_THRESHOLD], - [-torque_params.friction, torque_params.friction] - ) - friction = friction_interp if friction_compensation else 0.0 - return (lateral_accel_value / torque_params.latAccelFactor) + friction + friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation) + return (lateral_accel_value / float(torque_params.latAccelFactor)) + friction def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: return self.torque_from_lateral_accel_linear diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 05c3897335..cd6525949c 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -190,3 +190,13 @@ def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates): current_curvature_desired + max_curvature_rate * DT_MDL) return safe_desired_curvature, safe_desired_curvature_rate + + +def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, friction_threshold: float, torque_params: car.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float: + friction_interp = interp( + apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), + [-friction_threshold, friction_threshold], + [-torque_params.friction, torque_params.friction] + ) + friction = float(friction_interp) if friction_compensation else 0.0 + return friction diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 2f56094379..6550b19227 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -61,10 +61,12 @@ class LatControlTorque(LatControl): low_speed_factor = interp(CS.vEgo, LOW_SPEED_X, LOW_SPEED_Y)**2 setpoint = desired_lateral_accel + low_speed_factor * desired_curvature measurement = actual_lateral_accel + low_speed_factor * actual_curvature - error = setpoint - measurement gravity_adjusted_lateral_accel = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY - pid_log.error = self.torque_from_lateral_accel(error, self.torque_params, error, + torque_from_setpoint = self.torque_from_lateral_accel(setpoint, self.torque_params, setpoint, lateral_accel_deadzone, friction_compensation=False) + torque_from_measurement = self.torque_from_lateral_accel(measurement, self.torque_params, measurement, + lateral_accel_deadzone, friction_compensation=False) + pid_log.error = torque_from_setpoint - torque_from_measurement ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params, desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, friction_compensation=True) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 556781738d..57f71fc807 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -50f1e873095fe2462d2aadb9c401bda76759c01c +1da098f096cee9f2871dafd2788dc9ddac85eeab \ No newline at end of file From 3df2e55bee3b72a9ec12dabc427b2908c16637a3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 29 Mar 2023 16:31:35 -0700 Subject: [PATCH 118/143] tizi: add panda siren fault (#27738) Co-authored-by: Comma Device --- cereal | 2 +- panda | 2 +- selfdrive/boardd/boardd.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 1f0d21df73..d70d215de6 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 1f0d21df7307228218a4b874a3fdcd819b1558af +Subproject commit d70d215de6c584f671272d2de2f46a4f778e9f14 diff --git a/panda b/panda index a1e1451d1c..12b9b65985 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit a1e1451d1c2f23b953d82eea7691a657c9a8a75a +Subproject commit 12b9b65985edf7207a1dfd48de0b714192e6e55d diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 4faa08d536..8f045c2a69 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -418,7 +418,7 @@ std::optional send_panda_states(PubMaster *pm, const std::vector size_t j = 0; for (size_t f = size_t(cereal::PandaState::FaultType::RELAY_MALFUNCTION); - f <= size_t(cereal::PandaState::FaultType::INTERRUPT_RATE_EXTI); f++) { + f <= size_t(cereal::PandaState::FaultType::SIREN_MALFUNCTION); f++) { if (fault_bits.test(f)) { faults.set(j, cereal::PandaState::FaultType(f)); j++; From eca3838237463fe34c6abd0e6592a935008d8ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 29 Mar 2023 16:35:30 -0700 Subject: [PATCH 119/143] Locationd qcom retune (#27739) --- selfdrive/locationd/locationd.cc | 17 ++++++++++++----- selfdrive/locationd/locationd.h | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 307626506a..87c5f644c5 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -27,7 +27,6 @@ const double MAX_FILTER_REWIND_TIME = 0.8; // s // They should be replaced with synced time from a real clock const double GPS_QUECTEL_SENSOR_TIME_OFFSET = 0.630; // s const double GPS_UBLOX_SENSOR_TIME_OFFSET = 0.095; // s -const float GPS_MUL_FACTOR = 10.0; const float GPS_POS_STD_THRESHOLD = 50.0; const float GPS_VEL_STD_THRESHOLD = 5.0; const float GPS_POS_ERROR_RESET_THRESHOLD = 300.0; @@ -326,8 +325,14 @@ 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; - MatrixXdr ecef_pos_R = Vector3d::Constant(std::pow(GPS_MUL_FACTOR * log.getAccuracy(),2) + std::pow(GPS_MUL_FACTOR * log.getVerticalAccuracy(),2)).asDiagonal(); - MatrixXdr ecef_vel_R = Vector3d::Constant(std::pow(GPS_MUL_FACTOR * log.getSpeedAccuracy(), 2)).asDiagonal(); + 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)); + } + 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(); this->unix_timestamp_millis = log.getUnixTimestampMillis(); double gps_est_error = (this->kf->get_x().segment(STATE_ECEF_POS_START) - ecef_pos).norm(); @@ -377,14 +382,14 @@ void Localizer::handle_gnss(double current_time, const cereal::GnssMeasurements: // indexed at 0 cause all std values are the same MAE auto ecef_pos_std = log.getPositionECEF().getStd()[0]; - MatrixXdr ecef_pos_R = Vector3d::Constant(pow(GPS_MUL_FACTOR*ecef_pos_std, 2)).asDiagonal(); + MatrixXdr ecef_pos_R = Vector3d::Constant(pow(this->gps_std_factor*ecef_pos_std, 2)).asDiagonal(); auto ecef_vel_v = log.getVelocityECEF().getValue(); VectorXd ecef_vel = Vector3d(ecef_vel_v[0], ecef_vel_v[1], ecef_vel_v[2]); // indexed at 0 cause all std values are the same MAE auto ecef_vel_std = log.getVelocityECEF().getStd()[0]; - MatrixXdr ecef_vel_R = Vector3d::Constant(pow(GPS_MUL_FACTOR*ecef_vel_std, 2)).asDiagonal(); + MatrixXdr ecef_vel_R = Vector3d::Constant(pow(this->gps_std_factor*ecef_vel_std, 2)).asDiagonal(); double gps_est_error = (this->kf->get_x().segment(STATE_ECEF_POS_START) - ecef_pos).norm(); @@ -661,8 +666,10 @@ int Localizer::locationd_thread() { const char* gps_location_socket; if (ublox_available) { gps_location_socket = "gpsLocationExternal"; + this->gps_std_factor = 10.0; } else { gps_location_socket = "gpsLocation"; + this->gps_std_factor = 2.0; } 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 b7e42a9df8..6366b84f8e 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -84,4 +84,5 @@ private: std::map observation_values_invalid; bool standstill = true; int32_t orientation_reset_count = 0; + float gps_std_factor; }; diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 57f71fc807..af63dab2f1 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -1da098f096cee9f2871dafd2788dc9ddac85eeab \ No newline at end of file +1bb3f665191e1b75c1b786f60e76d51b274f98ae From e377305ea84dc6e50367f500897f553376583728 Mon Sep 17 00:00:00 2001 From: royjr Date: Wed, 29 Mar 2023 22:04:33 -0400 Subject: [PATCH 120/143] Honda Civic 2022: match stock Auto Idle Stop behavior (#27722) * honda_idlestop_timer * whoops * simplify * just use stopping counter and move bosch radarless specific logic into the function * it's actually 4 seconds * Update selfdrive/car/honda/hondacan.py * check equal to 0 --------- Co-authored-by: Shane Smiskol --- selfdrive/car/honda/carcontroller.py | 4 +++- selfdrive/car/honda/hondacan.py | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index f6d328131b..347c16c86f 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -116,6 +116,7 @@ class CarController: self.brake_last = 0. self.apply_brake_last = 0 self.last_pump_ts = 0. + self.stopping_counter = 0 self.accel = 0.0 self.speed = 0.0 @@ -217,8 +218,9 @@ class CarController: self.gas = interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V) stopping = actuators.longControlState == LongCtrlState.stopping + self.stopping_counter = self.stopping_counter + 1 if stopping else 0 can_sends.extend(hondacan.create_acc_commands(self.packer, CC.enabled, CC.longActive, self.accel, self.gas, - stopping, self.CP.carFingerprint)) + self.stopping_counter, self.CP.carFingerprint)) else: apply_brake = clip(self.brake_last - wind_brake, 0.0, 1.0) apply_brake = int(clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1)) diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py index b7c448d1d3..1fe0a13767 100644 --- a/selfdrive/car/honda/hondacan.py +++ b/selfdrive/car/honda/hondacan.py @@ -51,7 +51,7 @@ def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_ return packer.make_can_msg("BRAKE_COMMAND", bus, values) -def create_acc_commands(packer, enabled, active, accel, gas, stopping, car_fingerprint): +def create_acc_commands(packer, enabled, active, accel, gas, stopping_counter, car_fingerprint): commands = [] bus = get_pt_bus(car_fingerprint) min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0] @@ -60,8 +60,8 @@ def create_acc_commands(packer, enabled, active, accel, gas, stopping, car_finge gas_command = gas if active and accel > min_gas_accel else -30000 accel_command = accel if active else 0 braking = 1 if active and accel < min_gas_accel else 0 - standstill = 1 if active and stopping else 0 - standstill_release = 1 if active and not stopping else 0 + standstill = 1 if active and stopping_counter > 0 else 0 + standstill_release = 1 if active and stopping_counter == 0 else 0 # common ACC_CONTROL values acc_control_values = { @@ -72,7 +72,7 @@ def create_acc_commands(packer, enabled, active, accel, gas, stopping, car_finge if car_fingerprint in HONDA_BOSCH_RADARLESS: acc_control_values.update({ "CONTROL_ON": enabled, - "IDLESTOP_ALLOW": 0, # disallows idle stop + "IDLESTOP_ALLOW": stopping_counter > 200, # allow idle stop after 4 seconds (50 Hz) }) else: acc_control_values.update({ From a9d342689cef1a6e21e12a529bcf0ad8cf2dec8e Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Wed, 29 Mar 2023 21:06:44 -0500 Subject: [PATCH 121/143] Add missing AVALON_TSS2 engine & ABS f/w (#27733) `@jundi#8597` 2022 Avalon ICE DongleID/route 6b650cedd7de2808|2023-03-29--18-36-56 --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 38fb8dfbd1..f0e846cc54 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -327,6 +327,7 @@ FW_VERSIONS = { CAR.AVALON_TSS2: { (Ecu.abs, 0x7b0, None): [ b'\x01F152607240\x00\x00\x00\x00\x00\x00', + b'\x01F152607250\x00\x00\x00\x00\x00\x00', b'\x01F152607280\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ @@ -334,6 +335,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x700, None): [ b'\x01896630742000\x00\x00\x00\x00', + b'\x01896630743000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F6201200\x00\x00\x00\x00', From fe49fbf8ec56733c0cbab45cde31df916f7a9fd3 Mon Sep 17 00:00:00 2001 From: royjr Date: Thu, 30 Mar 2023 15:18:32 -0400 Subject: [PATCH 122/143] Honda Bosch Radarless: update stopAccel to match actuation limits (#27740) * civic22_stop_faster * limit stopAccel to current safety model * Update selfdrive/car/honda/interface.py * Update selfdrive/car/honda/interface.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/honda/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 7314afd50a..51ddf1ac92 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -74,7 +74,7 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kiV = [0.05] ret.longitudinalActuatorDelayUpperBound = 0.5 # s if candidate in HONDA_BOSCH_RADARLESS: - ret.stopAccel = -4.0 + ret.stopAccel = -3.5 # stock uses -4.0 m/s^2 once stopped but limited by safety model else: # default longitudinal tuning for all hondas ret.longitudinalTuning.kpBP = [0., 5., 35.] From 51c3f43205048948d49d1c969c71ebb46c3fc53e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 30 Mar 2023 12:19:48 -0700 Subject: [PATCH 123/143] Honda Bosch Radarless: use CarControllerParams variable --- selfdrive/car/honda/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 51ddf1ac92..3a40f03dd9 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -74,7 +74,7 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kiV = [0.05] ret.longitudinalActuatorDelayUpperBound = 0.5 # s if candidate in HONDA_BOSCH_RADARLESS: - ret.stopAccel = -3.5 # stock uses -4.0 m/s^2 once stopped but limited by safety model + ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model else: # default longitudinal tuning for all hondas ret.longitudinalTuning.kpBP = [0., 5., 35.] From f3664b658b0b375cb95d6511d345d5869ae64a24 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 31 Mar 2023 03:24:41 +0800 Subject: [PATCH 124/143] add libncurses5 to ubuntu_setup.sh (#27751) --- tools/ubuntu_setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 71bad2e8a2..97b706de5b 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -53,6 +53,8 @@ function install_ubuntu_common_requirements() { libgles2-mesa-dev \ libglfw3-dev \ libglib2.0-0 \ + libncurses5-dev \ + libncursesw5-dev \ libomp-dev \ libopencv-dev \ libpng16-16 \ From cf299002f73d121ed2e7afb69f9ff68567ac62cd Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 30 Mar 2023 21:36:34 +0200 Subject: [PATCH 125/143] cabana: allow zooming to smaller ranges (#27748) * cabana: allow zooming to smaller ranges * remove comment --- tools/cabana/chartswidget.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 24415c6f95..148e075414 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -713,8 +713,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { if (rubber->width() <= 0) { // no rubber dragged, seek to mouse position can->seekTo(min); - } else if ((max_rounded - min_rounded) >= 0.5) { - // zoom in if selected range is greater than 0.5s + } else if (rubber->width() > 10) { emit zoomIn(min_rounded, max_rounded); } else { update(); From 469accbec105e376b88d75a387bb244f0cfd11eb Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 30 Mar 2023 21:36:54 +0200 Subject: [PATCH 126/143] cabana: show string value for val/desc (#27747) --- tools/cabana/signalview.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 3f8a38825a..020e2ec285 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -62,10 +62,21 @@ void SignalModel::updateState(const QHash *msgs) { auto &dat = can->lastMessage(msg_id).dat; int row = 0; for (auto item : root->children) { - item->sig_val = QString::number(get_raw_value((uint8_t *)dat.constData(), dat.size(), *item->sig), 'f', item->sig->precision); + double value = get_raw_value((uint8_t *)dat.constData(), dat.size(), *item->sig); + item->sig_val = QString::number(value, 'f', item->sig->precision); + + // Show unit if (!item->sig->unit.isEmpty()) { item->sig_val += " " + item->sig->unit; } + + // Show enum string + for (auto &[val, desc] : item->sig->val_desc) { + if (std::abs(value - val.toInt()) < 1e-6) { + item->sig_val = desc; + } + } + emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); ++row; } From ecd82f04087eb58df7de9b503133aae1d8de15d5 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 30 Mar 2023 21:37:29 +0200 Subject: [PATCH 127/143] cabana: fix drawing sparkline at half width on hi-dpi screen (#27746) --- tools/cabana/signalview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 020e2ec285..e3c19faa13 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -400,7 +400,7 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionView int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); int v_margin = std::max(option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 2, 4); - const double xscale = (option.rect.width() - 175.0 * option.widget->devicePixelRatioF() - h_margin * 2) / settings.sparkline_range; + const double xscale = (option.rect.width() - 175.0 - h_margin * 2) / settings.sparkline_range; const double yscale = (option.rect.height() - v_margin * 2) / (max - min); const int left = option.rect.left(); const int top = option.rect.top() + v_margin; From bec8cb1e30c91b150008ef600b42abaf48e1641a Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 30 Mar 2023 21:37:49 +0200 Subject: [PATCH 128/143] cabana: fix parts of chart widget not being redrawn (#27742) * cabana: fix parts of chart widget not being redrawn * revert others --- tools/cabana/chartswidget.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 148e075414..09ee9f1cff 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -528,7 +528,7 @@ void ChartView::updatePlot(double cur, double min, double max) { updateAxisY(); updateSeriesPoints(); } - update(); + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } void ChartView::updateSeriesPoints() { @@ -716,7 +716,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } else if (rubber->width() > 10) { emit zoomIn(min_rounded, max_rounded); } else { - update(); + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } event->accept(); } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { @@ -774,7 +774,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); QPointF tooltip_pt(x + 12, plot_area.top() - 20); QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), text_list.join("
"), this, plot_area.toRect()); - update(); + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } else { QToolTip::hideText(); } @@ -787,7 +787,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (rubber_rect != rubber->geometry()) { rubber->setGeometry(rubber_rect); } - update(); + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } } From 5ec7da96a60fd7712a9f7c8c5e53e0104204becc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 30 Mar 2023 12:43:00 -0700 Subject: [PATCH 129/143] ci: always upload process replay ref logs --- .github/workflows/selfdrive_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 5873e7aee6..0f782107ec 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -261,7 +261,7 @@ jobs: name: process_replay_diff.txt path: selfdrive/test/process_replay/diff.txt - name: Upload reference logs - if: ${{ failure() && steps.print-diff.outcome == 'success' && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} + if: ${{ failure() && steps.print-diff.outcome == 'success' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} run: | ${{ env.RUN }} "CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" - name: "Upload coverage to Codecov" From dd4e07fe7b67ef6db8095a7f654acdc8d6010be6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 31 Mar 2023 04:00:06 +0800 Subject: [PATCH 130/143] cabana: fill rows with Qt::BDiagPattern if messag size is incorrect (#27750) --- tools/cabana/binaryview.cc | 10 +++++++--- tools/cabana/binaryview.h | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 84225bb96c..d0576615c9 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -273,6 +273,10 @@ void BinaryViewModel::refresh() { row_count = can->lastMessage(msg_id).dat.size(); items.resize(row_count * column_count); } + int valid_rows = std::min(can->lastMessage(msg_id).dat.size(), row_count); + for (int i = 0; i < valid_rows * column_count; ++i) { + items[i].valid = true; + } endResetModel(); updateState(); } @@ -307,9 +311,6 @@ void BinaryViewModel::updateState() { items[i * column_count + 8].val = toHex(binary[i]); items[i * column_count + 8].bg_color = last_msg.colors[i]; } - for (int i = binary.size() * column_count; i < items.size(); ++i) { - items[i].val = "-"; - } for (int i = 0; i < items.size(); ++i) { if (i >= prev_items.size() || prev_items[i].val != items[i].val || prev_items[i].bg_color != items[i].bg_color) { @@ -376,6 +377,9 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } } + if (!item->valid) { + painter->fillRect(option.rect, QBrush(Qt::darkGray, Qt::BDiagPattern)); + } painter->drawText(option.rect, Qt::AlignCenter, item->val); if (item->is_msb || item->is_lsb) { painter->setFont(small_font); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 8598fe490b..aa1f8c656b 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -42,8 +42,9 @@ public: QColor bg_color = QColor(102, 86, 169, 0); bool is_msb = false; bool is_lsb = false; - QString val = "-"; + QString val; QList sigs; + bool valid = false; }; std::vector items; From c2d13e529219422b942cbedcc3a496e2c936dd9b Mon Sep 17 00:00:00 2001 From: royjr Date: Thu, 30 Mar 2023 17:27:05 -0400 Subject: [PATCH 131/143] ui: experimental -> alpha OP long toggle (#27725) * swap locations * remove experimental from toggle name * revert * alpha * revert that --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/qt/offroad/settings.cc | 8 ++++---- selfdrive/ui/translations/main_de.ts | 24 ++++++++++++------------ selfdrive/ui/translations/main_ja.ts | 24 ++++++++++++------------ selfdrive/ui/translations/main_ko.ts | 24 ++++++++++++------------ selfdrive/ui/translations/main_pt-BR.ts | 24 ++++++++++++------------ selfdrive/ui/translations/main_zh-CHS.ts | 24 ++++++++++++------------ selfdrive/ui/translations/main_zh-CHT.ts | 24 ++++++++++++------------ 7 files changed, 76 insertions(+), 76 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index c22484167c..fd14ed15e2 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -43,10 +43,10 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { }, { "ExperimentalLongitudinalEnabled", - tr("Experimental openpilot Longitudinal Control"), - QString("%1
%2") - .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB).")) - .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 using experimental openpilot longitudinal control.")), + tr("openpilot Longitudinal Control (Alpha)"), + QString("%1

%2") + .arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).")) + .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", }, { diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 5f3511d3cc..2e4e833e07 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -992,22 +992,10 @@ This may take up to a minute. Experimental Mode Experimenteller Modus - - Experimental openpilot Longitudinal Control - Experimenteller Openpilot Tempomat - - - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - WARNUNG: Der Openpilot Tempomat ist für dieses Auto experimentell und deaktiviert den Notbremsassistenten. - Disengage on Accelerator Pedal Bei Gasbetätigung ausschalten - - 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 using experimental openpilot longitudinal control. - Bei diesem auto wird standardmäßig der im Auto eingebaute adaptive Tempomat anstelle des Openpilot Tempomats benutzt. Aktiviere diesen Schalter, um zum Openpilot Tempomaten zu wechseln. Es ist empfohlen den Experimentellen Modus bei Nutzung des Openpilot Tempomats zu aktivieren. - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: Openpilot fährt standardmäßig im <b>entspannten Modus</b>. Der Experimentelle Modus aktiviert<b>Alpha-level Funktionen</b>, die noch nicht für den entspannten Modus bereit sind. Die experimentellen Funktionen sind die Folgenden: @@ -1044,6 +1032,18 @@ This may take up to a minute. Enable experimental longitudinal control to allow Experimental mode. Aktiviere den experimentellen Openpilot Tempomaten für experimentelle Funktionen. + + openpilot Longitudinal Control (Alpha) + + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (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. + + Updater diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 1e0223606b..06435d3b41 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -962,10 +962,6 @@ This may take up to a minute. Upload data from the driver facing camera and help improve the driver monitoring algorithm. 車内カメラの映像をアップロードし、ドライバー監視システムのアルゴリズムの向上に役立てます。 - - Experimental openpilot Longitudinal Control - 実験段階のopenpilotによるアクセル制御 - Disengage on Accelerator Pedal アクセルを踏むと openpilot を中断 @@ -994,14 +990,6 @@ This may take up to a minute. Experimental Mode 実験モード - - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - 警告: この車種でのopenpilotによるアクセル制御は実験段階であり、衝突被害軽減ブレーキ(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 using experimental openpilot longitudinal control. - openpilotはこの車の場合、車に内蔵されているACCを標準で利用します。この機能を有効にすることで実験段階のopenpilotによるアクセル制御を利用できます。実験モードと合わせて利用することをお勧めします。 - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。 @@ -1038,6 +1026,18 @@ This may take up to a minute. Enable experimental longitudinal control to allow Experimental mode. 実験段階のopenpilotによるアクセル制御を有効にしてください。 + + openpilot Longitudinal Control (Alpha) + + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (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. + + Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index be11f2efde..675798e377 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -963,10 +963,6 @@ This may take up to a minute. Upload data from the driver facing camera and help improve the driver monitoring algorithm. 운전자 카메라에서 데이터를 업로드하고 운전자 모니터링 알고리즘을 개선합니다. - - Experimental openpilot Longitudinal Control - openpilot 롱컨트롤 (실험적) - Disengage on Accelerator Pedal 가속페달 조작시 해제 @@ -995,14 +991,6 @@ This may take up to a minute. Experimental Mode 실험적 모드 - - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - 경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 자동긴급제동(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 using experimental openpilot longitudinal control. - 이 차량은 openpilot 롱컨트롤 대신 차량의 내장 ACC로 기본 설정됩니다. openpilot 롱컨트롤을 사용하려면 이 옵션을 활성화하세요. 실험적 openpilot 롱컨트롤을 사용하는 경우 실험적 모드를 활성화 하세요. - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험적 모드의 특징은 아래에 나열되어 있습니다 @@ -1039,6 +1027,18 @@ This may take up to a minute. Enable experimental longitudinal control to allow Experimental mode. 실험적 롱컨트롤을 사용하려면 실험적 모드를 활성화 하세요. + + openpilot Longitudinal Control (Alpha) + + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (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. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 8dc3a9830d..f1caaa9068 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -967,10 +967,6 @@ Isso pode levar até um minuto. Upload data from the driver facing camera and help improve the driver monitoring algorithm. Upload dados da câmera voltada para o motorista e ajude a melhorar o algoritmo de monitoramentor. - - Experimental openpilot Longitudinal Control - Controle longitudinal experimental openpilot - Disengage on Accelerator Pedal Desacionar com Pedal do Acelerador @@ -999,14 +995,6 @@ Isso pode levar até um minuto. Experimental Mode Modo Experimental - - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - ATENÇÃO: o controle longitudinal do openpilot é experimental para este carro e desativará a Frenagem Automática de Emergência (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 using experimental openpilot longitudinal control. - Neste carro o penpilot por padrão utiliza o ACC nativo do veículo ao invés de controlar longitudinalmente. Ative isto para mudar para o controle longitudinal do openpilot. Ativar o Modo Experimental é recomendado quando em uso do controle longitudinal experimental do openpilot. - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: @@ -1043,6 +1031,18 @@ Isso pode levar até um minuto. Enable experimental longitudinal control to allow Experimental mode. Ative o controle longitudinal experimental para permitir o modo Experimental. + + openpilot Longitudinal Control (Alpha) + + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index cfc055ac98..7cacc72f1c 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -960,10 +960,6 @@ This may take up to a minute. Upload data from the driver facing camera and help improve the driver monitoring algorithm. 上传驾驶员摄像头的数据,帮助改进驾驶员监控算法。 - - Experimental openpilot Longitudinal Control - 试验性的openpilot纵向控制 - Disengage on Accelerator Pedal 踩油门时取消控制 @@ -992,14 +988,6 @@ This may take up to a minute. Experimental Mode 测试模式 - - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - 警告: 此车辆的openpilot纵向控制是试验性功能,且将禁用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 using experimental openpilot longitudinal control. - 针对此车辆,openpilot默认使用车辆自带的ACC,而非openpilot的纵向控制。启用此选项将切换到openpilot纵向控制。当使用试验性的openpilot纵向控制时,建议同时启用试验模式。 - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: openpilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: @@ -1036,6 +1024,18 @@ This may take up to a minute. Enable experimental longitudinal control to allow Experimental mode. 启用试验性的纵向控制,以便允许使用试验模式。 + + openpilot Longitudinal Control (Alpha) + + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 83db0b7301..e559ca88a6 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -962,10 +962,6 @@ This may take up to a minute. Upload data from the driver facing camera and help improve the driver monitoring algorithm. 上傳駕駛監控的錄像來協助我們提升駕駛監控的準確率。 - - Experimental openpilot Longitudinal Control - 使用 openpilot 縱向控制(實驗) - Disengage on Accelerator Pedal 油門取消控車 @@ -994,14 +990,6 @@ This may take up to a minute. Experimental Mode 實驗模式 - - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - 警告:openpilot 縱向控制在這輛車上仍屬實驗性質,啟用後會喪失自動緊急煞車 (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 using experimental openpilot longitudinal control. - 在本車輛中,openpilot預設將使用原車內建的ACC系統,而非openpilot縱向控制。開啟此開關來啟用openpilot縱向控制,使用此選項時建議一併啟用實驗模式。 - openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: openpilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: @@ -1038,6 +1026,18 @@ This may take up to a minute. Enable experimental longitudinal control to allow Experimental mode. 啟用實驗性縱向控制以使用實驗模式。 + + openpilot Longitudinal Control (Alpha) + + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (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. + + Updater From 2c13bfac7498adb17d526c5472228f4bf4b09780 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Fri, 31 Mar 2023 09:34:39 +0900 Subject: [PATCH 132/143] Multilang: kor translation update (#27756) --- selfdrive/ui/translations/main_ko.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 675798e377..b55a56a061 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1029,15 +1029,15 @@ This may take up to a minute. openpilot Longitudinal Control (Alpha) - + openpilot 롱컨트롤 (알파) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - + 경고: openpilot 롱컨트롤은 알파 기능으로 차량의 자동긴급제동(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 롱컨트롤 알파를 활성화하는경우 실험적 모드 활성화를 권장합니다. From 08be9eed0820ecedcec63a92f32bc5b1077713a2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 30 Mar 2023 19:36:03 -0700 Subject: [PATCH 133/143] sensord: remove hardcoded irq from test (#27759) * sensord: remove hardcoded irq from test * fix linter --------- Co-authored-by: Comma Device --- system/sensord/tests/test_sensord.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/system/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py index c6fe33129a..21b67271d6 100755 --- a/system/sensord/tests/test_sensord.py +++ b/system/sensord/tests/test_sensord.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import glob import time import unittest import numpy as np @@ -7,7 +8,7 @@ from collections import namedtuple, defaultdict import cereal.messaging as messaging from cereal import log -from system.hardware import TICI, HARDWARE +from system.hardware import TICI from selfdrive.manager.process_config import managed_processes BMX = { @@ -70,7 +71,6 @@ ALL_SENSORS = { } } -LSM_IRQ = 336 def get_irq_count(irq: int): with open(f"/sys/kernel/irq/{irq}/per_cpu_count") as f: @@ -101,9 +101,6 @@ class TestSensord(unittest.TestCase): if not TICI: raise unittest.SkipTest - # make sure gpiochip0 is readable - HARDWARE.initialize_hardware() - # enable LSM self test os.environ["LSM_SELF_TEST"] = "1" @@ -114,6 +111,15 @@ class TestSensord(unittest.TestCase): time.sleep(3) cls.sample_secs = 10 cls.events = read_sensor_events(cls.sample_secs) + + # determine sensord's irq + cls.sensord_irq = None + for fn in glob.glob('/sys/kernel/irq/*/actions'): + with open(fn) as f: + if "sensord" in f.read(): + cls.sensord_irq = int(fn.split('/')[-2]) + break + assert cls.sensord_irq is not None finally: # teardown won't run if this doesn't succeed managed_processes["sensord"].stop() @@ -121,8 +127,6 @@ class TestSensord(unittest.TestCase): @classmethod def tearDownClass(cls): managed_processes["sensord"].stop() - if "LSM_SELF_TEST" in os.environ: - del os.environ['LSM_SELF_TEST'] def tearDown(self): managed_processes["sensord"].stop() @@ -250,9 +254,9 @@ class TestSensord(unittest.TestCase): time.sleep(3) # read /proc/interrupts to verify interrupts are received - state_one = get_irq_count(LSM_IRQ) + state_one = get_irq_count(self.sensord_irq) time.sleep(1) - state_two = get_irq_count(LSM_IRQ) + state_two = get_irq_count(self.sensord_irq) error_msg = f"no interrupts received after sensord start!\n{state_one} {state_two}" assert state_one != state_two, error_msg @@ -261,9 +265,9 @@ class TestSensord(unittest.TestCase): time.sleep(1) # read /proc/interrupts to verify no more interrupts are received - state_one = get_irq_count(LSM_IRQ) + state_one = get_irq_count(self.sensord_irq) time.sleep(1) - state_two = get_irq_count(LSM_IRQ) + state_two = get_irq_count(self.sensord_irq) assert state_one == state_two, "Interrupts received after sensord stop!" From 909ad5e285cdd8dfe68f76e0ae67eda20fcf782d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 31 Mar 2023 00:10:41 -0700 Subject: [PATCH 134/143] bump panda (#27761) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 12b9b65985..7933635b54 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 12b9b65985edf7207a1dfd48de0b714192e6e55d +Subproject commit 7933635b54b68eda3f8a906d5e2c3ca30dbed279 From 652fc0e90419d505bec80bac12617676a3591854 Mon Sep 17 00:00:00 2001 From: routine88 Date: Thu, 30 Mar 2023 21:34:35 -1000 Subject: [PATCH 135/143] Added fingerprint for 2023 Hyundai Elantra Hybrid (#27758) * Update values.py * Update values.py * Update selfdrive/car/hyundai/values.py * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index dcc3a0fc0f..7fcc5b9140 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1485,25 +1485,29 @@ FW_VERSIONS = { b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.05 99210-AA000 210930', b'\xf1\000CN7HMFC AT USA LHD 1.00 1.03 99210-AA000 200819', b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.07 99210-AA000 220426', + b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.08 99210-AA000 220728', ], (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\000CNhe SCC FHCUP 1.00 1.01 99110-BY000 ', + b'\xf1\x00CNhe SCC FHCUP 1.00 1.01 99110-BY000 ', b'\xf1\x8799110BY000\xf1\x00CNhe SCC FHCUP 1.00 1.01 99110-BY000 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00CN7 MDPS C 1.00 1.03 56310BY0500 4CNHC103', b'\xf1\x8756310/BY050\xf1\x00CN7 MDPS C 1.00 1.03 56310/BY050 4CNHC103', b'\xf1\x8756310/BY050\xf1\000CN7 MDPS C 1.00 1.02 56310/BY050 4CNHC102', + b'\xf1\x00CN7 MDPS C 1.00 1.04 56310BY050\x00 4CNHC104', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\0006U3L0_C2\000\0006U3K3051\000\000HCN0G16NS0\xb9?A\xaa', b'\xf1\0006U3L0_C2\000\0006U3K3051\000\000HCN0G16NS0\000\000\000\000', b'\xf1\x816U3K3051\000\000\xf1\0006U3L0_C2\000\0006U3K3051\000\000HCN0G16NS0\xb9?A\xaa', b'\xf1\x816U3K3051\x00\x00\xf1\x006U3L0_C2\x00\x006U3K3051\x00\x00HCN0G16NS0\x00\x00\x00\x00', + b'\xf1\x006U3L0_C2\x00\x006U3K9051\x00\x00HCN0G16NS1\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x816H6G8051\x00\x00\x00\x00\x00\x00\x00\x00', ] }, CAR.KONA_HEV: { From 852f67dc8818abe011aa7ad4f2e425fc1d9f81e8 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Fri, 31 Mar 2023 15:29:08 -0300 Subject: [PATCH 136/143] Multilang: update pt-BR translations (#27767) --- 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 f1caaa9068..34fbc8abf0 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1033,15 +1033,15 @@ Isso pode levar até um minuto. openpilot Longitudinal Control (Alpha) - + Controle Longitudinal openpilot (Alpha) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - + AVISO: o controle longitudinal openpilot está em alfa para este carro e desativará a Frenagem Automática de Emergência (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. - + 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. From ced90c163ed292f41a450810035ae32438fe81fc Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 31 Mar 2023 20:32:27 +0200 Subject: [PATCH 137/143] cabana: show min and max values in chart tooltip (#27744) --- tools/cabana/chartswidget.cc | 20 +++++++++++++------- tools/cabana/chartswidget.h | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 09ee9f1cff..2c9a01b752 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -606,16 +606,20 @@ void ChartView::updateAxisY() { auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), xLessThan); + s.min = std::numeric_limits::max(); + s.max = std::numeric_limits::lowest(); if (can->liveStreaming()) { for (auto it = first; it != last; ++it) { - if (it->y() < min) min = it->y(); - if (it->y() > max) max = it->y(); + if (it->y() < s.min) s.min = it->y(); + if (it->y() > s.max) s.max = it->y(); } } else { auto [min_y, max_y] = s.segment_tree.minmax(std::distance(s.vals.begin(), first), std::distance(s.vals.begin(), last)); - min = std::min(min, min_y); - max = std::max(max, max_y); + s.min = min_y; + s.max = max_y; } + min = std::min(min, s.min); + max = std::max(max, s.max); } if (min == std::numeric_limits::max()) min = 0; if (max == std::numeric_limits::lowest()) max = 0; @@ -764,16 +768,18 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { s.track_pt = chart()->mapToPosition(*it); x = std::max(x, s.track_pt.x()); } - text_list.push_back(QString("%2: %3") + text_list.push_back(QString("%2: %3 (%4 - %5)") .arg(s.series->color().name(), s.sig->name, - s.track_pt.isNull() ? "--" : QString::number(value))); + s.track_pt.isNull() ? "--" : QString::number(value), + QString::number(s.min), QString::number(s.max))); + } if (x < 0) { x = ev->pos().x(); } text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); QPointF tooltip_pt(x + 12, plot_area.top() - 20); - QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), text_list.join("
"), this, plot_area.toRect()); + QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), "

" + text_list.join("
"), this, plot_area.toRect()); scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } else { QToolTip::hideText(); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 7f757f0211..592e063163 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -46,6 +46,8 @@ public: uint64_t last_value_mono_time = 0; QPointF track_pt{}; SegmentTree segment_tree; + double min = 0; + double max = 0; }; signals: From 63f888fa3a31dcf06ff2a2f098e2930c45050ea6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 1 Apr 2023 02:44:21 +0800 Subject: [PATCH 138/143] cabana: fix sparkline overlapping issue (#27766) * fix sparkline overlapping issue * cleanup --- tools/cabana/detailwidget.cc | 1 - tools/cabana/detailwidget.h | 1 - tools/cabana/signalview.cc | 48 +++++++++++++++++++++++++----------- tools/cabana/signalview.h | 3 ++- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index ab723fa0e2..543946b19a 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -48,7 +48,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart // msg widget splitter = new QSplitter(Qt::Vertical, this); - splitter->setAutoFillBackground(true); splitter->addWidget(binary_view = new BinaryView(this)); splitter->addWidget(signal_view = new SignalView(charts, this)); binary_view->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 2794d41b99..b7cfed376c 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -30,7 +30,6 @@ public: DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const MessageId &message_id); void refresh(); - QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } private: void showTabBarContextMenu(const QPoint &pt); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index e3c19faa13..4eb1456b1e 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -168,6 +168,8 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { if (item->type == Item::Signed) return item->sig->is_signed ? Qt::Checked : Qt::Unchecked; } else if (role == Qt::DecorationRole && index.column() == 0 && item->type == Item::ExtraInfo) { return 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 {}; @@ -323,11 +325,25 @@ QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo int spacing = option.widget->style()->pixelMetric(QStyle::PM_TreeViewIndentation) + color_label_width + 8; it = width_cache.insert(text, option.fontMetrics.width(text) + spacing); } - width = std::min(width, it.value()); + width = std::min(option.widget->size().width() / 3.0, it.value()); } 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::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); @@ -363,25 +379,30 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->fillRect(option.rect, option.palette.highlight()); } - drawSparkline(painter, option, index); + int adjust_right = ((SignalView *)parent())->tree->indexWidget(index)->sizeHint().width() + 2 * h_margin; + QRect r = option.rect.adjusted(h_margin, v_margin, -adjust_right, -v_margin); // draw signal value - int right_offset = ((SignalView *)parent())->tree->indexWidget(index)->sizeHint().width() + 2 * h_margin; - QRect rc = option.rect.adjusted(0, 0, -right_offset, 0); - auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); + QRect value_rect = r.adjusted(r.width() * 0.6 + h_margin, 0, 0, 0); + auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, value_rect.width()); painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); - painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); + painter->drawText(value_rect, Qt::AlignRight | Qt::AlignVCenter, text); + + QRect sparkline_rect = r.adjusted(0, 0, -r.width() * 0.4 - h_margin, 0); + drawSparkline(painter, sparkline_rect, index); } else { QStyledItemDelegate::paint(painter, option, index); } } -void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { +void SignalItemDelegate::drawSparkline(QPainter *painter, const QRect &rect, const QModelIndex &index) const { static std::vector points; const auto &msg_id = ((SignalView *)parent())->msg_id; const auto &msgs = can->events().at(msg_id); + uint64_t ts = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9; auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = (uint64_t)std::max(ts - settings.sparkline_range * 1e9, 0)}); auto last = std::upper_bound(first, msgs.cend(), CanEvent{.mono_time = ts}); + if (first != last) { double min = std::numeric_limits::max(); double max = std::numeric_limits::lowest(); @@ -398,16 +419,13 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionView max += 1; } - int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); - int v_margin = std::max(option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 2, 4); - const double xscale = (option.rect.width() - 175.0 - h_margin * 2) / settings.sparkline_range; - const double yscale = (option.rect.height() - v_margin * 2) / (max - min); - const int left = option.rect.left(); - const int top = option.rect.top() + v_margin; + const double xscale = rect.width() / (double)settings.sparkline_range; + const double yscale = rect.height() / (max - min); for (auto &pt : points) { - pt.rx() = left + pt.x() * xscale; - pt.ry() = top + std::abs(pt.y() - max) * yscale; + pt.rx() = rect.left() + pt.x() * xscale; + pt.ry() = rect.top() + std::abs(pt.y() - max) * yscale; } + painter->setPen(getColor(sig)); painter->drawPolyline(points.data(), points.size()); if ((points.back().x() - points.front().x()) / points.size() > 10) { diff --git a/tools/cabana/signalview.h b/tools/cabana/signalview.h index 50ba4e06b8..8bc9477888 100644 --- a/tools/cabana/signalview.h +++ b/tools/cabana/signalview.h @@ -83,7 +83,8 @@ 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; - void drawSparkline(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override; + void drawSparkline(QPainter *painter, const QRect &rect, const QModelIndex &index) const; QValidator *name_validator, *double_validator; QFont small_font; const int color_label_width = 18; From a1d01220e787b160f2be153e02c172c938a491e5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 31 Mar 2023 12:15:59 -0700 Subject: [PATCH 139/143] bump panda (#27768) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 7933635b54..09fee3e7ea 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 7933635b54b68eda3f8a906d5e2c3ca30dbed279 +Subproject commit 09fee3e7ead96a6a9613430c81bb2d3e095aa0fe From 15a4b60ee6e78d16646db1535c5840cc4fd56932 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 1 Apr 2023 03:48:31 +0800 Subject: [PATCH 140/143] cabana: display signal value in all charts on mouse hover (#27749) * display all values * cleanup * cleanup * emit hoverd if tip is visible --- tools/cabana/chartswidget.cc | 119 +++++++++++++++++++++++++---------- tools/cabana/chartswidget.h | 12 ++++ 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 2c9a01b752..4ae83c05d7 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -157,6 +158,12 @@ void ChartsWidget::zoomUndo() { } } +void ChartsWidget::showValueTip(double sec) { + for (auto c : charts) { + sec >= 0 ? c->showTip(sec) : c->hideTip(); + } +} + void ChartsWidget::updateState() { if (charts.isEmpty()) return; @@ -226,6 +233,7 @@ ChartView *ChartsWidget::createChart() { QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start)); + QObject::connect(chart, &ChartView::hovered, this, &ChartsWidget::showValueTip); charts.push_back(chart); updateLayout(); return chart; @@ -346,7 +354,7 @@ bool ChartsWidget::event(QEvent *event) { // ChartView -ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { +ChartView::ChartView(QWidget *parent) : tip_label(this), QChartView(nullptr, parent) { series_type = (SeriesType)settings.chart_series_type; QChart *chart = new QChart(); chart->setBackgroundVisible(false); @@ -542,7 +550,11 @@ void ChartView::updateSeriesPoints() { double pixels_per_point = (chart()->mapToPosition(right_pt).x() - chart()->mapToPosition(*begin).x()) / num_points; if (series_type == SeriesType::Scatter) { - ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 2.0, 2.0, 8.0) * devicePixelRatioF()); + qreal size = std::clamp(pixels_per_point / 2.0, 2.0, 8.0); + if (s.series->useOpenGL()) { + size *= devicePixelRatioF(); + } + ((QScatterSeries *)s.series)->setMarkerSize(size); } else { s.series->setPointsVisible(pixels_per_point > 20); } @@ -672,8 +684,9 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) { } void ChartView::leaveEvent(QEvent *event) { - clearTrackPoints(); - scene()->update(); + if (tip_label.isVisible()) { + emit hovered(-1); + } QChartView::leaveEvent(event); } @@ -745,44 +758,17 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (plot_area.contains(ev->pos())) { can->seekTo(std::clamp(chart()->mapToValue(ev->pos()).x(), 0., can->totalSeconds())); } - return; } auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); - is_scrubbing = false; clearTrackPoints(); if (!is_zooming && plot_area.contains(ev->pos())) { - QStringList text_list; const double sec = chart()->mapToValue(ev->pos()).x(); - qreal x = -1; - for (auto &s : sigs) { - if (!s.series->isVisible()) continue; - - // use reverse iterator to find last item <= sec. - double value = 0; - auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); - if (it != s.vals.rend() && it->x() >= axis_x->min()) { - value = it->y(); - s.track_pt = chart()->mapToPosition(*it); - x = std::max(x, s.track_pt.x()); - } - text_list.push_back(QString("%2: %3 (%4 - %5)") - .arg(s.series->color().name(), s.sig->name, - s.track_pt.isNull() ? "--" : QString::number(value), - QString::number(s.min), QString::number(s.max))); - - } - if (x < 0) { - x = ev->pos().x(); - } - text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); - QPointF tooltip_pt(x + 12, plot_area.top() - 20); - QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), "

" + text_list.join("
"), this, plot_area.toRect()); - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); - } else { - QToolTip::hideText(); + emit hovered(sec); + } else if (tip_label.isVisible()) { + emit hovered(-1); } QChartView::mouseMoveEvent(ev); @@ -797,6 +783,35 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { } } +void ChartView::showTip(double sec) { + qreal x = chart()->mapToPosition({sec, 0}).x(); + QStringList text_list(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); + for (auto &s : sigs) { + if (s.series->isVisible()) { + QString value = "--"; + // use reverse iterator to find last item <= sec. + auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); + if (it != s.vals.rend() && it->x() >= axis_x->min()) { + value = QString::number(it->y()); + s.track_pt = chart()->mapToPosition(*it); + x = std::max(x, s.track_pt.x()); + } + text_list << QString("%2: %3 (%4 - %5)") + .arg(s.series->color().name(), s.sig->name, value, QString::number(s.min), QString::number(s.max)); + } + } + QPointF tooltip_pt(x, chart()->plotArea().top()); + int plot_right = mapToGlobal(chart()->plotArea().topRight().toPoint()).x(); + tip_label.showText(mapToGlobal(tooltip_pt.toPoint()), "

" + text_list.join("
") + "

", plot_right); + scene()->update(); +} + +void ChartView::hideTip() { + clearTrackPoints(); + tip_label.hide(); + scene()->update(); +} + void ChartView::dragMoveEvent(QDragMoveEvent *event) { if (event->mimeData()->hasFormat(mime_type)) { event->setDropAction(event->source() == this ? Qt::MoveAction : Qt::CopyAction); @@ -1039,3 +1054,39 @@ QList SeriesSelector::seletedItems() { for (int i = 0; i < selected_list->count(); ++i) ret.push_back((ListItem *)selected_list->item(i)); return ret; } + +// ValueTipLabel + +ValueTipLabel::ValueTipLabel(QWidget *parent) : QLabel(parent, Qt::Tool | Qt::FramelessWindowHint) { + setForegroundRole(QPalette::ToolTipText); + setBackgroundRole(QPalette::ToolTipBase); + setPalette(QToolTip::palette()); + ensurePolished(); + setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, this)); + setAttribute(Qt::WA_ShowWithoutActivating); + setTextFormat(Qt::RichText); + setVisible(false); +} + +void ValueTipLabel::showText(const QPoint &pt, const QString &text, int right_edge) { + setText(text); + if (!text.isEmpty()) { + QSize extra(1, 1); + resize(sizeHint() + extra); + QPoint tip_pos(pt.x() + 12, pt.y()); + if (tip_pos.x() + size().width() >= right_edge) { + tip_pos.rx() = pt.x() - size().width() - 12; + } + move(tip_pos); + } + setVisible(!text.isEmpty()); +} + +void ValueTipLabel::paintEvent(QPaintEvent *ev) { + QStylePainter p(this); + QStyleOptionFrame opt; + opt.init(this); + p.drawPrimitive(QStyle::PE_PanelTipLabel, opt); + p.end(); + QLabel::paintEvent(ev); +} diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 592e063163..fad345ae34 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -25,6 +25,13 @@ enum class SeriesType { Scatter }; +class ValueTipLabel : public QLabel { +public: + ValueTipLabel(QWidget *parent = nullptr); + void showText(const QPoint &pt, const QString &sec, int right_edge); + void paintEvent(QPaintEvent *ev) override; +}; + class ChartView : public QChartView { Q_OBJECT @@ -36,6 +43,8 @@ public: void updatePlot(double cur, double min, double max); void setSeriesType(SeriesType type); void updatePlotArea(int left); + void showTip(double sec); + void hideTip(); struct SigItem { MessageId msg_id; @@ -57,6 +66,7 @@ signals: void zoomUndo(); void remove(); void axisYLabelWidthChanged(int w); + void hovered(double sec); private slots: void signalUpdated(const cabana::Signal *sig); @@ -94,6 +104,7 @@ private: QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; QGraphicsRectItem *background; + ValueTipLabel tip_label; QList sigs; double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; @@ -137,6 +148,7 @@ private: void setMaxChartRange(int value); void updateLayout(); void settingChanged(); + void showValueTip(double sec); bool eventFilter(QObject *obj, QEvent *event) override; ChartView *findChart(const MessageId &id, const cabana::Signal *sig); From aa3b8e5f300f992c69b4924a7c94994ce13db5c4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 1 Apr 2023 04:58:50 +0800 Subject: [PATCH 141/143] cabana: fixed chat tool tips was displayed outside of the viewport (#27770) --- tools/cabana/chartswidget.cc | 11 ++++++++--- tools/cabana/chartswidget.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 4ae83c05d7..845667bad7 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -71,13 +71,13 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent) charts_layout = new QGridLayout(); charts_layout->setSpacing(10); - QWidget *charts_container = new QWidget(this); + charts_container = new QWidget(this); QVBoxLayout *charts_main_layout = new QVBoxLayout(charts_container); charts_main_layout->setContentsMargins(0, 0, 0, 0); charts_main_layout->addLayout(charts_layout); charts_main_layout->addStretch(0); - QScrollArea *charts_scroll = new QScrollArea(this); + charts_scroll = new QScrollArea(this); charts_scroll->setFrameStyle(QFrame::NoFrame); charts_scroll->setWidgetResizable(true); charts_scroll->setWidget(charts_container); @@ -159,8 +159,13 @@ void ChartsWidget::zoomUndo() { } void ChartsWidget::showValueTip(double sec) { + const QRect visible_rect(-charts_container->pos(), charts_scroll->viewport()->size()); for (auto c : charts) { - sec >= 0 ? c->showTip(sec) : c->hideTip(); + if (sec >= 0 && visible_rect.contains(QRect(c->mapTo(charts_container, QPoint(0, 0)), c->size()))) { + c->showTip(sec); + } else { + c->hideTip(); + } } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index fad345ae34..98ceb02674 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -164,6 +164,8 @@ private: QAction *remove_all_btn; QGridLayout *charts_layout; QList charts; + QWidget *charts_container; + QScrollArea *charts_scroll; uint32_t max_chart_range = 0; bool is_zoomed = false; std::pair display_range; From e82d7a10d37cbcec54918a05f2233e20ee755ce2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 1 Apr 2023 04:59:08 +0800 Subject: [PATCH 142/143] cabana: show min and max values in sparkline on hover (#27769) --- tools/cabana/signalview.cc | 29 +++++++++++++++++++++++++++-- tools/cabana/signalview.h | 1 + 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 4eb1456b1e..4f841a2866 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -344,6 +344,17 @@ bool SignalItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, c 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) { + QRect geom = option.widget->style()->subElementRect(QStyle::SE_ItemViewItemText, &option); + geom.setLeft(geom.right() - editor->sizeHint().width()); + editor->setGeometry(geom); + return; + } + QStyledItemDelegate::updateEditorGeometry(editor, option, index); +} + void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); @@ -375,6 +386,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); } else if (index.column() == 1 && item && item->type == SignalModel::Item::Sig) { + painter->save(); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } @@ -389,6 +401,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QRect sparkline_rect = r.adjusted(0, 0, -r.width() * 0.4 - h_margin, 0); drawSparkline(painter, sparkline_rect, index); + painter->restore(); } else { QStyledItemDelegate::paint(painter, option, index); } @@ -406,7 +419,8 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QRect &rect, con if (first != last) { double min = std::numeric_limits::max(); double max = std::numeric_limits::lowest(); - const auto sig = ((SignalModel::Item *)index.internalPointer())->sig; + const auto item = (const SignalModel::Item *)index.internalPointer(); + const auto sig = item->sig; points.clear(); for (auto it = first; it != last; ++it) { double value = get_raw_value(it->dat, it->size, *sig); @@ -435,6 +449,17 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QRect &rect, con painter->drawEllipse(pt, 2, 2); } } + + if (item->highlight) { + QFont font; + font.setPixelSize(10); + painter->setFont(font); + painter->setPen(Qt::darkGray); + painter->drawLine(rect.topRight(), rect.bottomRight()); + QRect minmax_rect{rect.right() + 3, rect.top(), 1000, rect.height()}; + painter->drawText(minmax_rect, Qt::AlignLeft | Qt::AlignTop, QString::number(max)); + painter->drawText(minmax_rect, Qt::AlignLeft | Qt::AlignBottom, QString::number(min)); + } } } @@ -552,7 +577,6 @@ void SignalView::rowsChanged() { int h_margin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin); h->setContentsMargins(0, v_margin, -h_margin, v_margin); h->setSpacing(style()->pixelMetric(QStyle::PM_ToolBarItemSpacing)); - h->addStretch(0); auto remove_btn = toolButton("x", tr("Remove signal")); auto plot_btn = toolButton("graph-up", ""); @@ -612,6 +636,7 @@ void SignalView::signalHovered(const cabana::Signal *sig) { bool highlight = children[i]->sig == sig; if (std::exchange(children[i]->highlight, highlight) != highlight) { emit model->dataChanged(model->index(i, 0), model->index(i, 0), {Qt::DecorationRole}); + emit model->dataChanged(model->index(i, 1), model->index(i, 1), {Qt::DisplayRole}); } } } diff --git a/tools/cabana/signalview.h b/tools/cabana/signalview.h index 8bc9477888..711748937a 100644 --- a/tools/cabana/signalview.h +++ b/tools/cabana/signalview.h @@ -85,6 +85,7 @@ public: 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 drawSparkline(QPainter *painter, const QRect &rect, const QModelIndex &index) const; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QValidator *name_validator, *double_validator; QFont small_font; const int color_label_width = 18; From 1ee4f41d5a6c8643301e197063c7934eae952c11 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 31 Mar 2023 20:00:49 -0700 Subject: [PATCH 143/143] bump panda: iso-tp bugfixes (#27772) bumppanda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 09fee3e7ea..a12c0a7956 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 09fee3e7ead96a6a9613430c81bb2d3e095aa0fe +Subproject commit a12c0a795678373d946b644b43d9402b72e502a9