diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index ff947e5760..bca2ac4c66 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -8,7 +8,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ bzip2 \ ca-certificates \ capnproto \ - libcapnp-dev \ clang \ cmake \ cppcheck \ @@ -19,17 +18,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ iputils-ping \ libarchive-dev \ libbz2-dev \ + libcapnp-dev \ libcurl4-openssl-dev \ libeigen3-dev \ libffi-dev \ - libglew-dev \ libgles2-mesa-dev \ + libglew-dev \ libglib2.0-0 \ liblzma-dev \ libomp-dev \ libopencv-dev \ - libssl-dev \ libsqlite3-dev \ + libssl-dev \ libsystemd-dev \ libusb-1.0-0-dev \ libzmq3-dev \ @@ -38,6 +38,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ocl-icd-opencl-dev \ opencl-headers \ python-dev \ + qml-module-qtquick2 \ qt5-default \ qtmultimedia5-dev \ qtwebengine5-dev \ diff --git a/README.md b/README.md index bf106ddd98..01aa9576bd 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Supported Cars | Lexus | RX 2020-21 | All | openpilot | 0mph | 0mph | | Lexus | RX Hybrid 2016-19 | All | Stock3| 0mph | 0mph | | Lexus | RX Hybrid 2020 | All | openpilot | 0mph | 0mph | -| Toyota | Avalon 2016-18, 2020-21 | TSS-P | Stock3| 20mph1 | 0mph | +| Toyota | Avalon 2016-21 | TSS-P | Stock3| 20mph1 | 0mph | | Toyota | Camry 2018-20 | All | Stock | 0mph4 | 0mph | | Toyota | Camry 2021 | All | openpilot | 0mph | 0mph | | Toyota | Camry Hybrid 2018-20 | All | Stock | 0mph4 | 0mph | @@ -130,58 +130,63 @@ Supported Cars Community Maintained Cars and Features ------ -| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below | -| ----------| ------------------------------| --------------------| -----------------| -------------------| -------------| -| Audi | A3 2014, 2017 | Prestige / Adv.Tech | Stock | 0mph | 0mph | -| Audi | A3 Sportback e-tron 2017-18 | Prestige / Adv.Tech | Stock | 0mph | 0mph | -| Buick | Regal 20181 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Cadillac | ATS 20181 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Chevrolet | Malibu 20171 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Chevrolet | Volt 2017-181 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | -| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph | -| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | -| Chrysler | Pacifica Hybrid 2019-21 | Adaptive Cruise | Stock | 0mph | 39mph | -| Genesis | G70 2018 | All | Stock | 0mph | 0mph | -| Genesis | G80 2018 | All | Stock | 0mph | 0mph | -| Genesis | G90 2018 | All | Stock | 0mph | 0mph | -| GMC | Acadia 20181 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Holden | Astra 20171 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph | -| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph | -| Hyundai | Ioniq Electric 2019 | SCC + LKAS | Stock | 0mph | 32mph | -| Hyundai | Ioniq Electric 2020 | SCC + LKAS | Stock | 0mph | 0mph | -| Hyundai | Kona 2020 | SCC + LKAS | Stock | 0mph | 0mph | -| Hyundai | Kona EV 2019 | SCC + LKAS | Stock | 0mph | 0mph | -| Hyundai | Santa Fe 2019-20 | All | Stock | 0mph | 0mph | -| Hyundai | Sonata 2018-2019 | SCC + LKAS | Stock | 0mph | 0mph | -| Hyundai | Veloster 2019 | SCC + LKAS | Stock | 5mph | 0mph | -| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph | -| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph | -| Kia | Forte 2018-19, 2021 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Niro EV 2020 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Optima 2017 | SCC + LKAS | Stock | 0mph | 32mph | -| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Seltos 2021 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Sorento 2018 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Ceed 2019 | SCC + LKAS | Stock | 0mph | 0mph | -| Nissan | Altima 2020 | ProPILOT | Stock | 0mph | 0mph | -| Nissan | Leaf 2018-20 | ProPILOT | Stock | 0mph | 0mph | -| Nissan | Rogue 2018-19 | ProPILOT | Stock | 0mph | 0mph | -| Nissan | X-Trail 2017 | ProPILOT | Stock | 0mph | 0mph | -| SEAT | Ateca 2018 | Driver Assistance | Stock | 0mph | 0mph | -| Škoda | Kodiaq 2018 | Driver Assistance | Stock | 0mph | 0mph | -| Škoda | Scala 2020 | Driver Assistance | Stock | 0mph | 0mph | -| Škoda | Superb 2018 | Driver Assistance | Stock | 0mph | 0mph | -| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph | -| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph | -| Subaru | Forester 2019-20 | EyeSight | Stock | 0mph | 0mph | -| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph | -| Volkswagen| Jetta 2018-21 | Driver Assistance | Stock | 0mph | 0mph | -| Volkswagen| Passat 2016-172 | Driver Assistance | Stock | 0mph | 0mph | -| Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph | -| Volkswagen| Tiguan 2020 | Driver Assistance | Stock | 0mph | 0mph | +| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below | +| ----------| ------------------------------| ------------------| -----------------| -------------------| -------------| +| Audi | A3 2014, 2017 | Prestige | Stock | 0mph | 0mph | +| Audi | A3 Sportback e-tron 2017-18 | Prestige | Stock | 0mph | 0mph | +| Buick | Regal 20181 | Adaptive Cruise | openpilot | 0mph | 7mph | +| Cadillac | ATS 20181 | Adaptive Cruise | openpilot | 0mph | 7mph | +| Chevrolet | Malibu 20171 | Adaptive Cruise | openpilot | 0mph | 7mph | +| Chevrolet | Volt 2017-181 | Adaptive Cruise | openpilot | 0mph | 7mph | +| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | +| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph | +| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | +| Chrysler | Pacifica Hybrid 2019-21 | Adaptive Cruise | Stock | 0mph | 39mph | +| Genesis | G70 2018 | All | Stock | 0mph | 0mph | +| Genesis | G80 2018 | All | Stock | 0mph | 0mph | +| Genesis | G90 2018 | All | Stock | 0mph | 0mph | +| GMC | Acadia 20181 | Adaptive Cruise | openpilot | 0mph | 7mph | +| Holden | Astra 20171 | Adaptive Cruise | openpilot | 0mph | 7mph | +| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph | +| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph | +| Hyundai | Ioniq Electric 2019 | SCC + LKAS | Stock | 0mph | 32mph | +| Hyundai | Ioniq Electric 2020 | SCC + LKAS | Stock | 0mph | 0mph | +| Hyundai | Kona 2020 | SCC + LKAS | Stock | 0mph | 0mph | +| Hyundai | Kona EV 2019 | SCC + LKAS | Stock | 0mph | 0mph | +| Hyundai | Santa Fe 2019-20 | All | Stock | 0mph | 0mph | +| Hyundai | Sonata 2018-2019 | SCC + LKAS | Stock | 0mph | 0mph | +| Hyundai | Veloster 2019 | SCC + LKAS | Stock | 5mph | 0mph | +| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph | +| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph | +| Kia | Forte 2018-2021 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Niro EV 2020 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Optima 2017 | SCC + LKAS | Stock | 0mph | 32mph | +| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Seltos 2021 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Sorento 2018 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Ceed 2019 | SCC + LKAS | Stock | 0mph | 0mph | +| Nissan | Altima 2020 | ProPILOT | Stock | 0mph | 0mph | +| Nissan | Leaf 2018-20 | ProPILOT | Stock | 0mph | 0mph | +| Nissan | Rogue 2018-19 | ProPILOT | Stock | 0mph | 0mph | +| Nissan | X-Trail 2017 | ProPILOT | Stock | 0mph | 0mph | +| SEAT | Ateca 2018 | Driver Assistance | Stock | 0mph | 0mph | +| Škoda | Kodiaq 2018 | Driver Assistance | Stock | 0mph | 0mph | +| Škoda | Scala 2020 | Driver Assistance | Stock | 0mph | 0mph | +| Škoda | Superb 2018 | Driver Assistance | Stock | 0mph | 0mph | +| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph | +| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph | +| Subaru | Forester 2019-20 | EyeSight | Stock | 0mph | 0mph | +| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph | +| Volkswagen| e-Golf 2014, 2020 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Golf GTE 2016 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Golf GTI 2018-19 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Golf R 2016-19 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Golf SportsVan 2016 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Jetta 2018-21 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Passat 2016-172 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Tiguan 2020 | Driver Assistance | Stock | 0mph | 0mph | 1Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built ASCM harness](https://github.com/commaai/openpilot/wiki/GM#hardware). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).***
2Only includes the MQB Passat sold outside of North America. The NMS Passat made in Chattanooga TN is not yet supported. diff --git a/common/logging_extra.py b/common/logging_extra.py index a80a5a0821..9471b44191 100644 --- a/common/logging_extra.py +++ b/common/logging_extra.py @@ -158,6 +158,8 @@ class SwagLogger(logging.Logger): evt.update(kwargs) if 'error' in kwargs: self.error(evt) + if 'debug' in kwargs: + self.debug(evt) else: self.info(evt) diff --git a/common/params_pxd.pxd b/common/params_pxd.pxd index 9faa117cb3..14fcb311c3 100644 --- a/common/params_pxd.pxd +++ b/common/params_pxd.pxd @@ -12,5 +12,5 @@ cdef extern from "selfdrive/common/params.h": Params(bool) Params(string) string get(string, bool) nogil - int delete_db_value(string) - int write_db_value(string, string) + int remove(string) + int put(string, string) diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index 499e6ea6e7..92b35302ca 100755 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -36,6 +36,7 @@ keys = { b"GitCommit": [TxType.PERSISTENT], b"GitRemote": [TxType.PERSISTENT], b"GithubSshKeys": [TxType.PERSISTENT], + b"GithubUsername": [TxType.PERSISTENT], b"HardwareSerial": [TxType.PERSISTENT], b"HasAcceptedTerms": [TxType.PERSISTENT], b"HasCompletedSetup": [TxType.PERSISTENT], @@ -156,11 +157,11 @@ cdef class Params: if key not in keys: raise UnknownKeyName(key) - self.p.write_db_value(key, dat) + self.p.put(key, dat) def delete(self, key): key = ensure_bytes(key) - self.p.delete_db_value(key) + self.p.remove(key) def put_nonblocking(key, val, d=None): diff --git a/release/build_release2.sh b/release/build_release2.sh index f8555767fb..fe4936913f 100755 --- a/release/build_release2.sh +++ b/release/build_release2.sh @@ -42,7 +42,7 @@ git commit -m "openpilot v$VERSION" # Build signed panda firmware pushd panda/ -CERT=/tmp/pandaextra/certs/release RELEASE=1 scons +CERT=/tmp/pandaextra/certs/release RELEASE=1 scons -u . mv board/obj/panda.bin.signed /tmp/panda.bin.signed popd @@ -63,6 +63,7 @@ find . -name '*.pyc' -delete find . -name '__pycache__' -delete rm -rf panda/board panda/certs panda/crypto rm -rf .sconsign.dblite Jenkinsfile release/ +rm models/supercombo.dlc # Move back signed panda fw mkdir -p panda/board/obj diff --git a/release/files_common b/release/files_common index 8536da8758..bcaa1cc43b 100644 --- a/release/files_common +++ b/release/files_common @@ -348,6 +348,7 @@ selfdrive/ui/qt/*.cc selfdrive/ui/qt/*.hpp selfdrive/ui/qt/offroad/*.cc selfdrive/ui/qt/offroad/*.hpp +selfdrive/ui/qt/offroad/*.qml selfdrive/ui/qt/widgets/*.cc selfdrive/ui/qt/widgets/*.hpp selfdrive/ui/qt/spinner_aarch64 diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 9529fdeec9..5191e3224b 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -82,6 +82,8 @@ def jsonrpc_handler(end_event): send_queue.put_nowait(response.json) elif "result" in data and "id" in data: log_recv_queue.put_nowait(data) + else: + raise Exception("not a valid request or response") except queue.Empty: pass except Exception as e: diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index 2e9e79b651..102ca063db 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -180,10 +180,15 @@ class TestAthenadMethods(unittest.TestCase): thread.daemon = True thread.start() try: + # with params athenad.recv_queue.put_nowait(json.dumps({"method": "echo", "params": ["hello"], "jsonrpc": "2.0", "id": 0})) resp = athenad.send_queue.get(timeout=3) self.assertDictEqual(json.loads(resp), {'result': 'hello', 'id': 0, 'jsonrpc': '2.0'}) - + # without params + athenad.recv_queue.put_nowait(json.dumps({"method": "getNetworkType", "jsonrpc": "2.0", "id": 0})) + resp = athenad.send_queue.get(timeout=3) + self.assertDictEqual(json.loads(resp), {'result': 1, 'id': 0, 'jsonrpc': '2.0'}) + # log forwarding athenad.recv_queue.put_nowait(json.dumps({'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'})) resp = athenad.log_recv_queue.get(timeout=3) self.assertDictEqual(json.loads(resp), {'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'}) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index a93e05d243..abf87208f5 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -71,12 +71,11 @@ void safety_setter_thread() { return; }; - std::vector value_vin = Params().read_db_bytes("CarVin"); + std::string value_vin = Params().get("CarVin"); if (value_vin.size() > 0) { // sanity check VIN format assert(value_vin.size() == 17); - std::string str_vin(value_vin.begin(), value_vin.end()); - LOGW("got CarVin %s", str_vin.c_str()); + LOGW("got CarVin %s", value_vin.c_str()); break; } util::sleep_for(100); @@ -85,7 +84,7 @@ void safety_setter_thread() { // VIN query done, stop listening to OBDII panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); - std::vector params; + std::string params; LOGW("waiting for params to set safety model"); while (true) { if (do_exit || !panda->connected){ @@ -93,7 +92,7 @@ void safety_setter_thread() { return; }; - params = Params().read_db_bytes("CarParams"); + params = Params().get("CarParams"); if (params.size() > 0) break; util::sleep_for(100); } @@ -133,7 +132,7 @@ bool usb_connect() { } if (auto fw_sig = tmp_panda->get_firmware_version(); fw_sig) { - params.write_db_value("PandaFirmware", (const char *)fw_sig->data(), fw_sig->size()); + params.put("PandaFirmware", (const char *)fw_sig->data(), fw_sig->size()); // Convert to hex for offroad char fw_sig_hex_buf[16] = {0}; @@ -143,13 +142,13 @@ bool usb_connect() { fw_sig_hex_buf[2*i+1] = NIBBLE_TO_HEX((uint8_t)fw_sig_buf[i] & 0xF); } - params.write_db_value("PandaFirmwareHex", fw_sig_hex_buf, 16); + params.put("PandaFirmwareHex", fw_sig_hex_buf, 16); LOGW("fw signature: %.*s", 16, fw_sig_hex_buf); } else { return false; } // get panda serial if (auto serial = tmp_panda->get_serial(); serial) { - params.write_db_value("PandaDongleId", serial->c_str(), serial->length()); + params.put("PandaDongleId", serial->c_str(), serial->length()); LOGW("panda serial: %s", serial->c_str()); } else { return false; } @@ -161,13 +160,18 @@ bool usb_connect() { #endif if (tmp_panda->has_rtc){ + setenv("TZ","UTC",1); struct tm sys_time = get_time(); struct tm rtc_time = tmp_panda->get_rtc(); if (!time_valid(sys_time) && time_valid(rtc_time)) { - LOGE("System time wrong, setting from RTC"); + LOGE("System time wrong, setting from RTC. " + "System: %d-%02d-%02d %02d:%02d:%02d RTC: %d-%02d-%02d %02d:%02d:%02d", + sys_time.tm_year + 1900, sys_time.tm_mon + 1, sys_time.tm_mday, + sys_time.tm_hour, sys_time.tm_min, sys_time.tm_sec, + rtc_time.tm_year + 1900, rtc_time.tm_mon + 1, rtc_time.tm_mday, + rtc_time.tm_hour, rtc_time.tm_min, rtc_time.tm_sec); - setenv("TZ","UTC",1); const struct timeval tv = {mktime(&rtc_time), 0}; settimeofday(&tv, 0); } @@ -313,9 +317,9 @@ void panda_state_thread(bool spoofing_started) { // clear VIN, CarParams, and set new safety on car start if (ignition && !ignition_last) { - int result = params.delete_db_value("CarVin"); + int result = params.remove("CarVin"); assert((result == 0) || (result == ERR_NO_VALUE)); - result = params.delete_db_value("CarParams"); + result = params.remove("CarParams"); assert((result == 0) || (result == ERR_NO_VALUE)); if (!safety_setter_thread_running) { @@ -329,9 +333,23 @@ void panda_state_thread(bool spoofing_started) { // Write to rtc once per minute when no ignition present if ((panda->has_rtc) && !ignition && (no_ignition_cnt % 120 == 1)){ // Write time to RTC if it looks reasonable + setenv("TZ","UTC",1); struct tm sys_time = get_time(); + if (time_valid(sys_time)){ - panda->set_rtc(sys_time); + struct tm rtc_time = panda->get_rtc(); + double seconds = difftime(mktime(&rtc_time), mktime(&sys_time)); + + if (std::abs(seconds) > 1.1) { + panda->set_rtc(sys_time); + LOGW("Updating panda RTC. dt = %.2f " + "System: %d-%02d-%02d %02d:%02d:%02d RTC: %d-%02d-%02d %02d:%02d:%02d", + seconds, + sys_time.tm_year + 1900, sys_time.tm_mon + 1, sys_time.tm_mday, + sys_time.tm_hour, sys_time.tm_min, sys_time.tm_sec, + rtc_time.tm_year + 1900, rtc_time.tm_mon + 1, rtc_time.tm_mday, + rtc_time.tm_hour, rtc_time.tm_min, rtc_time.tm_sec); + } } } diff --git a/selfdrive/camerad/cameras/camera_common.cc b/selfdrive/camerad/cameras/camera_common.cc index b431eecac0..c41d734895 100644 --- a/selfdrive/camerad/cameras/camera_common.cc +++ b/selfdrive/camerad/cameras/camera_common.cc @@ -352,7 +352,7 @@ void common_process_driver_camera(SubMaster *sm, PubMaster *pm, CameraState *c, const CameraBuf *b = &c->buf; static int x_min = 0, x_max = 0, y_min = 0, y_max = 0; - static const bool is_rhd = Params().read_db_bool("IsRHD"); + static const bool is_rhd = Params().getBool("IsRHD"); // auto exposure if (cnt % 3 == 0) { diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index f32106b10f..54fa98f4f4 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -380,6 +380,7 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x7D0, None): [ b'\xf1\x00DEev SCC F-CUP 1.00 1.03 96400-Q4100 \xf1\xa01.03', b'\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 \xf1\xa01.00', + b'\xf1\x8799110Q4500\xf1\000DEev SCC F-CUP 1.00 1.00 99110-Q4500 \xf1\xa01.00', ], (Ecu.esp, 0x7D1, None): [ b'\xf1\xa01.06', @@ -392,15 +393,25 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7C4, None): [ b'\xf1\x00DEE MFC AT USA LHD 1.00 1.03 95740-Q4000 180821', b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211', + b'\xf1\000DEE MFC AT EUR LHD 1.00 1.00 99211-Q4100 200706', ], }, CAR.KIA_SELTOS: { (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x8799110Q5100\xf1\000SP2_ SCC FHCUP 1.01 1.05 99110-Q5100 \xf1\xa01.05',], - (Ecu.esp, 0x7d1, None): [b'\xf1\x8758910-Q5450\xf1\000SP ESC \t 101\031\t\005 58910-Q5450\xf1\xa01.01',], - (Ecu.engine, 0x7e0, None): [b'\xf1\x81616D2051\000\000\000\000\000\000\000\000',], + (Ecu.esp, 0x7d1, None): [ + b'\xf1\x8758910-Q5450\xf1\000SP ESC \a 101\031\t\005 58910-Q5450\xf1\xa01.01', + b'\xf1\x8758910-Q5450\xf1\000SP ESC \t 101\031\t\005 58910-Q5450\xf1\xa01.01', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81616D2051\000\000\000\000\000\000\000\000', + b'\001TSP2KNL06F100J0K', + ], (Ecu.eps, 0x7d4, None): [b'\xf1\000SP2 MDPS C 1.00 1.04 56300Q5200 ',], (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\000SP2 MFC AT USA LHD 1.00 1.04 99210-Q5000 191114',], - (Ecu.transmission, 0x7e1, None): [b'\xf1\x87CZLUB49370612JF7h\xa8y\x87\x99\xa7hv\x99\x97fv\x88\x87x\x89x\x96O\xff\x88\xff\xff\xff.@\xf1\x816V2C2051\000\000\xf1\0006V2B0_C2\000\0006V2C2051\000\000CSP4N20NS3\000\000\000\000',], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x87CZLUB49370612JF7h\xa8y\x87\x99\xa7hv\x99\x97fv\x88\x87x\x89x\x96O\xff\x88\xff\xff\xff.@\xf1\x816V2C2051\000\000\xf1\0006V2B0_C2\000\0006V2C2051\000\000CSP4N20NS3\000\000\000\000', + b'\xf1\x87954A22D200\xf1\x81T01950A1 \xf1\000T0190XBL T01950A1 DSP2T16X4X950NS6\xd30\xa5\xb9', + ], }, CAR.KIA_OPTIMA: { (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 '], diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 68ad598f52..5bf030d9c6 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -597,7 +597,7 @@ FW_VERSIONS = { ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646FF404000 ', - b'8821FF406000 ', + b'8646FF406000 ', b'8646FF407000 ', ], }, @@ -1022,7 +1022,6 @@ FW_VERSIONS = { b'\x02342N9000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02342N9100\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02342P0000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x02342Q2000\x00\x00\x00\x00\x00\x00\x00\x0054213000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B42103\x00\x00\x00\x00\x00\x00', @@ -1127,6 +1126,7 @@ FW_VERSIONS = { b'\x018966342W5000\x00\x00\x00\x00', b'\x028966342W4001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', b'\x02896634A13001\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', + b'\x02896634A13101\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896634A14001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', b'\x02896634A23001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', b'\x02896634A14001\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index ba94a96bb6..fd62428117 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -57,10 +57,10 @@ class CarInterface(CarInterfaceBase): # Per-chassis tuning values, override tuning defaults here if desired - if candidate == CAR.GOLF: - # Temporarily carry forward old tuning values while we test vehicle identification - ret.mass = 1500 + STD_CARGO_KG - ret.wheelbase = 2.64 + if candidate == CAR.GOLF_MK7: + # Averages of all AU Golf variants + ret.mass = 1397 + STD_CARGO_KG + ret.wheelbase = 2.62 elif candidate == CAR.JETTA_MK7: # Averages of all BU Jetta variants diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 828928de99..e44e8a321d 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -55,7 +55,7 @@ MQB_LDW_MESSAGES = { # FW_VERSIONS for that existing CAR. class CAR: - GOLF = "VOLKSWAGEN GOLF" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants + GOLF_MK7 = "VOLKSWAGEN GOLF 7TH GEN" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 Jetta PASSAT_MK8 = "VOLKSWAGEN PASSAT 8TH GEN" # Chassis 3G, Mk8 Passat and variants TIGUAN_MK2 = "VOLKSWAGEN TIGUAN 2ND GEN" # Chassis AD/BW, Mk2 VW Tiguan and variants @@ -66,7 +66,7 @@ class CAR: SKODA_SUPERB_MK3 = "SKODA SUPERB 3RD GEN" # Chassis 3V/NP, Mk3 Skoda Superb and variants FINGERPRINTS = { - CAR.GOLF: [{ + CAR.GOLF_MK7: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 264: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 385: 8, 418: 8, 427: 8, 668: 8, 679: 8, 681: 8, 695: 8, 779: 8, 780: 8, 783: 8, 792: 8, 795: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 870: 8, 896: 8, 897: 8, 898: 8, 901: 8, 917: 8, 919: 8, 927: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1120: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1440: 5, 1514: 8, 1515: 8, 1520: 8, 1529: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8 }], CAR.JETTA_MK7: [{ @@ -98,21 +98,76 @@ FINGERPRINTS = { IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.PASSAT_MK8, CAR.TIGUAN_MK2, CAR.SEAT_ATECA_MK1, CAR.SKODA_KODIAQ_MK1, CAR.SKODA_SCALA_MK1, CAR.SKODA_SUPERB_MK3] FW_VERSIONS = { - CAR.GOLF: { + CAR.GOLF_MK7: { (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704E906016A \xf1\x897697', + b'\xf1\x8704E906016AD\xf1\x895758', + b'\xf1\x8704E906023AG\xf1\x891726', + b'\xf1\x8704E906023BN\xf1\x894518', + b'\xf1\x8704E906027GR\xf1\x892394', + b'\xf1\x8704L906026NF\xf1\x899528', + b'\xf1\x8704L906056HE\xf1\x893758', + b'\xf1\x870EA906016A \xf1\x898343', + b'\xf1\x870EA906016S \xf1\x897207', + b'\xf1\x875G0906259 \xf1\x890007', + b'\xf1\x875G0906259J \xf1\x890002', + b'\xf1\x875G0906259L \xf1\x890002', + b'\xf1\x875G0906259Q \xf1\x890002', b'\xf1\x878V0906259P \xf1\x890001', + b'\xf1\x878V0906259Q \xf1\x890002', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870CW300045 \xf1\x894531', + b'\xf1\x870D9300040S \xf1\x894311', + b'\xf1\x870CW300047D \xf1\x895261', + b'\xf1\x870D9300012 \xf1\x894913', + b'\xf1\x870CW300042F \xf1\x891604', + b'\xf1\x870DD300046F \xf1\x891601', + b'\xf1\x870D9300020S \xf1\x895201', b'\xf1\x870GC300012A \xf1\x891403', + b'\xf1\x870GC300043T \xf1\x899999', + b'\xf1\x870GC300020G \xf1\x892404', + b'\xf1\x870GC300014B \xf1\x892405', + b'\xf1\x870DD300045K \xf1\x891120', ], (Ecu.srs, 0x715, None): [ - b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13271212111312--071104171838103891131211', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023271212111312--071104171838103891131211', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13272512111312--07110417182C102C91131211', + b'\xf1\x875Q0959655M \xf1\x890361\xf1\x82\0211413001112120041114115121611169112', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02324230011211200621143171724112491132111', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02315120011211200621143171717111791132111', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\x1315120011211200061104171717101791132111', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02324230011211200061104171724102491132111', + b'\xf1\x875Q0959655AA\xf1\x890386\xf1\x82\0211413001113120053114317121C111C9113', + b'\xf1\x875Q0959655AA\xf1\x890386\xf1\x82\0211413001113120043114317121C111C9113', + b'\xf1\x875Q0959655AA\xf1\x890388\xf1\x82\0211413001113120053114317121C111C9113', + b'\xf1\x875Q0959655AA\xf1\x890388\xf1\x82\0211413001113120043114417121411149113', + b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02314160011123300314211012230229333463100', ], (Ecu.eps, 0x712, None): [ + b'\xf1\x873Q0909144F \xf1\x895043\xf1\x82\00561A01612A0', + b'\xf1\x873Q0909144H \xf1\x895061\xf1\x82\00566A0J612A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571A0JA15A1', + b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\00571A0JA16A1', + b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820519A9040203', + b'\xf1\x875Q0909144L \xf1\x891021\xf1\x82\00522A00402A0', + b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00511A00403A0', + b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\00516A07A02A1', + b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\00521A00441A1', + b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\x0521A00641A1', + b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521A00642A1', + b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521A07B05A1', + b'\xf1\x875QN909144A \xf1\x895081\xf1\x82\x0571A01A17A1', ], (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x875Q0907572A \xf1\x890141\xf1\x82\00101', + b'\xf1\x875Q0907572B \xf1\x890200\xf1\x82\00101', + b'\xf1\x875Q0907572C \xf1\x890210\xf1\x82\00101', + b'\xf1\x875Q0907572D \xf1\x890304\xf1\x82\00101', + b'\xf1\x875Q0907572F \xf1\x890400\xf1\x82\00101', + b'\xf1\x875Q0907572H \xf1\x890620', b'\xf1\x875Q0907572J \xf1\x890654', + b'\xf1\x875Q0907572P \xf1\x890682', ], }, CAR.JETTA_MK7: { @@ -281,7 +336,7 @@ FW_VERSIONS = { } DBC = { - CAR.GOLF: dbc_dict('vw_mqb_2010', None), + CAR.GOLF_MK7: dbc_dict('vw_mqb_2010', None), CAR.JETTA_MK7: dbc_dict('vw_mqb_2010', None), CAR.PASSAT_MK8: dbc_dict('vw_mqb_2010', None), CAR.TIGUAN_MK2: dbc_dict('vw_mqb_2010', None), diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc index 930f3f0df2..1bb719874c 100644 --- a/selfdrive/common/params.cc +++ b/selfdrive/common/params.cc @@ -11,9 +11,6 @@ #include #include -#include -#include -#include #include #include @@ -83,15 +80,11 @@ Params::Params(bool persistent_param){ params_path = persistent_param ? persistent_params_path : default_params_path; } -Params::Params(std::string path) { +Params::Params(const std::string &path) { params_path = path; } -int Params::write_db_value(std::string key, std::string dat){ - return write_db_value(key.c_str(), dat.c_str(), dat.length()); -} - -int Params::write_db_value(const char* key, const char* value, size_t value_size) { +int Params::put(const char* key, const char* value, size_t value_size) { // Information about safely and atomically writing a file: https://lwn.net/Articles/457667/ // 1) Create temp file // 2) Write data to temp file @@ -213,7 +206,7 @@ cleanup: return result; } -int Params::delete_db_value(std::string key) { +int Params::remove(const char *key) { int lock_fd = -1; int result; std::string path; @@ -230,7 +223,7 @@ int Params::delete_db_value(std::string key) { // Delete value. path = params_path + "/d/" + key; - result = remove(path.c_str()); + result = ::remove(path.c_str()); if (result != 0) { result = ERR_NO_VALUE; goto cleanup; @@ -251,52 +244,28 @@ cleanup: return result; } -std::string Params::get(std::string key, bool block){ - char* value; - size_t size; - int r; - - if (block) { - r = read_db_value_blocking((const char*)key.c_str(), &value, &size); - } else { - r = read_db_value((const char*)key.c_str(), &value, &size); - } - - if (r == 0){ - std::string s(value, size); - free(value); - return s; +std::string Params::get(const char *key, bool block) { + std::string path = params_path + "/d/" + key; + if (!block) { + return util::read_file(path); } else { - return ""; - } -} - -int Params::read_db_value(const char* key, char** value, size_t* value_sz) { - std::string path = params_path + "/d/" + std::string(key); - *value = static_cast(read_file(path.c_str(), value_sz)); - if (*value == NULL) { - return -22; - } - return 0; -} - -int Params::read_db_value_blocking(const char* key, char** value, size_t* value_sz) { - params_do_exit = 0; - void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler); - void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler); - - while (!params_do_exit) { - const int result = read_db_value(key, value, value_sz); - if (result == 0) { - break; - } else { - util::sleep_for(100); // 0.1 s + // blocking read until successful + params_do_exit = 0; + void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler); + void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler); + + std::string value; + while (!params_do_exit) { + if (value = util::read_file(path); !value.empty()) { + break; + } + util::sleep_for(100); // 0.1 s } - } - std::signal(SIGINT, prev_handler_sigint); - std::signal(SIGTERM, prev_handler_sigterm); - return params_do_exit; // Return 0 if we had no interrupt + std::signal(SIGINT, prev_handler_sigint); + std::signal(SIGTERM, prev_handler_sigterm); + return value; + } } int Params::read_db_all(std::map *params) { @@ -334,20 +303,3 @@ int Params::read_db_all(std::map *params) { close(lock_fd); return 0; } - -std::vector Params::read_db_bytes(const char* param_name) { - std::vector bytes; - char* value; - size_t sz; - int result = read_db_value(param_name, &value, &sz); - if (result == 0) { - bytes.assign(value, value+sz); - free(value); - } - return bytes; -} - -bool Params::read_db_bool(const char* param_name) { - std::vector bytes = read_db_bytes(param_name); - return bytes.size() > 0 and bytes[0] == '1'; -} diff --git a/selfdrive/common/params.h b/selfdrive/common/params.h index 8da077cfdc..2362db4da5 100644 --- a/selfdrive/common/params.h +++ b/selfdrive/common/params.h @@ -1,8 +1,9 @@ #pragma once + #include #include #include -#include +#include #define ERR_NO_VALUE -33 @@ -12,35 +13,44 @@ private: public: Params(bool persistent_param = false); - Params(std::string path); - - int write_db_value(std::string key, std::string dat); - int write_db_value(const char* key, const char* value, size_t value_size); - - // Reads a value from the params database. - // Inputs: - // key: The key to read. - // value: A pointer where a newly allocated string containing the db value will - // be written. - // value_sz: A pointer where the size of value will be written. Does not - // include the NULL terminator. - // persistent_param: Boolean indicating if the param store in the /persist partition is to be used. - // e.g. for sensor calibration files. Will not be cleared after wipe or re-install. - // - // Returns: Negative on failure, otherwise 0. - int read_db_value(const char* key, char** value, size_t* value_sz); - - // Delete a value from the params database. - // Inputs are the same as read_db_value, without value and value_sz. - int delete_db_value(std::string key); - - // Reads a value from the params database, blocking until successful. - // Inputs are the same as read_db_value. - int read_db_value_blocking(const char* key, char** value, size_t* value_sz); + Params(const std::string &path); + + // Delete a value + int remove(const char *key); + inline int remove(const std::string &key) { + return remove (key.c_str()); + } + // read all values int read_db_all(std::map *params); - std::vector read_db_bytes(const char* param_name); - bool read_db_bool(const char* param_name); - std::string get(std::string key, bool block=false); + // read a value + std::string get(const char *key, bool block = false); + + inline std::string get(const std::string &key, bool block = false) { + return get(key.c_str(), block); + } + + template + std::optional get(const char *key, bool block = false) { + std::istringstream iss(get(key, block)); + T value{}; + iss >> value; + return iss.fail() ? std::nullopt : std::optional(value); + } + + inline bool getBool(const char *key) { + return get(key) == "1"; + } + + // write a value + int put(const char* key, const char* val, size_t value_size); + + inline int put(const std::string &key, const std::string &val) { + return put(key.c_str(), val.data(), val.size()); + } + + inline int putBool(const char *key, bool val) { + return put(key, val ? "1" : "0", 1); + } }; diff --git a/selfdrive/common/swaglog.cc b/selfdrive/common/swaglog.cc index 5c69c0a949..c1e168fde5 100644 --- a/selfdrive/common/swaglog.cc +++ b/selfdrive/common/swaglog.cc @@ -89,8 +89,7 @@ void log(int levelnum, const char* filename, int lineno, const char* func, const printf("%s: %s\n", filename, msg); } char levelnum_c = levelnum; - zmq_send(s.sock, &levelnum_c, 1, ZMQ_NOBLOCK | ZMQ_SNDMORE); - zmq_send(s.sock, log_s.c_str(), log_s.length(), ZMQ_NOBLOCK); + zmq_send(s.sock, (levelnum_c + log_s).c_str(), log_s.length() + 1, ZMQ_NOBLOCK); } void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func, diff --git a/selfdrive/common/test_params.c b/selfdrive/common/test_params.c deleted file mode 100644 index 51aff9d480..0000000000 --- a/selfdrive/common/test_params.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "selfdrive/common/params.h" - -#include -#include -#include - -static const char* const kUsage = "%s: read|write|read_block params_path key [value]\n"; - -int main(int argc, const char* argv[]) { - if (argc < 4) { - printf(kUsage, argv[0]); - return 0; - } - - const char* params_path = argv[2]; - const char* key = argv[3]; - if (strcmp(argv[1], "read") == 0) { - char* value; - size_t value_size; - int result = read_db_value(params_path, key, &value, &value_size); - if (result >= 0) { - fprintf(stdout, "Read %zu bytes: ", value_size); - fwrite(value, 1, value_size, stdout); - fprintf(stdout, "\n"); - free(value); - } else { - fprintf(stderr, "Error reading: %d\n", result); - return -1; - } - } else if (strcmp(argv[1], "write") == 0) { - if (argc < 5) { - fprintf(stderr, "Error: write value required\n"); - return 1; - } - - const char* value = argv[4]; - const size_t value_size = strlen(value); - int result = write_db_value(params_path, key, value, value_size); - if (result >= 0) { - fprintf(stdout, "Wrote %s to %s\n", value, key); - } else { - fprintf(stderr, "Error writing: %d\n", result); - return -1; - } - } else if (strcmp(argv[1], "read_block") == 0) { - char* value; - size_t value_size; - read_db_value_blocking(params_path, key, &value, &value_size); - fprintf(stdout, "Read %zu bytes: ", value_size); - fwrite(value, 1, value_size, stdout); - fprintf(stdout, "\n"); - free(value); - } else { - printf(kUsage, argv[0]); - return 1; - } - - return 0; -} - -// BUILD: -// $ gcc -I$HOME/one selfdrive/common/test_params.c selfdrive/common/params.c selfdrive/common/util.cc -o ./test_params -// $ seq 0 100000 | xargs -P20 -I{} ./test_params write /data/params DongleId {} && sleep 0.1 & -// $ while ./test_params read /data/params DongleId; do sleep 0.05; done diff --git a/selfdrive/common/util.h b/selfdrive/common/util.h index b75c2f4343..98406e0f4b 100644 --- a/selfdrive/common/util.h +++ b/selfdrive/common/util.h @@ -161,3 +161,19 @@ struct unique_fd { operator int() const { return fd_; } int fd_; }; + +class FirstOrderFilter { +public: + FirstOrderFilter(float x0, float ts, float dt) { + k_ = (dt / ts) / (1.0 + dt / ts); + x_ = x0; + } + inline float update(float x) { + x_ = (1. - k_) * x_ + k_ * x; + return x_; + } + inline void reset(float x) { x_ = x; } + +private: + float x_, k_; +}; diff --git a/selfdrive/debug/dump.py b/selfdrive/debug/dump.py index 908b129c73..ce96b360f8 100755 --- a/selfdrive/debug/dump.py +++ b/selfdrive/debug/dump.py @@ -38,7 +38,7 @@ if __name__ == "__main__": values = [s.strip().split(".") for s in args.values.split(",")] while 1: - polld = poller.poll(1000) + polld = poller.poll(100) for sock in polld: msg = sock.receive() evt = log.Event.from_bytes(msg) diff --git a/selfdrive/hardware/eon/hardware.h b/selfdrive/hardware/eon/hardware.h index 70e9144c33..bcf99a6284 100644 --- a/selfdrive/hardware/eon/hardware.h +++ b/selfdrive/hardware/eon/hardware.h @@ -40,4 +40,26 @@ public: std::string cmd = util::string_format("setprop persist.neos.ssh %d", enabled ? 1 : 0); std::system(cmd.c_str()); }; + + // android only + inline static bool launched_activity = false; + static void check_activity() { + int ret = std::system("dumpsys SurfaceFlinger --list | grep -Fq 'com.android.settings'"); + launched_activity = ret == 0; + } + static void launch_activity(std::string activity, std::string opts = "") { + if (!launched_activity) { + std::string cmd = "am start -n " + activity + " " + opts + + " --ez extra_prefs_show_button_bar true \ + --es extra_prefs_set_next_text ''"; + std::system(cmd.c_str()); + } + launched_activity = true; + } + static void launch_wifi() { + launch_activity("com.android.settings/.wifi.WifiPickerActivity", "-a android.net.wifi.PICK_WIFI_NETWORK"); + } + static void launch_tethering() { + launch_activity("com.android.settings/.TetherSettings"); + } }; diff --git a/selfdrive/hardware/tici/hardware.h b/selfdrive/hardware/tici/hardware.h index 034e01a862..705f8b81e2 100644 --- a/selfdrive/hardware/tici/hardware.h +++ b/selfdrive/hardware/tici/hardware.h @@ -27,6 +27,6 @@ public: }; static void set_display_power(bool on) {}; - static bool get_ssh_enabled() { return Params().read_db_bool("SshEnabled"); }; - static void set_ssh_enabled(bool enabled) { Params().write_db_value("SshEnabled", (enabled ? "1" : "0")); }; + static bool get_ssh_enabled() { return Params().getBool("SshEnabled"); }; + static void set_ssh_enabled(bool enabled) { Params().putBool("SshEnabled", enabled); }; }; diff --git a/selfdrive/loggerd/logger.cc b/selfdrive/loggerd/logger.cc index ca621810e0..d227446944 100644 --- a/selfdrive/loggerd/logger.cc +++ b/selfdrive/loggerd/logger.cc @@ -102,7 +102,7 @@ kj::Array logger_build_init_data() { init.setGitCommit(params.get("GitCommit")); init.setGitBranch(params.get("GitBranch")); init.setGitRemote(params.get("GitRemote")); - init.setPassive(params.read_db_bool("Passive")); + init.setPassive(params.getBool("Passive")); { std::map params_map; params.read_db_all(¶ms_map); diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index c28657c6f1..c5e347d6e0 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -369,7 +369,7 @@ int main(int argc, char** argv) { s.rotate_state[LOG_CAMERA_ID_FCAMERA].enabled = true; #if defined(QCOM) || defined(QCOM2) - bool record_front = Params().read_db_bool("RecordFront"); + bool record_front = Params().getBool("RecordFront"); if (record_front) { encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_DCAMERA)); s.rotate_state[LOG_CAMERA_ID_DCAMERA].enabled = true; diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index 198dccdf26..4a8539dd3e 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -127,10 +127,10 @@ class Uploader(): url_resp_json = json.loads(url_resp.text) url = url_resp_json['url'] headers = url_resp_json['headers'] - cloudlog.info("upload_url v1.3 %s %s", url, str(headers)) + cloudlog.debug("upload_url v1.3 %s %s", url, str(headers)) if fake_upload: - cloudlog.info("*** WARNING, THIS IS A FAKE UPLOAD TO %s ***" % url) + cloudlog.debug("*** WARNING, THIS IS A FAKE UPLOAD TO %s ***" % url) class FakeResponse(): def __init__(self): @@ -164,7 +164,7 @@ class Uploader(): cloudlog.event("upload", key=key, fn=fn, sz=sz) - cloudlog.info("checking %r with size %r", key, sz) + cloudlog.debug("checking %r with size %r", key, sz) if sz == 0: try: @@ -174,10 +174,10 @@ class Uploader(): cloudlog.event("uploader_setxattr_failed", exc=self.last_exc, key=key, fn=fn, sz=sz) success = True else: - cloudlog.info("uploading %r", fn) + cloudlog.debug("uploading %r", fn) stat = self.normal_upload(key, fn) if stat is not None and stat.status_code in (200, 201, 412): - cloudlog.event("upload_success" if stat.status_code != 412 else "upload_ignored", key=key, fn=fn, sz=sz) + cloudlog.event("upload_success" if stat.status_code != 412 else "upload_ignored", key=key, fn=fn, sz=sz, debug=True) try: # tag file as uploaded setxattr(fn, UPLOAD_ATTR_NAME, UPLOAD_ATTR_VALUE) @@ -185,14 +185,12 @@ class Uploader(): cloudlog.event("uploader_setxattr_failed", exc=self.last_exc, key=key, fn=fn, sz=sz) success = True else: - cloudlog.event("upload_failed", stat=stat, exc=self.last_exc, key=key, fn=fn, sz=sz) + cloudlog.event("upload_failed", stat=stat, exc=self.last_exc, key=key, fn=fn, sz=sz, debug=True) success = False return success def uploader_fn(exit_event): - cloudlog.info("uploader_fn") - params = Params() dongle_id = params.get("DongleId").decode('utf8') @@ -209,8 +207,14 @@ def uploader_fn(exit_event): backoff = 0.1 while not exit_event.is_set(): sm.update(0) - on_wifi = force_wifi or sm['deviceState'].networkType == NetworkType.wifi offroad = params.get("IsOffroad") == b'1' + network_type = sm['deviceState'].networkType if not force_wifi else NetworkType.wifi + if network_type == NetworkType.none: + if allow_sleep: + time.sleep(60 if offroad else 5) + continue + + on_wifi = network_type == NetworkType.wifi allow_raw_upload = params.get("IsUploadRawEnabled") != b"0" d = uploader.next_file_to_upload(with_raw=allow_raw_upload and on_wifi and offroad) @@ -221,13 +225,12 @@ def uploader_fn(exit_event): key, fn = d - cloudlog.event("uploader_netcheck", is_on_wifi=on_wifi) - cloudlog.info("to upload %r", d) + cloudlog.debug("upload %r over %s", d, network_type) success = uploader.upload(key, fn) if success: backoff = 0.1 elif allow_sleep: - cloudlog.info("backoff %r", backoff) + cloudlog.info("upload backoff %r", backoff) time.sleep(backoff + random.uniform(0, backoff)) backoff = min(backoff*2, 120) cloudlog.info("upload done, success=%r", success) diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 4eb64cfd4b..e967d5a754 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -72,10 +72,7 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client) { SubMaster sm({"lateralPlan", "roadCameraState"}); // setup filter to track dropped frames - const float dt = 1. / MODEL_FREQ; - const float ts = 10.0; // filter time constant (s) - const float frame_filter_k = (dt / ts) / (1. + dt / ts); - float frames_dropped = 0; + FirstOrderFilter frame_dropped_filter(0., 10., 1. / MODEL_FREQ); uint32_t frame_id = 0, last_vipc_frame_id = 0; double last = 0; @@ -114,8 +111,12 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client) { // tracked dropped frames uint32_t vipc_dropped_frames = extra.frame_id - last_vipc_frame_id - 1; - frames_dropped = (1. - frame_filter_k) * frames_dropped + frame_filter_k * (float)std::min(vipc_dropped_frames, 10U); - if (run_count < 10) frames_dropped = 0; // let frame drops warm up + float frames_dropped = frame_dropped_filter.update((float)std::min(vipc_dropped_frames, 10U)); + if (run_count < 10) { // let frame drops warm up + frame_dropped_filter.reset(0); + frames_dropped = 0.; + } + float frame_drop_ratio = frames_dropped / (1 + frames_dropped); model_publish(pm, extra.frame_id, frame_id, frame_drop_ratio, model_buf, extra.timestamp_eof, model_execution_time, diff --git a/selfdrive/modeld/models/dmonitoring.cc b/selfdrive/modeld/models/dmonitoring.cc index 33900579fb..6cf2d46ee8 100644 --- a/selfdrive/modeld/models/dmonitoring.cc +++ b/selfdrive/modeld/models/dmonitoring.cc @@ -25,7 +25,7 @@ void dmonitoring_init(DMonitoringModelState* s) { int runtime = USE_DSP_RUNTIME; s->m = new DefaultRunModel(model_path, &s->output[0], OUTPUT_SIZE, runtime); - s->is_rhd = Params().read_db_bool("IsRHD"); + s->is_rhd = Params().getBool("IsRHD"); } template diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 767bc2fe1f..c0b7de3d30 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -70,7 +70,7 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context) { #endif #ifdef TRAFFIC_CONVENTION - const int idx = Params().read_db_bool("IsRHD") ? 1 : 0; + const int idx = Params().getBool("IsRHD") ? 1 : 0; s->traffic_convention[idx] = 1.0; s->m->addTrafficConvention(s->traffic_convention, TRAFFIC_CONVENTION_LEN); #endif diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index 1e7c012035..2637af214f 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -30,6 +30,8 @@ _BLINK_THRESHOLD_SLACK = 0.65 _BLINK_THRESHOLD_STRICT = 0.5 _PITCH_WEIGHT = 1.35 # pitch matters a lot more _POSESTD_THRESHOLD = 0.14 +_E2E_POSE_THRESHOLD = 0.9 +_E2E_EYES_THRESHOLD = 0.75 _METRIC_THRESHOLD = 0.4 _METRIC_THRESHOLD_SLACK = 0.55 _METRIC_THRESHOLD_STRICT = 0.4 @@ -194,8 +196,10 @@ class DriverStatus(): self.blink.left_blink = driver_state.leftBlinkProb * (driver_state.leftEyeProb > _EYE_THRESHOLD) * (driver_state.sunglassesProb < _SG_THRESHOLD) self.blink.right_blink = driver_state.rightBlinkProb * (driver_state.rightEyeProb > _EYE_THRESHOLD) * (driver_state.sunglassesProb < _SG_THRESHOLD) - self.driver_distracted = self._is_driver_distracted(self.pose, self.blink) > 0 and \ - driver_state.faceProb > _FACE_THRESHOLD and self.pose.low_std + self.driver_distracted = (self._is_driver_distracted(self.pose, self.blink) > 0 and + driver_state.faceProb > _FACE_THRESHOLD and self.pose.low_std) or \ + ((driver_state.distractedPose > _E2E_POSE_THRESHOLD or driver_state.distractedEyes > _E2E_EYES_THRESHOLD) and + (self.face_detected and not self.face_partial)) self.driver_distraction_filter.update(self.driver_distracted) # update offseter @@ -209,7 +213,7 @@ class DriverStatus(): self.is_model_uncertain = self.hi_stds * DT_DMON > _HI_STD_FALLBACK_TIME self._set_timers(self.face_detected and not self.is_model_uncertain) - if self.face_detected and not self.pose.low_std: + if self.face_detected and not self.pose.low_std and not self.driver_distracted: self.hi_stds += 1 elif self.face_detected and self.pose.low_std: self.hi_stds = 0 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dc8060123d..8acd96e4ea 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3da639f754563292103525345ec26e384e4cb9a5 \ No newline at end of file +796df70c9c83a693f81e4a35d97f90dc5378ef06 \ No newline at end of file diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index 4bcc783921..8d777c52fc 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -437,8 +437,8 @@ routes = { 'enableCamera': True, 'enableDsu': False, }, - "76b83eb0245de90e|2019-10-20--15-42-29": { - 'carFingerprint': VOLKSWAGEN.GOLF, + "cae14e88932eb364|2021-03-26--14-43-28": { + 'carFingerprint': VOLKSWAGEN.GOLF_MK7, 'enableCamera': True, }, "58a7d3b707987d65|2021-03-25--17-26-37": { diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index adb44c35ef..265e391ca7 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -57,6 +57,9 @@ def check_cpu_usage(first_proc, last_proc): cpu_time = cputime_total(last) - cputime_total(first) cpu_usage = cpu_time / dt * 100. if cpu_usage > max(normal_cpu_usage * 1.1, normal_cpu_usage + 5.0): + # TODO: fix high CPU when playing sounds constantly in UI + if proc_name == "./_ui" and cpu_usage < 40.: + continue result += f"Warning {proc_name} using more CPU than normal\n" r = False elif cpu_usage < min(normal_cpu_usage * 0.65, max(normal_cpu_usage - 1.0, 0.0)): diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index c790f8d60b..485ebd2dee 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -169,13 +169,13 @@ class PowerMonitoring: return disable_charging # See if we need to shutdown - def should_shutdown(self, pandaState, offroad_timestamp, started_seen, LEON): + def should_shutdown(self, pandaState, offroad_timestamp, started_seen): if pandaState is None or offroad_timestamp is None: return False now = sec_since_boot() panda_charging = (pandaState.pandaState.usbPowerMode != log.PandaState.UsbPowerMode.client) - BATT_PERC_OFF = 10 if LEON else 3 + BATT_PERC_OFF = 10 should_shutdown = False # Wait until we have shut down charging before powering down diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 6240d14e47..9f76980174 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -2,6 +2,7 @@ import datetime import os import time +from pathlib import Path from typing import Dict, Optional, Tuple import psutil @@ -37,9 +38,9 @@ DISCONNECT_TIMEOUT = 5. # wait 5 seconds before going offroad after disconnect prev_offroad_states: Dict[str, Tuple[bool, Optional[str]]] = {} -LEON = False last_eon_fan_val = None + def read_tz(x): if x is None: return 0 @@ -62,44 +63,24 @@ def read_thermal(thermal_config): def setup_eon_fan(): - global LEON - os.system("echo 2 > /sys/module/dwc3_msm/parameters/otg_switch") - bus = SMBus(7, force=True) - try: - bus.write_byte_data(0x21, 0x10, 0xf) # mask all interrupts - bus.write_byte_data(0x21, 0x03, 0x1) # set drive current and global interrupt disable - bus.write_byte_data(0x21, 0x02, 0x2) # needed? - bus.write_byte_data(0x21, 0x04, 0x4) # manual override source - except IOError: - print("LEON detected") - LEON = True - bus.close() - def set_eon_fan(val): - global LEON, last_eon_fan_val + global last_eon_fan_val if last_eon_fan_val is None or last_eon_fan_val != val: bus = SMBus(7, force=True) - if LEON: - try: - i = [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10][val] - bus.write_i2c_block_data(0x3d, 0, [i]) - except IOError: - # tusb320 - if val == 0: - bus.write_i2c_block_data(0x67, 0xa, [0]) - #bus.write_i2c_block_data(0x67, 0x45, [1<<2]) - else: - #bus.write_i2c_block_data(0x67, 0x45, [0]) - bus.write_i2c_block_data(0x67, 0xa, [0x20]) - bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6]) - else: - bus.write_byte_data(0x21, 0x04, 0x2) - bus.write_byte_data(0x21, 0x03, (val*2)+1) - bus.write_byte_data(0x21, 0x04, 0x4) + try: + i = [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10][val] + bus.write_i2c_block_data(0x3d, 0, [i]) + except IOError: + # tusb320 + if val == 0: + bus.write_i2c_block_data(0x67, 0xa, [0]) + else: + bus.write_i2c_block_data(0x67, 0xa, [0x20]) + bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6]) bus.close() last_eon_fan_val = val @@ -191,6 +172,19 @@ def thermald_thread(): thermal_config = HARDWARE.get_thermal_config() + # CPR3 logging + if EON: + base_path = "/sys/kernel/debug/cpr3-regulator/" + cpr_files = [p for p in Path(base_path).glob("**/*") if p.is_file()] + cpr_data = {} + for cf in cpr_files: + with open(cf, "r") as f: + try: + cpr_data[str(cf)] = f.read().strip() + except Exception: + pass + cloudlog.event("CPR", data=cpr_data) + while 1: pandaState = messaging.recv_sock(pandaState_sock, wait=True) msg = read_thermal(thermal_config) @@ -386,7 +380,7 @@ def thermald_thread(): msg.deviceState.chargingDisabled = power_monitor.should_disable_charging(pandaState, off_ts) # Check if we need to shut down - if power_monitor.should_shutdown(pandaState, off_ts, started_seen, LEON): + if power_monitor.should_shutdown(pandaState, off_ts, started_seen): cloudlog.info(f"shutting device down, offroad since {off_ts}") # TODO: add function for blocking cloudlog instead of sleep time.sleep(10) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index a0507ef598..ebef246ab6 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -16,7 +16,7 @@ if arch == "Darwin": qt_env['FRAMEWORKS'] += ['OpenCL'] widgets_src = ["qt/widgets/input.cc", "qt/widgets/drive_stats.cc", - "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/qt_sound.cc", + "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/sound.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc", "#phonelibs/qrcode/QrCode.cc"] if arch != 'aarch64': diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc index 563dec36a3..7d19a61576 100644 --- a/selfdrive/ui/paint.cc +++ b/selfdrive/ui/paint.cc @@ -50,19 +50,19 @@ static void draw_chevron(UIState *s, float x, float y, float sz, NVGcolor fillCo nvgFill(s->vg); } -static void ui_draw_circle_image(const UIState *s, int x, int y, int size, const char *image, NVGcolor color, float img_alpha, int img_y = 0) { - const int img_size = size * 1.5; +static void ui_draw_circle_image(const UIState *s, int center_x, int center_y, int radius, const char *image, NVGcolor color, float img_alpha) { nvgBeginPath(s->vg); - nvgCircle(s->vg, x, y + (bdr_s * 1.5), size); + nvgCircle(s->vg, center_x, center_y, radius); nvgFillColor(s->vg, color); nvgFill(s->vg); - ui_draw_image(s, {x - (img_size / 2), img_y ? img_y : y - (size / 4), img_size, img_size}, image, img_alpha); + const int img_size = radius * 1.5; + ui_draw_image(s, {center_x - (img_size / 2), center_y - (img_size / 2), img_size, img_size}, image, img_alpha); } -static void ui_draw_circle_image(const UIState *s, int x, int y, int size, const char *image, bool active) { +static void ui_draw_circle_image(const UIState *s, int center_x, int center_y, int radius, const char *image, bool active) { float bg_alpha = active ? 0.3f : 0.1f; float img_alpha = active ? 1.0f : 0.15f; - ui_draw_circle_image(s, x, y, size, image, nvgRGBA(0, 0, 0, (255 * bg_alpha)), img_alpha); + ui_draw_circle_image(s, center_x, center_y, radius, image, nvgRGBA(0, 0, 0, (255 * bg_alpha)), img_alpha); } static void draw_lead(UIState *s, int idx) { @@ -215,18 +215,18 @@ static void ui_draw_vision_speed(UIState *s) { static void ui_draw_vision_event(UIState *s) { if (s->scene.controls_state.getEngageable()) { // draw steering wheel - const int bg_wheel_size = 96; - const int bg_wheel_x = s->viz_rect.right() - bg_wheel_size - bdr_s * 2; - const int bg_wheel_y = s->viz_rect.y + (bg_wheel_size / 2) + (bdr_s * 1.5); - ui_draw_circle_image(s, bg_wheel_x, bg_wheel_y, bg_wheel_size, "wheel", bg_colors[s->status], 1.0f, bg_wheel_y - 25); + const int radius = 96; + const int center_x = s->viz_rect.right() - radius - bdr_s * 2; + const int center_y = s->viz_rect.y + radius + (bdr_s * 1.5); + ui_draw_circle_image(s, center_x, center_y, radius, "wheel", bg_colors[s->status], 1.0f); } } static void ui_draw_vision_face(UIState *s) { - const int face_size = 96; - const int face_x = (s->viz_rect.x + face_size + (bdr_s * 2)); - const int face_y = (s->viz_rect.bottom() - footer_h + ((footer_h - face_size) / 2)); - ui_draw_circle_image(s, face_x, face_y, face_size, "driver_face", s->scene.dmonitoring_state.getIsActiveMode()); + const int radius = 96; + const int center_x = s->viz_rect.x + radius + (bdr_s * 2); + const int center_y = s->viz_rect.bottom() - footer_h / 2; + ui_draw_circle_image(s, center_x, center_y, radius, "driver_face", s->scene.dmonitoring_state.getIsActiveMode()); } static void ui_draw_driver_view(UIState *s) { @@ -266,10 +266,10 @@ static void ui_draw_driver_view(UIState *s) { } // draw face icon - const int face_size = 85; - const int icon_x = is_rhd ? rect.right() - face_size - bdr_s * 2 : rect.x + face_size + bdr_s * 2; - const int icon_y = rect.bottom() - face_size - bdr_s * 2.5; - ui_draw_circle_image(s, icon_x, icon_y, face_size, "driver_face", face_detected); + const int face_radius = 85; + const int center_x = is_rhd ? rect.right() - face_radius - bdr_s * 2 : rect.x + face_radius + bdr_s * 2; + const int center_y = rect.bottom() - face_radius - bdr_s * 2.5; + ui_draw_circle_image(s, center_x, center_y, face_radius, "driver_face", face_detected); } static void ui_draw_vision_header(UIState *s) { @@ -396,6 +396,11 @@ void ui_draw(UIState *s) { if (draw_alerts && s->scene.alert_size != cereal::ControlsState::AlertSize::NONE) { ui_draw_vision_alert(s); } + + if (s->scene.driver_view && !s->vipc_client->connected) { + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + ui_draw_text(s, s->viz_rect.centerX(), s->viz_rect.centerY(), "Please wait for camera to start", 40 * 2.5, COLOR_WHITE, "sans-bold"); + } nvgEndFrame(s->vg); glDisable(GL_BLEND); } diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc index 5522705c4f..cf7a8758cc 100644 --- a/selfdrive/ui/qt/api.cc +++ b/selfdrive/ui/qt/api.cc @@ -134,12 +134,12 @@ void RequestRepeater::requestFinished(){ if (reply->error() == QNetworkReply::NoError) { // save to cache if (!cache_key.isEmpty()) { - Params().write_db_value(cache_key.toStdString(), response.toStdString()); + Params().put(cache_key.toStdString(), response.toStdString()); } emit receivedResponse(response); } else { if (!cache_key.isEmpty()) { - Params().delete_db_value(cache_key.toStdString()); + Params().remove(cache_key.toStdString()); } emit failedResponse(reply->errorString()); } diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 2dc7b9fc6b..f36acb1676 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -51,7 +51,8 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { void HomeWindow::mousePressEvent(QMouseEvent* e) { UIState* ui_state = &glWindow->ui_state; if (GLWindow::ui_state.scene.driver_view) { - Params().write_db_value("IsDriverViewEnabled", "0", 1); + Params().putBool("IsDriverViewEnabled", false); + GLWindow::ui_state.scene.driver_view = false; return; } @@ -87,7 +88,7 @@ OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) { QObject::connect(alert_notification, SIGNAL(released()), this, SLOT(openAlerts())); header_layout->addWidget(alert_notification, 0, Qt::AlignHCenter | Qt::AlignRight); - std::string brand = Params().read_db_bool("Passive") ? "dashcam" : "openpilot"; + std::string brand = Params().getBool("Passive") ? "dashcam" : "openpilot"; QLabel* version = new QLabel(QString::fromStdString(brand + " v" + Params().get("Version"))); version->setStyleSheet(R"(font-size: 55px;)"); header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight); @@ -153,7 +154,7 @@ void OffroadHome::refresh() { // update alerts alerts_widget->refresh(); - if (!alerts_widget->alerts.size() && !alerts_widget->updateAvailable) { + if (!alerts_widget->alertCount && !alerts_widget->updateAvailable) { emit closeAlerts(); alert_notification->setVisible(false); return; @@ -162,7 +163,7 @@ void OffroadHome::refresh() { if (alerts_widget->updateAvailable) { alert_notification->setText("UPDATE"); } else { - int alerts = alerts_widget->alerts.size(); + int alerts = alerts_widget->alertCount; alert_notification->setText(QString::number(alerts) + " ALERT" + (alerts == 1 ? "" : "S")); } @@ -222,20 +223,15 @@ static void handle_display_state(UIState* s, bool user_input) { } } -GLWindow::GLWindow(QWidget* parent) : QOpenGLWidget(parent) { +GLWindow::GLWindow(QWidget* parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QOpenGLWidget(parent) { timer = new QTimer(this); QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate())); backlight_timer = new QTimer(this); QObject::connect(backlight_timer, SIGNAL(timeout()), this, SLOT(backlightUpdate())); - int result = read_param(&brightness_b, "BRIGHTNESS_B", true); - result += read_param(&brightness_m, "BRIGHTNESS_M", true); - if (result != 0) { - brightness_b = 10.0; - brightness_m = 0.1; - } - smooth_brightness = BACKLIGHT_OFFROAD; + brightness_b = Params().get("BRIGHTNESS_B").value_or(10.0); + brightness_m = Params().get("BRIGHTNESS_M").value_or(0.1); } GLWindow::~GLWindow() { @@ -264,16 +260,12 @@ void GLWindow::initializeGL() { void GLWindow::backlightUpdate() { // Update brightness - float k = (BACKLIGHT_DT / BACKLIGHT_TS) / (1.0f + BACKLIGHT_DT / BACKLIGHT_TS); - float clipped_brightness = std::min(100.0f, (ui_state.scene.light_sensor * brightness_m) + brightness_b); if (!ui_state.scene.started) { clipped_brightness = BACKLIGHT_OFFROAD; } - smooth_brightness = clipped_brightness * k + smooth_brightness * (1.0f - k); - - int brightness = smooth_brightness; + int brightness = brightness_filter.update(clipped_brightness); if (!ui_state.awake) { brightness = 0; emit screen_shutoff(); @@ -321,7 +313,7 @@ void GLWindow::paintGL() { double cur_draw_t = millis_since_boot(); double dt = cur_draw_t - prev_draw_t; - if (dt > 66 && onroad){ + if (dt > 66 && onroad && !ui_state.scene.driver_view) { // warn on sub 15fps LOGW("slow frame(%llu) time: %.2f", ui_state.sm->frame, dt); } diff --git a/selfdrive/ui/qt/home.hpp b/selfdrive/ui/qt/home.hpp index f941c928aa..d19b9d60cb 100644 --- a/selfdrive/ui/qt/home.hpp +++ b/selfdrive/ui/qt/home.hpp @@ -9,8 +9,9 @@ #include #include -#include "qt_sound.hpp" +#include "sound.hpp" #include "ui/ui.hpp" +#include "common/util.h" #include "widgets/offroad_alerts.hpp" // container window for onroad NVG UI @@ -38,7 +39,7 @@ private: QTimer* timer; QTimer* backlight_timer; - QtSound sound; + Sound sound; bool onroad = true; double prev_draw_t = 0; @@ -46,8 +47,8 @@ private: // TODO: make a nice abstraction to handle embedded device stuff float brightness_b = 0; float brightness_m = 0; - float smooth_brightness = 0; float last_brightness = 0; + FirstOrderFilter brightness_filter; public slots: void timerUpdate(); diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index 2c93906347..5c539b55b6 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -2,14 +2,8 @@ #include #include #include -#include -#include -#include -#include "common/params.h" -#include "hardware/hw.h" #include "networking.hpp" -#include "util.h" void clearLayout(QLayout* layout) { while (QLayoutItem* item = layout->takeAt(0)) { @@ -23,12 +17,6 @@ void clearLayout(QLayout* layout) { } } -QWidget* layoutToWidget(QLayout* l, QWidget* parent){ - QWidget* q = new QWidget(parent); - q->setLayout(l); - return q; -} - // Networking functions Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), show_advanced(show_advanced){ @@ -61,9 +49,9 @@ void Networking::attemptInitialization(){ if (show_advanced) { QPushButton* advancedSettings = new QPushButton("Advanced"); - advancedSettings->setStyleSheet(R"(margin-right: 30px)"); + advancedSettings->setStyleSheet("margin-right: 30px;"); advancedSettings->setFixedSize(350, 100); - connect(advancedSettings, &QPushButton::released, [=](){s->setCurrentWidget(an);}); + connect(advancedSettings, &QPushButton::released, [=](){ s->setCurrentWidget(an); }); vlayout->addSpacing(10); vlayout->addWidget(advancedSettings, 0, Qt::AlignRight); vlayout->addSpacing(10); @@ -73,7 +61,8 @@ void Networking::attemptInitialization(){ connect(wifiWidget, SIGNAL(connectToNetwork(Network)), this, SLOT(connectToNetwork(Network))); vlayout->addWidget(wifiWidget, 1); - wifiScreen = layoutToWidget(vlayout, this); + QWidget* wifiScreen = new QWidget(this); + wifiScreen->setLayout(vlayout); s->addWidget(wifiScreen); an = new AdvancedNetworking(this, wifi); @@ -138,6 +127,7 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid QVBoxLayout* vlayout = new QVBoxLayout; vlayout->setMargin(40); + vlayout->setSpacing(20); // Back button QPushButton* back = new QPushButton("Back"); @@ -146,41 +136,24 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid vlayout->addWidget(back, 0, Qt::AlignLeft); // Enable tethering layout - QHBoxLayout* tetheringToggleLayout = new QHBoxLayout; - tetheringToggleLayout->addWidget(new QLabel("Enable tethering")); - Toggle* toggle_switch = new Toggle; - toggle_switch->setFixedSize(150, 100); - tetheringToggleLayout->addWidget(toggle_switch); - tetheringToggleLayout->addSpacing(40); - if (wifi->tetheringEnabled()) { - toggle_switch->togglePosition(); - } - QObject::connect(toggle_switch, SIGNAL(stateChanged(bool)), this, SLOT(toggleTethering(bool))); - vlayout->addWidget(layoutToWidget(tetheringToggleLayout, this), 0); + ToggleControl *tetheringToggle = new ToggleControl("Enable Tethering", "", "", wifi->tetheringEnabled()); + vlayout->addWidget(tetheringToggle); + QObject::connect(tetheringToggle, SIGNAL(toggleFlipped(bool)), this, SLOT(toggleTethering(bool))); vlayout->addWidget(horizontal_line(), 0); // Change tethering password - QHBoxLayout *tetheringPassword = new QHBoxLayout; - tetheringPassword->addWidget(new QLabel("Edit tethering password"), 1); - editPasswordButton = new QPushButton("EDIT"); - editPasswordButton->setFixedWidth(500); - connect(editPasswordButton, &QPushButton::released, [=](){ + editPasswordButton = new ButtonControl("Tethering Password", "EDIT", "", [=](){ QString pass = InputDialog::getText("Enter new tethering password", 8); if (pass.size()) { wifi->changeTetheringPassword(pass); } }); - tetheringPassword->addWidget(editPasswordButton, 1, Qt::AlignRight); - vlayout->addWidget(layoutToWidget(tetheringPassword, this), 0); + vlayout->addWidget(editPasswordButton, 0); vlayout->addWidget(horizontal_line(), 0); - // IP adress - QHBoxLayout* IPlayout = new QHBoxLayout; - IPlayout->addWidget(new QLabel("IP address"), 0); - ipLabel = new QLabel(wifi->ipv4_address); - ipLabel->setStyleSheet("color: #aaaaaa"); - IPlayout->addWidget(ipLabel, 0, Qt::AlignRight); - vlayout->addWidget(layoutToWidget(IPlayout, this), 0); + // IP address + ipLabel = new LabelControl("IP Address", wifi->ipv4_address); + vlayout->addWidget(ipLabel, 0); vlayout->addWidget(horizontal_line(), 0); // SSH keys @@ -188,6 +161,7 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid vlayout->addWidget(horizontal_line(), 0); vlayout->addWidget(new SshControl()); + vlayout->addStretch(1); setLayout(vlayout); } @@ -218,7 +192,6 @@ WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) vlayout->setSpacing(25); setLayout(vlayout); - page = 0; } void WifiUI::refresh() { @@ -229,70 +202,40 @@ void WifiUI::refresh() { connectButtons = new QButtonGroup(this); // TODO check if this is a leak QObject::connect(connectButtons, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(handleButton(QAbstractButton*))); - int networks_per_page = height() / 180; - int i = 0; - int pageCount = (wifi->seen_networks.size() - 1) / networks_per_page; - page = std::max(0, std::min(page, pageCount)); for (Network &network : wifi->seen_networks) { QHBoxLayout *hlayout = new QHBoxLayout; - if (page * networks_per_page <= i && i < (page + 1) * networks_per_page) { - // SSID - hlayout->addSpacing(50); - QString ssid = QString::fromUtf8(network.ssid); - if(ssid.length() > 20){ - ssid = ssid.left(20 - 3) + "…"; - } - - QLabel *ssid_label = new QLabel(ssid); - ssid_label->setStyleSheet(R"( - font-size: 55px; - )"); - ssid_label->setFixedWidth(this->width()*0.5); - hlayout->addWidget(ssid_label, 0, Qt::AlignLeft); - - // TODO: don't use images for this - // strength indicator - unsigned int strength_scale = network.strength / 17; - QPixmap pix("../assets/images/network_" + QString::number(strength_scale) + ".png"); - QLabel *icon = new QLabel(); - icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation)); - icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - hlayout->addWidget(icon, 0, Qt::AlignRight); - - // connect button - QPushButton* btn = new QPushButton(network.security_type == SecurityType::UNSUPPORTED ? "Unsupported" : (network.connected == ConnectedType::CONNECTED ? "Connected" : (network.connected == ConnectedType::CONNECTING ? "Connecting" : "Connect"))); - btn->setDisabled(network.connected == ConnectedType::CONNECTED || network.connected == ConnectedType::CONNECTING || network.security_type == SecurityType::UNSUPPORTED); - btn->setFixedWidth(350); - hlayout->addWidget(btn, 0, Qt::AlignRight); - - connectButtons->addButton(btn, i); - - vlayout->addLayout(hlayout, 1); - // Don't add the last horizontal line - if (page * networks_per_page <= i+1 && i+1 < (page + 1) * networks_per_page && i+1 < wifi->seen_networks.size()) { - vlayout->addWidget(horizontal_line(), 0); - } + hlayout->addSpacing(50); + + QLabel *ssid_label = new QLabel(QString::fromUtf8(network.ssid)); + ssid_label->setStyleSheet("font-size: 55px;"); + hlayout->addWidget(ssid_label, 1, Qt::AlignLeft); + + // TODO: don't use images for this + // strength indicator + unsigned int strength_scale = network.strength / 17; + QPixmap pix("../assets/images/network_" + QString::number(strength_scale) + ".png"); + QLabel *icon = new QLabel(); + icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation)); + icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + hlayout->addWidget(icon, 0, Qt::AlignRight); + + // connect button + QPushButton* btn = new QPushButton(network.security_type == SecurityType::UNSUPPORTED ? "Unsupported" : (network.connected == ConnectedType::CONNECTED ? "Connected" : (network.connected == ConnectedType::CONNECTING ? "Connecting" : "Connect"))); + btn->setDisabled(network.connected == ConnectedType::CONNECTED || network.connected == ConnectedType::CONNECTING || network.security_type == SecurityType::UNSUPPORTED); + btn->setFixedWidth(350); + hlayout->addWidget(btn, 0, Qt::AlignRight); + + connectButtons->addButton(btn, i); + + vlayout->addLayout(hlayout, 1); + // Don't add the last horizontal line + if (i+1 < wifi->seen_networks.size()) { + vlayout->addWidget(horizontal_line(), 0); } i++; } vlayout->addStretch(3); - - - // Setup buttons for pagination - QHBoxLayout *prev_next_buttons = new QHBoxLayout; - - QPushButton* prev = new QPushButton("Previous"); - prev->setEnabled(page); - QObject::connect(prev, SIGNAL(released()), this, SLOT(prevPage())); - prev_next_buttons->addWidget(prev); - - QPushButton* next = new QPushButton("Next"); - next->setEnabled(wifi->seen_networks.size() > (page + 1) * networks_per_page); - QObject::connect(next, SIGNAL(released()), this, SLOT(nextPage())); - prev_next_buttons->addWidget(next); - - vlayout->addLayout(prev_next_buttons, 2); } void WifiUI::handleButton(QAbstractButton* button) { @@ -300,13 +243,3 @@ void WifiUI::handleButton(QAbstractButton* button) { Network n = wifi->seen_networks[connectButtons->id(btn)]; emit connectToNetwork(n); } - -void WifiUI::prevPage() { - page--; - refresh(); -} - -void WifiUI::nextPage() { - page++; - refresh(); -} diff --git a/selfdrive/ui/qt/offroad/networking.hpp b/selfdrive/ui/qt/offroad/networking.hpp index fba7705074..1eaa413d4d 100644 --- a/selfdrive/ui/qt/offroad/networking.hpp +++ b/selfdrive/ui/qt/offroad/networking.hpp @@ -15,7 +15,6 @@ class WifiUI : public QWidget { Q_OBJECT public: - int page; explicit WifiUI(QWidget *parent = 0, WifiManager* wifi = 0); private: @@ -29,10 +28,8 @@ signals: void connectToNetwork(Network n); public slots: - void handleButton(QAbstractButton* m_button); void refresh(); - void prevPage(); - void nextPage(); + void handleButton(QAbstractButton* m_button); }; class AdvancedNetworking : public QWidget { @@ -41,8 +38,8 @@ public: explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0); private: - QLabel* ipLabel; - QPushButton* editPasswordButton; + LabelControl* ipLabel; + ButtonControl* editPasswordButton; WifiManager* wifi = nullptr; signals: @@ -60,7 +57,7 @@ public: explicit Networking(QWidget* parent = 0, bool show_advanced = true); private: - QStackedLayout* s = nullptr; // nm_warning, keyboard, wifiScreen, advanced + QStackedLayout* s = nullptr; // nm_warning, wifiScreen, advanced QWidget* wifiScreen = nullptr; AdvancedNetworking* an = nullptr; bool ui_setup_complete = false; diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc index 7fcae65aeb..8440e87357 100644 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ b/selfdrive/ui/qt/offroad/onboarding.cc @@ -12,14 +12,15 @@ void TrainingGuide::mouseReleaseEvent(QMouseEvent *e) { - //qDebug() << e->x() << ", " << e->y(); + QPoint touch = QPoint(e->x(), e->y()) - imageCorner; + //qDebug() << touch.x() << ", " << touch.y(); // Check for restart - if (currentIndex == (boundingBox.size() - 1) && 200 <= e->x() && e->x() <= 920 && - 760 <= e->y() && e->y() <= 960) { + if (currentIndex == (boundingBox.size() - 1) && 200 <= touch.x() && touch.x() <= 920 && + 760 <= touch.y() && touch.y() <= 960) { currentIndex = 0; - } else if (boundingBox[currentIndex][0] <= e->x() && e->x() <= boundingBox[currentIndex][1] && - boundingBox[currentIndex][2] <= e->y() && e->y() <= boundingBox[currentIndex][3]) { + } else if (boundingBox[currentIndex][0] <= touch.x() && touch.x() <= boundingBox[currentIndex][1] && + boundingBox[currentIndex][2] <= touch.y() && touch.y() <= boundingBox[currentIndex][3]) { currentIndex += 1; } @@ -39,17 +40,17 @@ void TrainingGuide::showEvent(QShowEvent *event) { void TrainingGuide::paintEvent(QPaintEvent *event) { QPainter painter(this); - QRect devRect(0, 0, painter.device()->width(), painter.device()->height()); - QBrush bgBrush("#072339"); - painter.fillRect(devRect, bgBrush); + QRect bg(0, 0, painter.device()->width(), painter.device()->height()); + QBrush bgBrush("#000000"); + painter.fillRect(bg, bgBrush); QRect rect(image.rect()); - rect.moveCenter(devRect.center()); + rect.moveCenter(bg.center()); painter.drawImage(rect.topLeft(), image); + imageCorner = rect.topLeft(); } TermsPage::TermsPage(QWidget *parent) : QFrame(parent){ - QVBoxLayout *main_layout = new QVBoxLayout; main_layout->setMargin(40); main_layout->setSpacing(40); @@ -126,13 +127,13 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { addWidget(terms); connect(terms, &TermsPage::acceptedTerms, [=](){ - Params().write_db_value("HasAcceptedTerms", current_terms_version); + Params().put("HasAcceptedTerms", current_terms_version); updateActiveScreen(); }); TrainingGuide* tr = new TrainingGuide(this); connect(tr, &TrainingGuide::completedTraining, [=](){ - Params().write_db_value("CompletedTrainingVersion", current_training_version); + Params().put("CompletedTrainingVersion", current_training_version); updateActiveScreen(); }); addWidget(tr); diff --git a/selfdrive/ui/qt/offroad/onboarding.hpp b/selfdrive/ui/qt/offroad/onboarding.hpp index eb067478cf..227090fd3a 100644 --- a/selfdrive/ui/qt/offroad/onboarding.hpp +++ b/selfdrive/ui/qt/offroad/onboarding.hpp @@ -22,6 +22,7 @@ protected: private: QImage image; + QPoint imageCorner; int currentIndex = 0; // Bounding boxes for the a given training guide step diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 47f5903f93..bd3611c8e0 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -15,12 +15,11 @@ #include "common/params.h" #include "common/util.h" #include "selfdrive/hardware/hw.h" - +#include "home.hpp" QWidget * toggles_panel() { QVBoxLayout *toggles_list = new QVBoxLayout(); - toggles_list->setMargin(50); toggles_list->addWidget(new ParamControl("OpenpilotEnabledToggle", "Enable openpilot", "Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.", @@ -62,7 +61,7 @@ QWidget * toggles_panel() { "In this mode openpilot will ignore lanelines and just drive how it thinks a human would.", "../assets/offroad/icon_road.png")); - bool record_lock = Params().read_db_bool("RecordFrontLock"); + bool record_lock = Params().getBool("RecordFrontLock"); record_toggle->setEnabled(!record_lock); QWidget *widget = new QWidget; @@ -72,63 +71,53 @@ QWidget * toggles_panel() { DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { QVBoxLayout *device_layout = new QVBoxLayout; - device_layout->setMargin(100); Params params = Params(); - std::vector> labels = { - {"Dongle ID", params.get("DongleId", false)}, - }; - - // get serial number - //std::string cmdline = util::read_file("/proc/cmdline"); - //auto delim = cmdline.find("serialno="); - //if (delim != std::string::npos) { - // labels.push_back({"Serial", cmdline.substr(delim, cmdline.find(" ", delim))}); - //} - - for (auto &l : labels) { - device_layout->addWidget(new LabelControl(QString::fromStdString(l.first), - QString::fromStdString(l.second))); - } + QString dongle = QString::fromStdString(params.get("DongleId", false)); + device_layout->addWidget(new LabelControl("Dongle ID", dongle)); device_layout->addWidget(horizontal_line()); - device_layout->addWidget(new ButtonControl("Driver Camera", "PREVIEW", - "Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off)", - [=]() { Params().write_db_value("IsDriverViewEnabled", "1", 1); })); + QString serial = QString::fromStdString(params.get("HardwareSerial", false)); + device_layout->addWidget(new LabelControl("Serial", serial)); - device_layout->addWidget(horizontal_line()); + // offroad-only buttons + QList offroad_btns; - // TODO: show current calibration values - device_layout->addWidget(new ButtonControl("Reset Calibration", "RESET", - "openpilot requires the device to be mounted within 4° left or right and within 5° up or down. openpilot is continuously calibrating, resetting is rarely required.", - [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to reset calibration?")) { - Params().delete_db_value("CalibrationParams"); - } - })); + offroad_btns.append(new ButtonControl("Driver Camera", "PREVIEW", + "Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off)", + [=]() { + Params().putBool("IsDriverViewEnabled", true); + GLWindow::ui_state.scene.driver_view = true; } + )); - device_layout->addWidget(horizontal_line()); + offroad_btns.append(new ButtonControl("Reset Calibration", "RESET", + "openpilot requires the device to be mounted within 4° left or right and within 5° up or down. openpilot is continuously calibrating, resetting is rarely required.", [=]() { + if (ConfirmationDialog::confirm("Are you sure you want to reset calibration?")) { + Params().remove("CalibrationParams"); + } + })); - device_layout->addWidget(new ButtonControl("Review Training Guide", "REVIEW", - "Review the rules, features, and limitations of openpilot", - [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to review the training guide?")) { - Params().delete_db_value("CompletedTrainingVersion"); - emit reviewTrainingGuide(); - } - })); + offroad_btns.append(new ButtonControl("Review Training Guide", "REVIEW", + "Review the rules, features, and limitations of openpilot", [=]() { + if (ConfirmationDialog::confirm("Are you sure you want to review the training guide?")) { + Params().remove("CompletedTrainingVersion"); + emit reviewTrainingGuide(); + } + })); - device_layout->addWidget(horizontal_line()); + QString brand = params.getBool("Passive") ? "dashcam" : "openpilot"; + offroad_btns.append(new ButtonControl("Uninstall " + brand, "UNINSTALL", "", [=]() { + if (ConfirmationDialog::confirm("Are you sure you want to uninstall?")) { + Params().putBool("DoUninstall", true); + } + })); - QString brand = params.read_db_bool("Passive") ? "dashcam" : "openpilot"; - device_layout->addWidget(new ButtonControl("Uninstall " + brand, "UNINSTALL", - "", - [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to uninstall?")) { - Params().write_db_value("DoUninstall", "1"); - } - })); + for(auto &btn : offroad_btns){ + device_layout->addWidget(horizontal_line()); + QObject::connect(parent, SIGNAL(offroadTransition(bool)), btn, SLOT(setEnabled(bool))); + device_layout->addWidget(btn); + } // power buttons QHBoxLayout *power_layout = new QHBoxLayout(); @@ -166,16 +155,15 @@ DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { DeveloperPanel::DeveloperPanel(QWidget* parent) : QFrame(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(100); setLayout(main_layout); setStyleSheet(R"(QLabel {font-size: 50px;})"); } void DeveloperPanel::showEvent(QShowEvent *event) { Params params = Params(); - std::string brand = params.read_db_bool("Passive") ? "dashcam" : "openpilot"; + std::string brand = params.getBool("Passive") ? "dashcam" : "openpilot"; QList> dev_params = { - {"Version", brand + " v" + params.get("Version", false)}, + {"Version", brand + " v" + params.get("Version", false).substr(0, 14)}, {"Git Branch", params.get("GitBranch", false)}, {"Git Commit", params.get("GitCommit", false).substr(0, 10)}, {"Panda Firmware", params.get("PandaFirmwareHex", false)}, @@ -200,25 +188,15 @@ void DeveloperPanel::showEvent(QShowEvent *event) { QWidget * network_panel(QWidget * parent) { #ifdef QCOM QVBoxLayout *layout = new QVBoxLayout; - layout->setMargin(100); layout->setSpacing(30); - // simple wifi + tethering buttons - const char* launch_wifi = "am start -n com.android.settings/.wifi.WifiPickerActivity \ - -a android.net.wifi.PICK_WIFI_NETWORK \ - --ez extra_prefs_show_button_bar true \ - --es extra_prefs_set_next_text ''"; + // wifi + tethering buttons layout->addWidget(new ButtonControl("WiFi Settings", "OPEN", "", - [=]() { std::system(launch_wifi); })); - + [=]() { HardwareEon::launch_wifi(); })); layout->addWidget(horizontal_line()); - const char* launch_tethering = "am start -n com.android.settings/.TetherSettings \ - --ez extra_prefs_show_button_bar true \ - --es extra_prefs_set_next_text ''"; layout->addWidget(new ButtonControl("Tethering Settings", "OPEN", "", - [=]() { std::system(launch_tethering); })); - + [=]() { HardwareEon::launch_tethering(); })); layout->addWidget(horizontal_line()); // SSH key management @@ -241,6 +219,10 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { QVBoxLayout *sidebar_layout = new QVBoxLayout(); sidebar_layout->setMargin(0); panel_widget = new QStackedWidget(); + panel_widget->setStyleSheet(R"( + border-radius: 30px; + background-color: #292929; + )"); // close button QPushButton *close_btn = new QPushButton("X"); @@ -273,7 +255,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { QPushButton *btn = new QPushButton(name); btn->setCheckable(true); btn->setStyleSheet(R"( - * { + QPushButton { color: grey; border: none; background: none; @@ -290,8 +272,25 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { nav_btns->addButton(btn); sidebar_layout->addWidget(btn, 0, Qt::AlignRight); - panel_widget->addWidget(panel); - QObject::connect(btn, &QPushButton::released, [=, w = panel]() { + panel->setContentsMargins(50, 25, 50, 25); + QScrollArea *panel_frame = new QScrollArea; + panel_frame->setWidget(panel); + panel_frame->setWidgetResizable(true); + panel_frame->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + panel_frame->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + panel_frame->setStyleSheet("background-color:transparent;"); + + QScroller *scroller = QScroller::scroller(panel_frame->viewport()); + auto sp = scroller->scrollerProperties(); + + sp.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); + + scroller->grabGesture(panel_frame->viewport(), QScroller::LeftMouseButtonGesture); + scroller->setScrollerProperties(sp); + + panel_widget->addWidget(panel_frame); + + QObject::connect(btn, &QPushButton::released, [=, w = panel_frame]() { panel_widget->setCurrentWidget(w); }); } @@ -305,25 +304,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { sidebar_widget->setLayout(sidebar_layout); sidebar_widget->setFixedWidth(500); settings_layout->addWidget(sidebar_widget); - - panel_frame = new QScrollArea; - panel_frame->setWidget(panel_widget); - panel_frame->setWidgetResizable(true); - panel_frame->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - panel_frame->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - panel_frame->setStyleSheet(R"( - border-radius: 30px; - background-color: #292929; - )"); - settings_layout->addWidget(panel_frame); - - // setup panel scrolling - QScroller *scroller = QScroller::scroller(panel_frame); - auto sp = scroller->scrollerProperties(); - sp.setScrollMetric(QScrollerProperties::FrameRate, QVariant::fromValue(QScrollerProperties::Fps30)); - sp.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); - scroller->setScrollerProperties(sp); - scroller->grabGesture(panel_frame->viewport(), QScroller::LeftMouseButtonGesture); + settings_layout->addWidget(panel_widget); setLayout(settings_layout); setStyleSheet(R"( diff --git a/selfdrive/ui/qt/offroad/settings.hpp b/selfdrive/ui/qt/offroad/settings.hpp index 1a26293116..2dee5b62d1 100644 --- a/selfdrive/ui/qt/offroad/settings.hpp +++ b/selfdrive/ui/qt/offroad/settings.hpp @@ -39,6 +39,7 @@ public: signals: void closeSettings(); + void offroadTransition(bool offroad); void reviewTrainingGuide(); private: @@ -46,5 +47,4 @@ private: QWidget *sidebar_widget; QButtonGroup *nav_btns; QStackedWidget *panel_widget; - QScrollArea *panel_frame; }; diff --git a/selfdrive/ui/qt/qt_sound.hpp b/selfdrive/ui/qt/qt_sound.hpp deleted file mode 100644 index da84c23be1..0000000000 --- a/selfdrive/ui/qt/qt_sound.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include "sound.hpp" - -class QtSound : public Sound { -public: - QtSound(); - bool play(AudibleAlert alert); - void stop(); - void setVolume(int volume); - float volume = 0; - -private: - std::map sounds; -}; diff --git a/selfdrive/ui/qt/qt_sound.cc b/selfdrive/ui/qt/sound.cc similarity index 71% rename from selfdrive/ui/qt/qt_sound.cc rename to selfdrive/ui/qt/sound.cc index ee04785748..641ffb22a5 100644 --- a/selfdrive/ui/qt/qt_sound.cc +++ b/selfdrive/ui/qt/sound.cc @@ -1,22 +1,21 @@ #include -#include "qt_sound.hpp" +#include "sound.hpp" -QtSound::QtSound() { +Sound::Sound() { for (auto &kv : sound_map) { auto path = QUrl::fromLocalFile(kv.second.first); sounds[kv.first].setSource(path); } } -bool QtSound::play(AudibleAlert alert) { +void Sound::play(AudibleAlert alert) { int loops = sound_map[alert].second> - 1 ? sound_map[alert].second : QSoundEffect::Infinite; sounds[alert].setLoopCount(loops); sounds[alert].setVolume(volume); sounds[alert].play(); - return true; } -void QtSound::stop() { +void Sound::stop() { for (auto &kv : sounds) { // Only stop repeating sounds if (sound_map[kv.first].second != 0) { @@ -24,7 +23,3 @@ void QtSound::stop() { } } } - -void QtSound::setVolume(int volume) { - // TODO: implement this -} diff --git a/selfdrive/ui/sound.hpp b/selfdrive/ui/qt/sound.hpp similarity index 84% rename from selfdrive/ui/sound.hpp rename to selfdrive/ui/qt/sound.hpp index ab83a0180d..cee1ea51ae 100644 --- a/selfdrive/ui/sound.hpp +++ b/selfdrive/ui/qt/sound.hpp @@ -1,5 +1,7 @@ #pragma once + #include +#include #include "cereal/gen/cpp/log.capnp.h" typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; @@ -18,8 +20,11 @@ static std::map> sound_map { class Sound { public: - virtual ~Sound() {} - virtual bool play(AudibleAlert alert) = 0; - virtual void stop() = 0; - virtual void setVolume(int volume) = 0; + Sound(); + void play(AudibleAlert alert); + void stop(); + float volume = 0; + +private: + std::map sounds; }; diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index a6f0812911..d9c170e27e 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -20,7 +20,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons hlayout = new QHBoxLayout; hlayout->setMargin(0); - hlayout->setSpacing(50); + hlayout->setSpacing(20); // left icon if (!icon.isEmpty()) { @@ -33,7 +33,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons // title title_label = new QPushButton(title); - title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; background: none;"); + title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left;"); hlayout->addWidget(title_label); vlayout->addLayout(hlayout); @@ -53,4 +53,5 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons } setLayout(vlayout); + setStyleSheet("background-color: transparent;"); } diff --git a/selfdrive/ui/qt/widgets/controls.hpp b/selfdrive/ui/qt/widgets/controls.hpp index 6066159ef2..b87299a59a 100644 --- a/selfdrive/ui/qt/widgets/controls.hpp +++ b/selfdrive/ui/qt/widgets/controls.hpp @@ -53,12 +53,17 @@ public: ButtonControl(const QString &title, const QString &text, const QString &desc, Functor functor, const QString &icon = "", QWidget *parent = nullptr) : AbstractControl(title, desc, icon, parent) { btn.setText(text); btn.setStyleSheet(R"( - padding: 0; - border-radius: 50px; - font-size: 35px; - font-weight: 500; - color: #E4E4E4; - background-color: #393939; + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:disabled { + color: #33E4E4E4; + } )"); btn.setFixedSize(250, 100); QObject::connect(&btn, &QPushButton::released, functor); @@ -66,6 +71,11 @@ public: } void setText(const QString &text) { btn.setText(text); } +public slots: + void setEnabled(bool enabled) { + btn.setEnabled(enabled); + }; + private: QPushButton btn; }; @@ -99,12 +109,11 @@ class ParamControl : public ToggleControl { public: ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, parent) { // set initial state from param - if (Params().read_db_bool(param.toStdString().c_str())) { + if (Params().getBool(param.toStdString().c_str())) { toggle.togglePosition(); } QObject::connect(this, &ToggleControl::toggleFlipped, [=](int state) { - char value = state ? '1' : '0'; - Params().write_db_value(param.toStdString().c_str(), &value, 1); + Params().putBool(param.toStdString().c_str(), (bool)state); }); } }; diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc index 7cbcc0aabd..83fca7a74c 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.cc +++ b/selfdrive/ui/qt/widgets/drive_stats.cc @@ -36,7 +36,7 @@ void DriveStats::parseResponse(QString response) { labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); }; - bool metric = Params().read_db_bool("IsMetric"); + bool metric = Params().getBool("IsMetric"); QJsonObject json = doc.object(); update(json["all"].toObject(), all_, metric); update(json["week"].toObject(), week_, metric); @@ -51,7 +51,7 @@ DriveStats::DriveStats(QWidget* parent) : QWidget(parent) { gl->addLayout(build_stat_layout(&labels.hours, "HOURS"), row, 2, 3, 1); }; - const char* distance_unit = Params().read_db_bool("IsMetric") ? "KM" : "MILES"; + const char* distance_unit = Params().getBool("IsMetric") ? "KM" : "MILES"; QGridLayout* gl = new QGridLayout(); gl->setMargin(0); gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3); diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc index cd1173722a..596586f583 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ b/selfdrive/ui/qt/widgets/offroad_alerts.cc @@ -1,47 +1,52 @@ -#include -#include #include #include #include #include -#include #include "offroad_alerts.hpp" -#include "common/params.h" #include "selfdrive/hardware/hw.h" - -void cleanStackedWidget(QStackedWidget* swidget) { - while(swidget->count() > 0) { - QWidget *w = swidget->widget(0); - swidget->removeWidget(w); - w->deleteLater(); - } -} +#include "selfdrive/common/util.h" OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(); - main_layout->setMargin(25); + QVBoxLayout *layout = new QVBoxLayout(); + layout->setMargin(50); + + // setup labels for each alert + QString json = QString::fromStdString(util::read_file("../controls/lib/alerts_offroad.json")); + QJsonObject obj = QJsonDocument::fromJson(json.toUtf8()).object(); + for (auto &k : obj.keys()) { + QLabel *l = new QLabel(this); + alerts[k.toStdString()] = l; + int severity = obj[k].toObject()["severity"].toInt(); + + l->setMargin(60); + l->setWordWrap(true); + l->setStyleSheet("background-color: " + QString(severity ? "#E22C2C" : "#292929")); + l->setVisible(false); + layout->addWidget(l); + } - alerts_stack = new QStackedWidget(); - main_layout->addWidget(alerts_stack, 1); + // release notes + releaseNotes.setVisible(false); + releaseNotes.setStyleSheet("font-size: 48px;"); + layout->addWidget(&releaseNotes); - // bottom footer + // bottom footer, dismiss + reboot buttons QHBoxLayout *footer_layout = new QHBoxLayout(); - main_layout->addLayout(footer_layout); + layout->addLayout(footer_layout); QPushButton *dismiss_btn = new QPushButton("Dismiss"); dismiss_btn->setFixedSize(400, 125); - footer_layout->addWidget(dismiss_btn, 0, Qt::AlignLeft); - - reboot_btn = new QPushButton("Reboot and Update"); - reboot_btn->setFixedSize(600, 125); - reboot_btn->setVisible(false); - footer_layout->addWidget(reboot_btn, 0, Qt::AlignRight); - + footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft); QObject::connect(dismiss_btn, SIGNAL(released()), this, SIGNAL(closeAlerts())); - QObject::connect(reboot_btn, &QPushButton::released, [=]() { Hardware::reboot(); }); - setLayout(main_layout); + rebootBtn.setText("Reboot and Update"); + rebootBtn.setFixedSize(600, 125); + rebootBtn.setVisible(false); + footer_layout->addWidget(&rebootBtn, 0, Qt::AlignBottom | Qt::AlignRight); + QObject::connect(&rebootBtn, &QPushButton::released, [=]() { Hardware::reboot(); }); + + setLayout(layout); setStyleSheet(R"( * { font-size: 48px; @@ -58,54 +63,33 @@ OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) { background-color: white; } )"); - main_layout->setMargin(50); - QFile inFile("../controls/lib/alerts_offroad.json"); - bool ret = inFile.open(QIODevice::ReadOnly | QIODevice::Text); - assert(ret); - QJsonDocument doc = QJsonDocument::fromJson(inFile.readAll()); - assert(!doc.isNull()); - alert_keys = doc.object().keys(); } void OffroadAlert::refresh() { - parse_alerts(); - cleanStackedWidget(alerts_stack); - - updateAvailable = Params().read_db_bool("UpdateAvailable"); - reboot_btn->setVisible(updateAvailable); + updateAlerts(); - QVBoxLayout *layout = new QVBoxLayout; - layout->setSpacing(20); + rebootBtn.setVisible(updateAvailable); + releaseNotes.setVisible(updateAvailable); + releaseNotes.setText(QString::fromStdString(params.get("ReleaseNotes"))); - if (updateAvailable) { - QLabel *body = new QLabel(QString::fromStdString(Params().get("ReleaseNotes"))); - body->setStyleSheet(R"(font-size: 48px;)"); - layout->addWidget(body, 0, Qt::AlignLeft | Qt::AlignTop); - } else { - for (const auto &alert : alerts) { - QLabel *l = new QLabel(alert.text); - l->setMargin(60); - l->setWordWrap(true); - l->setStyleSheet("background-color: " + QString(alert.severity ? "#E22C2C" : "#292929")); - layout->addWidget(l, 0, Qt::AlignTop); - } + for (const auto& [k, label] : alerts) { + label->setVisible(!updateAvailable && !label->text().isEmpty()); } - - QWidget *w = new QWidget(); - w->setLayout(layout); - alerts_stack->addWidget(w); } -void OffroadAlert::parse_alerts() { - alerts.clear(); - for (const QString &key : alert_keys) { - std::vector bytes = Params().read_db_bytes(key.toStdString().c_str()); +void OffroadAlert::updateAlerts() { + alertCount = 0; + updateAvailable = params.getBool("UpdateAvailable"); + for (const auto& [key, label] : alerts) { + auto bytes = params.get(key.c_str()); if (bytes.size()) { QJsonDocument doc_par = QJsonDocument::fromJson(QByteArray(bytes.data(), bytes.size())); QJsonObject obj = doc_par.object(); - Alert alert = {obj.value("text").toString(), obj.value("severity").toInt()}; - alerts.push_back(alert); + label->setText(obj.value("text").toString()); + alertCount++; + } else { + label->setText(""); } } } diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.hpp b/selfdrive/ui/qt/widgets/offroad_alerts.hpp index ec48f89c7e..b05d68d334 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.hpp +++ b/selfdrive/ui/qt/widgets/offroad_alerts.hpp @@ -1,28 +1,26 @@ #pragma once +#include #include -#include #include -#include +#include -struct Alert { - QString text; - int severity; -}; +#include "common/params.h" class OffroadAlert : public QFrame { Q_OBJECT public: explicit OffroadAlert(QWidget *parent = 0); - QVector alerts; - QStringList alert_keys; + int alertCount = 0; bool updateAvailable; private: - QStackedWidget *alerts_stack; - QPushButton *reboot_btn; - void parse_alerts(); + Params params; + QLabel releaseNotes; + std::map alerts; + QPushButton rebootBtn; + void updateAlerts(); signals: void closeAlerts(); diff --git a/selfdrive/ui/qt/widgets/ssh_keys.cc b/selfdrive/ui/qt/widgets/ssh_keys.cc index c3c1ad9ec2..b0266f6336 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.cc +++ b/selfdrive/ui/qt/widgets/ssh_keys.cc @@ -1,12 +1,19 @@ #include - +#include #include "widgets/input.hpp" #include "widgets/ssh_keys.hpp" #include "common/params.h" SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username.", "") { + // setup widget + hlayout->addStretch(1); + + username_label.setAlignment(Qt::AlignVCenter); + username_label.setStyleSheet("color: #aaaaaa"); + hlayout->addWidget(&username_label); + btn.setStyleSheet(R"( padding: 0; border-radius: 50px; @@ -27,7 +34,8 @@ SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH getUserKeys(username); } } else { - Params().delete_db_value("GithubSshKeys"); + Params().remove("GithubUsername"); + Params().remove("GithubSshKeys"); refresh(); } }); @@ -45,8 +53,10 @@ SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH void SshControl::refresh() { QString param = QString::fromStdString(Params().get("GithubSshKeys")); if (param.length()) { + username_label.setText(QString::fromStdString(Params().get("GithubUsername"))); btn.setText("REMOVE"); } else { + username_label.setText(""); btn.setText("ADD"); } btn.setEnabled(true); @@ -79,7 +89,8 @@ void SshControl::parseResponse(){ networkTimer->stop(); QString response = reply->readAll(); if (reply->error() == QNetworkReply::NoError && response.length()) { - Params().write_db_value("GithubSshKeys", response.toStdString()); + Params().put("GithubUsername", username.toStdString()); + Params().put("GithubSshKeys", response.toStdString()); } else if(reply->error() == QNetworkReply::NoError){ err = "Username '" + username + "' has no keys on GitHub"; } else { diff --git a/selfdrive/ui/qt/widgets/ssh_keys.hpp b/selfdrive/ui/qt/widgets/ssh_keys.hpp index c55249c0d5..24deee9534 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.hpp +++ b/selfdrive/ui/qt/widgets/ssh_keys.hpp @@ -29,6 +29,7 @@ public: private: QPushButton btn; QString username; + QLabel username_label; // networking QTimer* networkTimer; diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index 0a783b57b8..c88a47dd94 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -1,4 +1,5 @@ #include "window.hpp" +#include "selfdrive/hardware/hw.h" MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { main_layout = new QStackedLayout; @@ -16,6 +17,7 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { QObject::connect(homeWindow, SIGNAL(openSettings()), this, SLOT(openSettings())); QObject::connect(homeWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings())); QObject::connect(homeWindow, SIGNAL(offroadTransition(bool)), this, SLOT(offroadTransition(bool))); + QObject::connect(homeWindow, SIGNAL(offroadTransition(bool)), settingsWindow, SIGNAL(offroadTransition(bool))); QObject::connect(settingsWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings())); QObject::connect(settingsWindow, SIGNAL(reviewTrainingGuide()), this, SLOT(reviewTrainingGuide())); @@ -54,8 +56,20 @@ void MainWindow::reviewTrainingGuide() { } bool MainWindow::eventFilter(QObject *obj, QEvent *event){ + // wake screen on tap if (event->type() == QEvent::MouseButtonPress) { homeWindow->glWindow->wake(); } + + // filter out touches while in android activity +#ifdef QCOM + const QList filter_events = {QEvent::MouseButtonPress, QEvent::MouseMove, QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd}; + if (HardwareEon::launched_activity && filter_events.contains(event->type())) { + HardwareEon::check_activity(); + if (HardwareEon::launched_activity) { + return true; + } + } +#endif return false; } diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 2d268f7955..96c1dcbfc4 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -10,13 +10,6 @@ #include "ui.hpp" #include "paint.hpp" - -int write_param_float(float param, const char* param_name, bool persistent_param) { - char s[16]; - int size = snprintf(s, sizeof(s), "%f", param); - return Params(persistent_param).write_db_value(param_name, s, size < sizeof(s) ? size : sizeof(s)); -} - // Projects a point in car to space to the corresponding point in full frame // image space. static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, float in_z, vertex_data *out) { @@ -205,11 +198,6 @@ static void update_sockets(UIState *s) { } if (sm.updated("driverMonitoringState")) { scene.dmonitoring_state = sm["driverMonitoringState"].getDriverMonitoringState(); - if(!scene.driver_view && !scene.ignition) { - read_param(&scene.driver_view, "IsDriverViewEnabled"); - } - } else if ((sm.frame - sm.rcv_frame("driverMonitoringState")) > UI_FREQ/2) { - scene.driver_view = false; } if (sm.updated("sensorEvents")) { for (auto sensor : sm["sensorEvents"].getSensorEvents()) { @@ -284,14 +272,13 @@ static void update_alert(UIState *s) { static void update_params(UIState *s) { const uint64_t frame = s->sm->frame; UIScene &scene = s->scene; - + Params params; if (frame % (5*UI_FREQ) == 0) { - read_param(&scene.is_metric, "IsMetric"); + scene.is_metric = params.getBool("IsMetric"); } else if (frame % (6*UI_FREQ) == 0) { scene.athenaStatus = NET_DISCONNECTED; - uint64_t last_ping = 0; - if (read_param(&last_ping, "LastAthenaPingTime") == 0) { - scene.athenaStatus = nanos_since_boot() - last_ping < 70e9 ? NET_CONNECTED : NET_ERROR; + if (auto last_ping = params.get("LastAthenaPingTime"); last_ping) { + scene.athenaStatus = nanos_since_boot() - *last_ping < 70e9 ? NET_CONNECTED : NET_ERROR; } } } @@ -334,8 +321,8 @@ static void update_status(UIState *s) { s->status = STATUS_DISENGAGED; s->scene.started_frame = s->sm->frame; - read_param(&s->scene.is_rhd, "IsRHD"); - read_param(&s->scene.end_to_end, "EndToEndToggle"); + s->scene.is_rhd = Params().getBool("IsRHD"); + s->scene.end_to_end = Params().getBool("EndToEndToggle"); s->sidebar_collapsed = true; s->scene.alert_size = cereal::ControlsState::AlertSize::NONE; s->vipc_client = s->scene.driver_view ? s->vipc_client_front : s->vipc_client_rear; diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp index e5e8790b1a..2f0134eb9c 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.hpp @@ -25,7 +25,7 @@ #include "common/params.h" #include "common/glutil.h" #include "common/transformations/orientation.hpp" -#include "sound.hpp" +#include "qt/sound.hpp" #include "visionipc.h" #include "visionipc_client.h" @@ -171,28 +171,3 @@ typedef struct UIState { void ui_init(UIState *s); void ui_update(UIState *s); - -int write_param_float(float param, const char* param_name, bool persistent_param = false); -template -int read_param(T* param, const char *param_name, bool persistent_param = false){ - T param_orig = *param; - char *value; - size_t sz; - - int result = Params(persistent_param).read_db_value(param_name, &value, &sz); - if (result == 0){ - std::string s = std::string(value, sz); // value is not null terminated - free(value); - - // Parse result - std::istringstream iss(s); - iss >> *param; - - // Restore original value if parsing failed - if (iss.fail()) { - *param = param_orig; - result = -1; - } - } - return result; -} diff --git a/tools/lib/route.py b/tools/lib/route.py index 7b65897d6c..ef90f89231 100644 --- a/tools/lib/route.py +++ b/tools/lib/route.py @@ -12,6 +12,7 @@ EXPLORER_FILE_RE = r'^({})--([a-z]+\.[a-z0-9]+)$'.format(SEGMENT_NAME_RE) OP_SEGMENT_DIR_RE = r'^({})$'.format(SEGMENT_NAME_RE) QLOG_FILENAMES = ['qlog.bz2'] +QCAMERA_FILENAMES = ['qcamera.ts'] LOG_FILENAMES = ['rlog.bz2', 'raw_log.bz2'] CAMERA_FILENAMES = ['fcamera.hevc', 'video.hevc'] @@ -40,6 +41,10 @@ class Route(object): camera_path_by_seg_num = {s.canonical_name.segment_num: s.camera_path for s in self._segments} return [camera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] + def qcamera_paths(self): + qcamera_path_by_seg_num = {s.canonical_name.segment_num: s.qcamera_path for s in self._segments} + return [qcamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] + def _get_segments_remote(self): api = CommaApi(get_token()) route_files = api.get('v1/route/' + self.route_name + '/files') @@ -53,14 +58,16 @@ class Route(object): segment_name, url if fn in LOG_FILENAMES else segments[segment_name].log_path, url if fn in QLOG_FILENAMES else segments[segment_name].qlog_path, - url if fn in CAMERA_FILENAMES else segments[segment_name].camera_path + url if fn in CAMERA_FILENAMES else segments[segment_name].camera_path, + url if fn in QCAMERA_FILENAMES else segments[segment_name].qcamera_path, ) else: segments[segment_name] = RouteSegment( segment_name, url if fn in LOG_FILENAMES else None, url if fn in QLOG_FILENAMES else None, - url if fn in CAMERA_FILENAMES else None + url if fn in CAMERA_FILENAMES else None, + url if fn in QCAMERA_FILENAMES else None, ) return sorted(segments.values(), key=lambda seg: seg.canonical_name.segment_num) @@ -110,18 +117,24 @@ class Route(object): except StopIteration: camera_path = None - segments.append(RouteSegment(segment, log_path, qlog_path, camera_path)) + try: + qcamera_path = next(path for path, filename in files if filename in QCAMERA_FILENAMES) + except StopIteration: + qcamera_path = None + + segments.append(RouteSegment(segment, log_path, qlog_path, camera_path, qcamera_path)) if len(segments) == 0: raise ValueError('Could not find segments for route {} in data directory {}'.format(self.route_name, data_dir)) return sorted(segments, key=lambda seg: seg.canonical_name.segment_num) class RouteSegment(object): - def __init__(self, name, log_path, qlog_path, camera_path): + def __init__(self, name, log_path, qlog_path, camera_path, qcamera_path): self._name = RouteSegmentName(name) self.log_path = log_path self.qlog_path = qlog_path self.camera_path = camera_path + self.qcamera_path = qcamera_path @property def name(self): diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 62a9b63f2a..1ad6455405 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -43,6 +43,7 @@ sudo apt-get update && sudo apt-get install -y \ opencl-headers \ python-dev \ python3-pip \ + qml-module-qtquick2 \ qt5-default \ qtmultimedia5-dev \ qtwebengine5-dev \