From 6418d4a09a8559dfe326e2927c0a51690f07527f Mon Sep 17 00:00:00 2001 From: Vehicle Researcher Date: Sat, 15 May 2021 01:20:48 +0000 Subject: [PATCH] openpilot v0.8.4 release --- .gitignore | 2 + Jenkinsfile | 51 +- README.md | 39 +- RELEASES.md | 10 + SConstruct | 71 +- cereal/SConscript | 9 +- cereal/car.capnp | 9 +- cereal/log.capnp | 7 +- cereal/messaging/__init__.py | 44 +- cereal/messaging/bridge.cc | 4 +- cereal/messaging/impl_msgq.cc | 6 +- .../messaging/{impl_msgq.hpp => impl_msgq.h} | 5 +- cereal/messaging/impl_zmq.cc | 7 +- cereal/messaging/{impl_zmq.hpp => impl_zmq.h} | 3 +- cereal/messaging/messaging.cc | 6 +- .../messaging/{messaging.hpp => messaging.h} | 7 +- cereal/messaging/messaging.pxd | 3 +- cereal/messaging/messaging_pyx.pyx | 3 + cereal/messaging/msgq.cc | 12 +- cereal/messaging/{msgq.hpp => msgq.h} | 2 + cereal/messaging/socketmaster.cc | 63 +- cereal/services.py | 105 +-- cereal/visionipc/visionipc_client.h | 2 +- cereal/visionipc/visionipc_server.cc | 2 +- cereal/visionipc/visionipc_server.h | 2 +- common/SConscript | 4 +- common/params.py | 3 +- common/params_pxd.pxd | 15 +- common/params_pyx.pyx | 124 +--- common/transformations/coordinates.cc | 2 - common/transformations/coordinates.hpp | 6 + common/transformations/orientation.cc | 3 +- installer/updater/updater | Bin 2501400 -> 2513688 bytes installer/updater/updater.cc | 53 +- launch_chffrplus.sh | 3 + launch_env.sh | 2 +- opendbc/can/parser.cc | 2 + opendbc/can/parser_pyx.pyx | 17 +- ...honda_civic_touring_2016_can_generated.dbc | 2 + opendbc/lexus_ct200h_2018_pt_generated.dbc | 7 +- opendbc/lexus_is_2018_pt_generated.dbc | 7 +- opendbc/lexus_nx300_2018_pt_generated.dbc | 7 +- opendbc/lexus_nx300h_2018_pt_generated.dbc | 7 +- opendbc/lexus_rx_350_2016_pt_generated.dbc | 7 +- opendbc/lexus_rx_hybrid_2017_pt_generated.dbc | 7 +- opendbc/toyota_avalon_2017_pt_generated.dbc | 7 +- .../toyota_camry_hybrid_2018_pt_generated.dbc | 7 +- opendbc/toyota_corolla_2017_pt_generated.dbc | 7 +- .../toyota_highlander_2017_pt_generated.dbc | 7 +- ...ta_highlander_hybrid_2018_pt_generated.dbc | 7 +- opendbc/toyota_nodsu_hybrid_pt_generated.dbc | 22 +- opendbc/toyota_nodsu_pt_generated.dbc | 35 +- opendbc/toyota_prius_2017_pt_generated.dbc | 7 +- opendbc/toyota_rav4_2017_pt_generated.dbc | 7 +- .../toyota_rav4_hybrid_2017_pt_generated.dbc | 7 +- .../toyota_sienna_xle_2018_pt_generated.dbc | 7 +- panda/.gitignore | 1 + panda/board/SConscript | 7 +- panda/board/gpio.h | 5 +- panda/board/safety/safety_hyundai.h | 41 +- panda/board/safety/safety_toyota.h | 21 +- panda/python/__init__.py | 2 +- panda/python/uds.py | 2 +- phonelibs/SConscript | 2 + phonelibs/kaitai/custom_decoder.h | 16 + phonelibs/kaitai/exceptions.h | 189 +++++ phonelibs/kaitai/kaitaistream.cpp | 689 ++++++++++++++++++ phonelibs/kaitai/kaitaistream.h | 268 +++++++ phonelibs/kaitai/kaitaistruct.h | 20 + rednose/SConscript | 40 + rednose/helpers/__init__.py | 9 +- rednose/helpers/common_ekf.cc | 19 + rednose/helpers/common_ekf.h | 43 ++ rednose/helpers/ekf_sym.cc | 223 ++++++ rednose/helpers/ekf_sym.h | 112 +++ rednose/helpers/ekf_sym.py | 188 +++-- rednose/helpers/ekf_sym_pyx.pyx | 190 +++++ rednose/helpers/feature_handler.py | 2 + .../{__init__.py => helpers/kalmanfilter.py} | 11 +- rednose/helpers/lst_sq_computer.py | 12 +- rednose/helpers/sympy_helpers.py | 1 - rednose/templates/compute_pos.c | 2 - rednose/templates/feature_handler.c | 2 - selfdrive/athena/athenad.py | 16 +- selfdrive/athena/manage_athenad.py | 4 - selfdrive/{ => athena}/registration.py | 50 +- selfdrive/boardd/boardd.cc | 132 ++-- selfdrive/boardd/boardd_api_impl.pyx | 2 + selfdrive/boardd/can_list_to_can_capnp.cc | 2 +- selfdrive/boardd/panda.cc | 35 +- selfdrive/boardd/panda.h | 10 +- selfdrive/boardd/pigeon.cc | 128 ++-- selfdrive/boardd/pigeon.h | 8 +- selfdrive/boardd/set_time.py | 37 + selfdrive/camerad/cameras/camera_common.cc | 162 ++-- selfdrive/camerad/cameras/camera_common.h | 23 +- .../camerad/cameras/camera_frame_stream.cc | 43 +- selfdrive/camerad/cameras/camera_qcom.cc | 217 +++--- selfdrive/camerad/cameras/camera_qcom.h | 36 +- selfdrive/camerad/cameras/camera_qcom2.cc | 172 ++--- selfdrive/camerad/cameras/camera_qcom2.h | 30 +- selfdrive/camerad/imgproc/utils.cc | 4 +- selfdrive/camerad/imgproc/utils.h | 6 +- selfdrive/camerad/main.cc | 44 +- selfdrive/camerad/snapshot/snapshot.py | 30 +- selfdrive/camerad/transforms/rgb_to_yuv.cc | 42 +- selfdrive/camerad/transforms/rgb_to_yuv.h | 27 +- .../camerad/transforms/rgb_to_yuv_test.cc | 27 +- selfdrive/car/__init__.py | 12 - selfdrive/car/car_helpers.py | 17 +- selfdrive/car/chrysler/carstate.py | 11 + selfdrive/car/chrysler/interface.py | 4 +- selfdrive/car/chrysler/values.py | 5 +- selfdrive/car/ford/carstate.py | 2 +- selfdrive/car/ford/interface.py | 2 +- selfdrive/car/fw_versions.py | 84 ++- selfdrive/car/gm/carstate.py | 22 +- selfdrive/car/gm/interface.py | 2 +- selfdrive/car/gm/radar_interface.py | 2 +- selfdrive/car/honda/carstate.py | 154 ++-- selfdrive/car/honda/interface.py | 3 + selfdrive/car/honda/radar_interface.py | 2 +- selfdrive/car/honda/values.py | 309 ++++++-- selfdrive/car/hyundai/carstate.py | 11 +- selfdrive/car/hyundai/interface.py | 21 +- selfdrive/car/hyundai/values.py | 238 ++++-- selfdrive/car/interfaces.py | 8 +- selfdrive/car/mazda/carcontroller.py | 4 +- selfdrive/car/mazda/mazdacan.py | 6 +- selfdrive/car/mazda/values.py | 2 +- selfdrive/car/nissan/carstate.py | 17 +- selfdrive/car/nissan/values.py | 3 - selfdrive/car/subaru/carstate.py | 22 +- selfdrive/car/subaru/interface.py | 1 + selfdrive/car/tests/test_car_interfaces.py | 97 ++- selfdrive/car/toyota/carcontroller.py | 6 +- selfdrive/car/toyota/carstate.py | 37 +- selfdrive/car/toyota/interface.py | 24 +- selfdrive/car/toyota/values.py | 267 +++++-- selfdrive/car/volkswagen/carcontroller.py | 14 +- selfdrive/car/volkswagen/carstate.py | 43 +- selfdrive/car/volkswagen/interface.py | 25 +- selfdrive/car/volkswagen/values.py | 158 +++- selfdrive/car/volkswagen/volkswagencan.py | 31 +- selfdrive/clocksd/clocksd.cc | 10 +- selfdrive/common/SConscript | 2 + selfdrive/common/clutil.cc | 9 +- selfdrive/common/framebuffer.cc | 10 +- selfdrive/common/framebuffer.h | 2 + selfdrive/common/glutil.cc | 11 +- selfdrive/common/glutil.h | 11 +- selfdrive/common/gpio.cc | 12 +- selfdrive/common/i2c.cc | 14 +- selfdrive/common/modeldata.h | 39 +- selfdrive/common/params.cc | 490 ++++++------- selfdrive/common/params.h | 82 ++- selfdrive/common/swaglog.cc | 33 +- selfdrive/common/timing.h | 5 +- selfdrive/common/touch.c | 16 +- selfdrive/common/util.cc | 99 +-- selfdrive/common/util.h | 64 +- selfdrive/common/version.h | 2 +- selfdrive/common/visionimg.cc | 5 +- selfdrive/common/visionimg.h | 4 +- selfdrive/common/watchdog.cc | 14 +- selfdrive/controls/controlsd.py | 58 +- selfdrive/controls/lib/alerts_offroad.json | 4 + selfdrive/controls/lib/events.py | 47 +- selfdrive/controls/lib/lane_planner.py | 11 +- .../controls/lib/lateral_mpc/generator.cpp | 2 +- .../controls/lib/lateral_mpc/lateral_mpc.c | 6 +- .../controls/lib/lateral_mpc/libmpc_py.py | 4 +- selfdrive/controls/lib/lateral_planner.py | 31 +- selfdrive/controls/plannerd.py | 14 +- selfdrive/controls/radard.py | 5 +- selfdrive/crash.py | 88 +-- selfdrive/debug/count_events.py | 20 + selfdrive/debug/cpu_usage_stat.py | 3 - selfdrive/debug/cycle_alerts.py | 9 +- selfdrive/debug/dump.py | 2 +- selfdrive/debug/filter_log_message.py | 2 +- selfdrive/debug/test_fw_query_on_routes.py | 91 ++- selfdrive/hardware/base.h | 19 +- selfdrive/hardware/base.py | 4 + selfdrive/hardware/eon/hardware.h | 8 + selfdrive/hardware/eon/hardware.py | 5 +- selfdrive/hardware/hw.h | 7 +- selfdrive/hardware/pc/hardware.py | 3 + selfdrive/hardware/tici/agnos.json | 14 +- selfdrive/hardware/tici/hardware.h | 8 +- selfdrive/hardware/tici/hardware.py | 23 + selfdrive/locationd/.gitignore | 3 +- selfdrive/locationd/SConscript | 24 +- selfdrive/locationd/calibrationd.py | 17 +- selfdrive/locationd/generated/gps.cpp | 325 +++++++++ selfdrive/locationd/generated/gps.h | 359 +++++++++ selfdrive/locationd/generated/ubx.cpp | 340 +++++++++ selfdrive/locationd/generated/ubx.h | 410 +++++++++++ selfdrive/locationd/locationd.cc | 457 ++++++++++++ selfdrive/locationd/locationd.h | 65 ++ selfdrive/locationd/locationd.py | 350 --------- selfdrive/locationd/models/SConscript | 37 - selfdrive/locationd/models/car_kf.py | 30 +- selfdrive/locationd/models/live_kf.cc | 144 ++++ selfdrive/locationd/models/live_kf.h | 57 ++ selfdrive/locationd/models/live_kf.py | 159 ++-- selfdrive/locationd/paramsd.py | 57 +- selfdrive/locationd/ublox_msg.cc | 602 +++++++-------- selfdrive/locationd/ublox_msg.h | 215 +----- selfdrive/locationd/ubloxd.cc | 81 +- selfdrive/locationd/ubloxd_main.cc | 114 --- selfdrive/logcatd/logcatd_android.cc | 10 +- selfdrive/logcatd/logcatd_systemd.cc | 21 +- selfdrive/loggerd/SConscript | 5 +- selfdrive/loggerd/bootlog.cc | 30 +- selfdrive/loggerd/logger.cc | 39 +- selfdrive/loggerd/logger.h | 20 +- selfdrive/loggerd/loggerd.cc | 105 ++- selfdrive/loggerd/omx_encoder.cc | 23 +- selfdrive/loggerd/omx_encoder.h | 15 +- selfdrive/loggerd/raw_logger.cc | 16 +- selfdrive/loggerd/raw_logger.h | 7 +- selfdrive/loggerd/uploader.py | 8 +- selfdrive/manager/manager.py | 70 +- selfdrive/manager/process_config.py | 2 +- selfdrive/manager/test/test_manager.py | 9 +- selfdrive/modeld/SConscript | 3 +- selfdrive/modeld/dmonitoringmodeld.cc | 14 +- selfdrive/modeld/modeld.cc | 65 +- selfdrive/modeld/models/commonmodel.cc | 11 +- selfdrive/modeld/models/commonmodel.h | 12 +- selfdrive/modeld/models/dmonitoring.cc | 126 ++-- selfdrive/modeld/models/dmonitoring.h | 10 +- selfdrive/modeld/models/driving.cc | 53 +- selfdrive/modeld/models/driving.h | 15 +- selfdrive/modeld/runners/run.h | 16 +- selfdrive/modeld/runners/runmodel.h | 6 +- selfdrive/modeld/runners/snpemodel.cc | 20 +- selfdrive/modeld/runners/snpemodel.h | 19 +- selfdrive/modeld/runners/thneedmodel.cc | 1 + selfdrive/modeld/runners/thneedmodel.h | 4 +- selfdrive/modeld/thneed/compile.cc | 5 +- selfdrive/modeld/thneed/serialize.cc | 6 +- selfdrive/modeld/thneed/thneed.cc | 17 +- selfdrive/modeld/thneed/thneed.h | 12 +- selfdrive/modeld/transforms/loadyuv.cc | 5 +- selfdrive/modeld/transforms/loadyuv.h | 3 +- selfdrive/modeld/transforms/transform.cc | 10 +- selfdrive/modeld/transforms/transform.h | 2 +- selfdrive/monitoring/dmonitoringd.py | 2 +- selfdrive/monitoring/driver_monitor.py | 12 +- selfdrive/pandad.py | 19 - selfdrive/proclogd/SConscript | 4 +- selfdrive/proclogd/proclogd.cc | 24 +- selfdrive/sensord/libdiag.h | 5 +- selfdrive/sensord/sensors/bmx055_accel.cc | 8 +- .../{bmx055_accel.hpp => bmx055_accel.h} | 2 +- selfdrive/sensord/sensors/bmx055_gyro.cc | 5 +- .../{bmx055_gyro.hpp => bmx055_gyro.h} | 2 +- selfdrive/sensord/sensors/bmx055_magn.cc | 13 +- .../{bmx055_magn.hpp => bmx055_magn.h} | 2 +- selfdrive/sensord/sensors/bmx055_temp.cc | 10 +- .../{bmx055_temp.hpp => bmx055_temp.h} | 5 +- .../sensors/{constants.hpp => constants.h} | 0 selfdrive/sensord/sensors/file_sensor.cc | 4 +- .../{file_sensor.hpp => file_sensor.h} | 3 +- selfdrive/sensord/sensors/i2c_sensor.cc | 3 +- .../sensors/{i2c_sensor.hpp => i2c_sensor.h} | 7 +- selfdrive/sensord/sensors/light_sensor.cc | 8 +- .../{light_sensor.hpp => light_sensor.h} | 2 +- selfdrive/sensord/sensors/lsm6ds3_accel.cc | 8 +- .../{lsm6ds3_accel.hpp => lsm6ds3_accel.h} | 2 +- selfdrive/sensord/sensors/lsm6ds3_gyro.cc | 7 +- .../{lsm6ds3_gyro.hpp => lsm6ds3_gyro.h} | 2 +- selfdrive/sensord/sensors/lsm6ds3_temp.cc | 8 +- .../{lsm6ds3_temp.hpp => lsm6ds3_temp.h} | 2 +- .../sensord/sensors/{sensor.hpp => sensor.h} | 0 selfdrive/sensord/sensors_qcom.cc | 30 +- selfdrive/sensord/sensors_qcom2.cc | 41 +- selfdrive/test/helpers.py | 13 +- selfdrive/test/setup_device_ci.sh | 4 +- selfdrive/test/test_onroad.py | 151 ++++ selfdrive/thermald/power_monitoring.py | 11 +- selfdrive/thermald/thermald.py | 35 +- selfdrive/tombstoned.py | 54 +- selfdrive/ui/.gitignore | 1 + selfdrive/ui/SConscript | 56 +- selfdrive/ui/{qt/ui.cc => main.cc} | 15 +- selfdrive/ui/paint.cc | 267 +++---- selfdrive/ui/{paint.hpp => paint.h} | 5 +- selfdrive/ui/qt/api.cc | 76 +- selfdrive/ui/qt/api.h | 51 ++ selfdrive/ui/qt/api.hpp | 55 -- selfdrive/ui/qt/home.cc | 259 ++----- selfdrive/ui/qt/home.h | 64 ++ selfdrive/ui/qt/home.hpp | 96 --- selfdrive/ui/qt/offroad/networking.cc | 155 ++-- .../offroad/{networking.hpp => networking.h} | 25 +- selfdrive/ui/qt/offroad/onboarding.cc | 44 +- .../offroad/{onboarding.hpp => onboarding.h} | 13 +- selfdrive/ui/qt/offroad/settings.cc | 245 ++++--- .../qt/offroad/{settings.hpp => settings.h} | 20 +- selfdrive/ui/qt/offroad/wifiManager.cc | 16 +- .../{wifiManager.hpp => wifiManager.h} | 0 selfdrive/ui/qt/onroad.cc | 206 ++++++ selfdrive/ui/qt/onroad.h | 92 +++ .../ui/qt/{qt_window.hpp => qt_window.h} | 14 +- selfdrive/ui/qt/request_repeater.cc | 13 + selfdrive/ui/qt/request_repeater.h | 12 + selfdrive/ui/qt/sidebar.cc | 113 +++ selfdrive/ui/qt/sidebar.h | 57 ++ selfdrive/ui/qt/sound.cc | 25 - selfdrive/ui/qt/sound.hpp | 30 - selfdrive/ui/qt/spinner.cc | 105 ++- selfdrive/ui/qt/{spinner.hpp => spinner.h} | 23 +- selfdrive/ui/qt/spinner_aarch64 | Bin 603552 -> 820976 bytes selfdrive/ui/qt/text.cc | 37 +- selfdrive/ui/qt/text_aarch64 | Bin 302968 -> 785800 bytes selfdrive/ui/qt/util.h | 10 + selfdrive/ui/qt/widgets/controls.cc | 11 +- .../qt/widgets/{controls.hpp => controls.h} | 26 +- selfdrive/ui/qt/widgets/drive_stats.cc | 34 +- .../{drive_stats.hpp => drive_stats.h} | 3 +- selfdrive/ui/qt/widgets/input.cc | 31 +- .../ui/qt/widgets/{input.hpp => input.h} | 12 +- selfdrive/ui/qt/widgets/keyboard.cc | 8 +- .../qt/widgets/{keyboard.hpp => keyboard.h} | 5 +- selfdrive/ui/qt/widgets/offroad_alerts.cc | 135 ++-- selfdrive/ui/qt/widgets/offroad_alerts.h | 38 + selfdrive/ui/qt/widgets/offroad_alerts.hpp | 32 - selfdrive/ui/qt/widgets/scrollview.cc | 47 ++ selfdrive/ui/qt/widgets/scrollview.h | 13 + selfdrive/ui/qt/widgets/setup.cc | 48 +- .../ui/qt/widgets/{setup.hpp => setup.h} | 9 +- selfdrive/ui/qt/widgets/ssh_keys.cc | 93 +-- .../qt/widgets/{ssh_keys.hpp => ssh_keys.h} | 21 +- selfdrive/ui/qt/widgets/toggle.cc | 2 +- .../ui/qt/widgets/{toggle.hpp => toggle.h} | 1 + selfdrive/ui/qt/window.cc | 36 +- selfdrive/ui/qt/{window.hpp => window.h} | 12 +- selfdrive/ui/sidebar.cc | 143 ---- selfdrive/ui/sidebar.hpp | 4 - selfdrive/ui/ui.cc | 250 ++++--- selfdrive/ui/{ui.hpp => ui.h} | 136 ++-- selfdrive/updated.py | 19 +- 345 files changed, 10464 insertions(+), 5438 deletions(-) rename cereal/messaging/{impl_msgq.hpp => impl_msgq.h} (95%) rename cereal/messaging/{impl_zmq.hpp => impl_zmq.h} (96%) rename cereal/messaging/{messaging.hpp => messaging.h} (93%) rename cereal/messaging/{msgq.hpp => msgq.h} (97%) mode change 100755 => 100644 cereal/services.py create mode 100644 phonelibs/kaitai/custom_decoder.h create mode 100644 phonelibs/kaitai/exceptions.h create mode 100644 phonelibs/kaitai/kaitaistream.cpp create mode 100644 phonelibs/kaitai/kaitaistream.h create mode 100644 phonelibs/kaitai/kaitaistruct.h create mode 100644 rednose/SConscript create mode 100644 rednose/helpers/common_ekf.cc create mode 100644 rednose/helpers/common_ekf.h create mode 100644 rednose/helpers/ekf_sym.cc create mode 100644 rednose/helpers/ekf_sym.h create mode 100644 rednose/helpers/ekf_sym_pyx.pyx rename rednose/{__init__.py => helpers/kalmanfilter.py} (74%) rename selfdrive/{ => athena}/registration.py (67%) create mode 100755 selfdrive/boardd/set_time.py create mode 100755 selfdrive/debug/count_events.py create mode 100644 selfdrive/locationd/generated/gps.cpp create mode 100644 selfdrive/locationd/generated/gps.h create mode 100644 selfdrive/locationd/generated/ubx.cpp create mode 100644 selfdrive/locationd/generated/ubx.h create mode 100755 selfdrive/locationd/locationd.cc create mode 100755 selfdrive/locationd/locationd.h delete mode 100755 selfdrive/locationd/locationd.py delete mode 100644 selfdrive/locationd/models/SConscript create mode 100755 selfdrive/locationd/models/live_kf.cc create mode 100755 selfdrive/locationd/models/live_kf.h delete mode 100644 selfdrive/locationd/ubloxd_main.cc rename selfdrive/sensord/sensors/{bmx055_accel.hpp => bmx055_accel.h} (95%) rename selfdrive/sensord/sensors/{bmx055_gyro.hpp => bmx055_gyro.h} (95%) rename selfdrive/sensord/sensors/{bmx055_magn.hpp => bmx055_magn.h} (97%) rename selfdrive/sensord/sensors/{bmx055_temp.hpp => bmx055_temp.h} (69%) rename selfdrive/sensord/sensors/{constants.hpp => constants.h} (100%) rename selfdrive/sensord/sensors/{file_sensor.hpp => file_sensor.h} (87%) rename selfdrive/sensord/sensors/{i2c_sensor.hpp => i2c_sensor.h} (80%) rename selfdrive/sensord/sensors/{light_sensor.hpp => light_sensor.h} (87%) rename selfdrive/sensord/sensors/{lsm6ds3_accel.hpp => lsm6ds3_accel.h} (92%) rename selfdrive/sensord/sensors/{lsm6ds3_gyro.hpp => lsm6ds3_gyro.h} (91%) rename selfdrive/sensord/sensors/{lsm6ds3_temp.hpp => lsm6ds3_temp.h} (90%) rename selfdrive/sensord/sensors/{sensor.hpp => sensor.h} (100%) create mode 100755 selfdrive/test/test_onroad.py rename selfdrive/ui/{qt/ui.cc => main.cc} (51%) rename selfdrive/ui/{paint.hpp => paint.h} (85%) create mode 100644 selfdrive/ui/qt/api.h delete mode 100644 selfdrive/ui/qt/api.hpp create mode 100644 selfdrive/ui/qt/home.h delete mode 100644 selfdrive/ui/qt/home.hpp rename selfdrive/ui/qt/offroad/{networking.hpp => networking.h} (80%) rename selfdrive/ui/qt/offroad/{onboarding.hpp => onboarding.h} (93%) rename selfdrive/ui/qt/offroad/{settings.hpp => settings.h} (74%) rename selfdrive/ui/qt/offroad/{wifiManager.hpp => wifiManager.h} (100%) create mode 100644 selfdrive/ui/qt/onroad.cc create mode 100644 selfdrive/ui/qt/onroad.h rename selfdrive/ui/qt/{qt_window.hpp => qt_window.h} (85%) create mode 100644 selfdrive/ui/qt/request_repeater.cc create mode 100644 selfdrive/ui/qt/request_repeater.h create mode 100644 selfdrive/ui/qt/sidebar.cc create mode 100644 selfdrive/ui/qt/sidebar.h delete mode 100644 selfdrive/ui/qt/sound.cc delete mode 100644 selfdrive/ui/qt/sound.hpp rename selfdrive/ui/qt/{spinner.hpp => spinner.h} (64%) create mode 100644 selfdrive/ui/qt/util.h rename selfdrive/ui/qt/widgets/{controls.hpp => controls.h} (84%) rename selfdrive/ui/qt/widgets/{drive_stats.hpp => drive_stats.h} (79%) rename selfdrive/ui/qt/widgets/{input.hpp => input.h} (85%) rename selfdrive/ui/qt/widgets/{keyboard.hpp => keyboard.h} (99%) create mode 100644 selfdrive/ui/qt/widgets/offroad_alerts.h delete mode 100644 selfdrive/ui/qt/widgets/offroad_alerts.hpp create mode 100644 selfdrive/ui/qt/widgets/scrollview.cc create mode 100644 selfdrive/ui/qt/widgets/scrollview.h rename selfdrive/ui/qt/widgets/{setup.hpp => setup.h} (81%) rename selfdrive/ui/qt/widgets/{ssh_keys.hpp => ssh_keys.h} (61%) rename selfdrive/ui/qt/widgets/{toggle.hpp => toggle.h} (99%) rename selfdrive/ui/qt/{window.hpp => window.h} (72%) delete mode 100644 selfdrive/ui/sidebar.cc delete mode 100644 selfdrive/ui/sidebar.hpp rename selfdrive/ui/{ui.hpp => ui.h} (63%) diff --git a/.gitignore b/.gitignore index f1f1d431c..f4932ed4f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ venv/ .vscode* model2.png a.out +.hypothesis *.dylib *.DSYM @@ -59,6 +60,7 @@ notebooks xx hyperthneed panda_jungle +provisioning .coverage* coverage.xml diff --git a/Jenkinsfile b/Jenkinsfile index 78a3a0fa6..97633da80 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,7 @@ EOF""" def phone_steps(String device_type, steps) { lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) { - timeout(time: 60, unit: 'MINUTES') { + timeout(time: 90, unit: 'MINUTES') { phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),) steps.each { item -> phone(device_ip, item[0], item[1]) @@ -83,7 +83,6 @@ pipeline { } } - stages { /* @@ -113,6 +112,10 @@ pipeline { stage('On-device Tests') { agent { docker { + /* + filename 'Dockerfile.ondevice_ci' + args "--privileged -v /dev:/dev --shm-size=1G --user=root" + */ image 'python:3.7.3' args '--user=root' } @@ -121,17 +124,12 @@ pipeline { stages { stage('parallel tests') { parallel { - stage('Devel Build') { - environment { - CI_PUSH = "${env.BRANCH_NAME == 'master' ? 'master-ci' : ' '}" - } + stage('Devel Tests') { steps { phone_steps("eon-build", [ - ["build", "SCONS_CACHE=1 scons -j4"], - ["test athena", "nosetests -s selfdrive/athena/tests/test_athenad_old.py"], + ["build devel", "cd release && SCONS_CACHE=1 DEVEL_TEST=1 ./build_devel.sh"], ["test manager", "python selfdrive/manager/test/test_manager.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], - ["build devel", "cd release && CI_PUSH=${env.CI_PUSH} ./build_devel.sh"], ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], ]) } @@ -150,6 +148,7 @@ pipeline { steps { phone_steps("eon", [ ["build", "SCONS_CACHE=1 scons -j4"], + ["test athena", "nosetests -s selfdrive/athena/tests/test_athenad_old.py"], ["test sounds", "nosetests -s selfdrive/test/test_sounds.py"], ["test boardd loopback", "nosetests -s selfdrive/boardd/tests/test_boardd_loopback.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], @@ -160,6 +159,27 @@ pipeline { } } + /* + stage('Power Consumption Tests') { + steps { + lock(resource: "", label: "c2-zookeeper", inversePrecedence: true, variable: 'device_ip', quantity: 1) { + timeout(time: 90, unit: 'MINUTES') { + sh script: "/home/batman/tools/zookeeper/enable_and_wait.py $device_ip 120", label: "turn on device" + phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),) + phone(device_ip, "build", "SCONS_CACHE=1 scons -j4 && sync") + sh script: "/home/batman/tools/zookeeper/disable.py $device_ip", label: "turn off device" + sh script: "/home/batman/tools/zookeeper/enable_and_wait.py $device_ip 120", label: "turn on device" + sh script: "/home/batman/tools/zookeeper/check_consumption.py 60 3", label: "idle power consumption after boot" + sh script: "/home/batman/tools/zookeeper/ignition.py 1", label: "go onroad" + sh script: "/home/batman/tools/zookeeper/check_consumption.py 60 10", label: "onroad power consumption" + sh script: "/home/batman/tools/zookeeper/ignition.py 0", label: "go offroad" + sh script: "/home/batman/tools/zookeeper/check_consumption.py 60 2", label: "idle power consumption offroad" + } + } + } + } + */ + stage('Tici Build') { environment { R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}" @@ -169,6 +189,7 @@ pipeline { ["build", "SCONS_CACHE=1 scons -j16"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], + ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], //["build release3-staging", "cd release && PUSH=${env.R3_PUSH} ./build_release3.sh"], ]) } @@ -196,6 +217,18 @@ pipeline { } } + + stage('Push master-ci') { + when { + branch 'master' + } + steps { + phone_steps("eon-build", [ + ["push devel", "cd release && CI_PUSH='master-ci' ./build_devel.sh"], + ]) + } + } + } post { diff --git a/README.md b/README.md index 52c06169e..95a0897c1 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Supported Cars | ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------| | Acura | ILX 2016-19 | AcuraWatch Plus | openpilot | 25mph1 | 25mph | | Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph1 | 12mph | -| Acura | RDX 2020-21 | All | Stock | 0mph | 3mph | +| Acura | RDX 2019-21 | All | Stock | 0mph | 3mph | | Honda | Accord 2018-20 | All | Stock | 0mph | 3mph | | Honda | Accord Hybrid 2018-20 | All | Stock | 0mph | 3mph | | Honda | Civic Hatchback 2017-21 | Honda Sensing | Stock | 0mph | 12mph | @@ -86,18 +86,18 @@ Supported Cars | Hyundai | Palisade 2020-21 | All | Stock | 0mph | 0mph | | Hyundai | Sonata 2020-21 | All | Stock | 0mph | 0mph | | Lexus | CT Hybrid 2017-18 | LSS | Stock3| 0mph | 0mph | -| Lexus | ES 2019-20 | All | openpilot | 0mph | 0mph | -| Lexus | ES Hybrid 2018 | LSS | Stock3| 0mph | 0mph | -| Lexus | ES Hybrid 2019 | All | openpilot | 0mph | 0mph | +| Lexus | ES 2019-21 | All | openpilot | 0mph | 0mph | +| Lexus | ES Hybrid 2017-18 | LSS | Stock3| 0mph | 0mph | +| Lexus | ES Hybrid 2019-21 | All | openpilot | 0mph | 0mph | | Lexus | IS 2017-2019 | All | Stock | 22mph | 0mph | -| Lexus | IS Hybrid 2017 | All | Stock | 0mph | 0mph | | Lexus | NX 2018 | All | Stock3| 0mph | 0mph | +| Lexus | NX 2020 | All | openpilot | 0mph | 0mph | | Lexus | NX Hybrid 2018 | All | Stock3| 0mph | 0mph | | Lexus | RX 2016-18 | All | Stock3| 0mph | 0mph | | 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 | @@ -112,6 +112,7 @@ Supported Cars | Toyota | Highlander 2020-21 | All | openpilot | 0mph | 0mph | | Toyota | Highlander Hybrid 2017-19 | All | Stock3| 0mph | 0mph | | Toyota | Highlander Hybrid 2020-21 | All | openpilot | 0mph | 0mph | +| Toyota | Mirai 2021 | All | openpilot | 0mph | 0mph | | Toyota | Prius 2016-20 | TSS-P | Stock3| 0mph | 0mph | | Toyota | Prius 2021 | All | openpilot | 0mph | 0mph | | Toyota | Prius Prime 2017-20 | All | Stock3| 0mph | 0mph | @@ -132,7 +133,8 @@ Community Maintained Cars and Features | Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below | | ----------| ------------------------------| ------------------| -----------------| -------------------| -------------| -| Audi | A3 2015, 2017 | Prestige | Stock | 0mph | 0mph | +| Audi | A3 2014-17 | 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 | @@ -157,45 +159,48 @@ Community Maintained Cars and Features | 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 | 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 | Sorento 2018-19 | 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 | Rogue 2018-20 | 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 | +| Škoda | Superb 2015-18 | 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 | Forester 2019-21 | EyeSight | Stock | 0mph | 0mph | | Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph | -| Volkswagen| e-Golf 2014, 2020 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Atlas 2018-19 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| e-Golf 2014, 2019-20 | Driver Assistance | Stock | 0mph | 0mph | | Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Golf Alltrack 2017-18 | 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| Jetta 2018-20 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Jetta GLI 2021 | 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. -Although it's not upstream, there's a community of people getting openpilot to run on Tesla's [here](https://tinkla.us/) - Community Maintained Cars and Features are not verified by comma to meet our [safety model](SAFETY.md). Be extra cautious using them. They are only available after enabling the toggle in `Settings->Developer->Enable Community Features`. To promote a car from community maintained, it must meet a few requirements. We must own one from the brand, we must sell the harness for it, has full ISO26262 in both panda and openpilot, there must be a path forward for longitudinal control, it must have AEB still enabled, and it must support fingerprinting 2.0 +Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). + Installation Instructions ------ @@ -327,7 +332,7 @@ Directory Structure . ├── cereal # The messaging spec and libs used for all logs ├── common # Library like functionality we've developed here - ├── installer/updater # Manages auto-updates of openpilot + ├── installer/updater # Manages auto-updates of NEOS ├── opendbc # Files showing how to interpret data from cars ├── panda # Code used to communicate on CAN ├── phonelibs # Libraries used on NEOS devices diff --git a/RELEASES.md b/RELEASES.md index 42b6379b4..bf764dd59 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,13 @@ +Version 0.8.4 (2021-05-17) +======================== + * Delay controls start until system is ready + * Fuzzy car identification, enabled with Community Features toggle + * Localizer optimized for increased precision and less CPU usage + * Retuned lateral control to be more aggressive when model is confident + * Toyota Mirai 2021 support + * Lexus NX 300 2020 support thanks to goesreallyfast! + * Volkswagen Atlas 2018-19 support thanks to jyoung8607! + Version 0.8.3 (2021-04-01) ======================== * New model diff --git a/SConstruct b/SConstruct index fc1ddfd66..138c6ab3f 100644 --- a/SConstruct +++ b/SConstruct @@ -13,6 +13,10 @@ AddOption('--test', action='store_true', help='build test files') +AddOption('--kaitai', + action='store_true', + help='Regenerate kaitai struct parsers') + AddOption('--asan', action='store_true', help='turn on ASAN') @@ -79,6 +83,9 @@ if arch == "aarch64" or arch == "larch64": "#phonelibs/libyuv/larch64/lib", "/usr/lib/aarch64-linux-gnu" ] + cpppath += [ + "#selfdrive/camerad/include", + ] cflags = ["-DQCOM2", "-mcpu=cortex-a57"] cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"] rpath = ["/usr/local/lib"] @@ -101,17 +108,22 @@ else: cpppath = [] if arch == "Darwin": + yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64" libpath = [ - "#phonelibs/libyuv/mac/lib", - "#cereal", - "#selfdrive/common", + f"#phonelibs/libyuv/{yuv_dir}/lib", "/usr/local/lib", + "/opt/homebrew/lib", "/usr/local/opt/openssl/lib", + "/opt/homebrew/opt/openssl/lib", "/System/Library/Frameworks/OpenGL.framework/Libraries", ] cflags += ["-DGL_SILENCE_DEPRECATION"] cxxflags += ["-DGL_SILENCE_DEPRECATION"] - cpppath += ["/usr/local/opt/openssl/include"] + cpppath += [ + "/opt/homebrew/include", + "/usr/local/opt/openssl/include", + "/opt/homebrew/opt/openssl/include" + ] else: libpath = [ "#phonelibs/snpe/x86_64-linux-clang", @@ -141,6 +153,10 @@ else: ccflags = [] ldflags = [] +# no --as-needed on mac linker +if arch != "Darwin": + ldflags += ["-Wl,--as-needed"] + # change pythonpath to this lenv["PYTHONPATH"] = Dir("#").path @@ -162,7 +178,6 @@ env = Environment( CPPPATH=cpppath + [ "#", - "#selfdrive", "#phonelibs/catch2/include", "#phonelibs/bzip2", "#phonelibs/libyuv/include", @@ -177,14 +192,7 @@ env = Environment( "#phonelibs/snpe/include", "#phonelibs/nanovg", "#phonelibs/qrcode", - "#selfdrive/boardd", - "#selfdrive/common", - "#selfdrive/camerad", - "#selfdrive/camerad/include", - "#selfdrive/loggerd/include", - "#selfdrive/modeld", - "#selfdrive/sensord", - "#selfdrive/ui", + "#phonelibs", "#cereal", "#cereal/messaging", "#cereal/visionipc", @@ -270,7 +278,10 @@ if arch != "aarch64": qt_libs = [] if arch == "Darwin": - qt_env['QTDIR'] = "/usr/local/opt/qt@5" + if real_arch == "arm64": + qt_env['QTDIR'] = "/opt/homebrew/opt/qt@5" + else: + qt_env['QTDIR'] = "/usr/local/opt/qt@5" qt_dirs = [ os.path.join(qt_env['QTDIR'], "include"), ] @@ -326,12 +337,8 @@ if GetOption("clazy"): qt_env['CXX'] = 'clazy' qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0] qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks) -Export('qt_env') - -# still needed for apks -zmq = 'zmq' -Export('env', 'arch', 'real_arch', 'zmq', 'SHARED', 'USE_WEBCAM', 'QCOM_REPLAY') +Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED', 'USE_WEBCAM', 'QCOM_REPLAY') # cereal and messaging are shared with the system SConscript(['cereal/SConscript']) @@ -356,6 +363,28 @@ else: Export('common', 'gpucommon', 'visionipc') +# Build rednose library and ekf models + +rednose_config = { + 'generated_folder': '#selfdrive/locationd/models/generated', + 'to_build': { + 'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h']), + 'car': ('#selfdrive/locationd/models/car_kf.py', True, []), + }, +} + +if arch != "aarch64": + rednose_config['to_build'].update({ + 'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, []), + 'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, []), + 'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, []), + 'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, []), + 'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, []), + 'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', True, []), + }) + +Export('rednose_config') +SConscript(['rednose/SConscript']) # Build openpilot @@ -384,16 +413,12 @@ SConscript(['selfdrive/clocksd/SConscript']) SConscript(['selfdrive/loggerd/SConscript']) SConscript(['selfdrive/locationd/SConscript']) -SConscript(['selfdrive/locationd/models/SConscript']) SConscript(['selfdrive/sensord/SConscript']) SConscript(['selfdrive/ui/SConscript']) if arch != "Darwin": SConscript(['selfdrive/logcatd/SConscript']) -if real_arch == "x86_64": - SConscript(['tools/nui/SConscript']) - external_sconscript = GetOption('external_sconscript') if external_sconscript: SConscript([external_sconscript]) diff --git a/cereal/SConscript b/cereal/SConscript index bd2cde9c6..a671aeecc 100644 --- a/cereal/SConscript +++ b/cereal/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'zmq', 'QCOM_REPLAY') +Import('env', 'envCython', 'arch', 'QCOM_REPLAY') import shutil @@ -40,13 +40,6 @@ messaging_objects = env.SharedObject([ messaging_lib = env.Library('messaging', messaging_objects) Depends('messaging/impl_zmq.cc', services_h) -# note, this rebuilds the deps shared, zmq is statically linked to make APK happy -# TODO: get APK to load system zmq to remove the static link -if arch == "aarch64": - zmq_static = FindFile("libzmq.a", "/usr/lib") - shared_lib_shared_lib = [zmq_static, 'm', 'stdc++', "gnustl_shared", "kj", "capnp"] - env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib) - env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging_lib, 'zmq']) Depends('messaging/bridge.cc', services_h) diff --git a/cereal/car.capnp b/cereal/car.capnp index d5726f7c5..c98928190 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -53,7 +53,7 @@ struct CarEvent @0x9b1657f34caf3ad3 { lowSpeedLockout @31; plannerError @32; debugAlert @34; - steerTempUnavailableMute @35; + steerTempUnavailableUserOverride @35; resumeRequired @36; preDriverDistracted @37; promptDriverDistracted @38; @@ -64,7 +64,7 @@ struct CarEvent @0x9b1657f34caf3ad3 { belowSteerSpeed @46; lowBattery @48; vehicleModelInvalid @50; - controlsFailed @51; + accFaulted @51; sensorDataInvalid @52; commIssue @53; tooDistracted @54; @@ -89,6 +89,7 @@ struct CarEvent @0x9b1657f34caf3ad3 { startupNoCar @76; startupNoControl @77; startupMaster @78; + startupFuzzyFingerprint @97; fcw @79; steerSaturated @80; belowEngageSpeed @84; @@ -101,6 +102,7 @@ struct CarEvent @0x9b1657f34caf3ad3 { gpsMalfunction @94; processNotRunning @95; dashcamMode @96; + controlsInitializing @98; radarCanErrorDEPRECATED @15; radarCommIssueDEPRECATED @67; @@ -351,12 +353,14 @@ struct CarControl { struct CarParams { carName @0 :Text; carFingerprint @1 :Text; + fuzzyFingerprint @55 :Bool; enableGasInterceptor @2 :Bool; enableCruise @3 :Bool; enableCamera @4 :Bool; enableDsu @5 :Bool; # driving support unit enableApgs @6 :Bool; # advanced parking guidance system + enableBsm @56 :Bool; # blind spot monitoring minEnableSpeed @7 :Float32; minSteerSpeed @8 :Float32; @@ -412,6 +416,7 @@ struct CarParams { dashcamOnly @41: Bool; transmissionType @43 :TransmissionType; carFw @44 :List(CarFw); + radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard communityFeature @46: Bool; # true if a community maintained feature is detected fingerprintSource @49: FingerprintSource; diff --git a/cereal/log.capnp b/cereal/log.capnp index aca7a9b35..41de42009 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -1070,6 +1070,7 @@ struct UbloxGnss { aStatus @2 :AntennaSupervisorState; aPower @3 :AntennaPowerStatus; jamInd @4 :UInt8; + flags @5 :UInt8; enum AntennaSupervisorState { init @0; @@ -1192,9 +1193,11 @@ struct DriverMonitoringState @0xb83cda094a1da284 { struct Boot { wallTimeNanos @0 :UInt64; - lastKmsg @1 :Data; - lastPmsg @2 :Data; + pstore @4 :Map(Text, Data); launchLog @3 :Text; + + lastKmsgDEPRECATED @1 :Data; + lastPmsgDEPRECATED @2 :Data; } struct LiveParametersData { diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py index 0b1204b47..1628dd524 100644 --- a/cereal/messaging/__init__.py +++ b/cereal/messaging/__init__.py @@ -1,9 +1,11 @@ # must be build with scons from .messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error from .messaging_pyx import MultiplePublishersError, MessagingError # pylint: disable=no-name-in-module, import-error +import os import capnp from typing import Optional, List, Union +from collections import deque from cereal import log from cereal.services import service_list @@ -11,6 +13,9 @@ from cereal.services import service_list assert MultiplePublishersError assert MessagingError +AVG_FREQ_HISTORY = 100 +SIMULATION = "SIMULATION" in os.environ + # sec_since_boot is faster, but allow to run standalone too try: from common.realtime import sec_since_boot @@ -126,12 +131,14 @@ def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader: class SubMaster(): def __init__(self, services: List[str], poll: Optional[List[str]] = None, - ignore_alive: Optional[List[str]] = None, addr:str ="127.0.0.1"): + ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None, + addr: str = "127.0.0.1"): self.frame = -1 self.updated = {s: False for s in services} self.rcv_time = {s: 0. for s in services} self.rcv_frame = {s: 0 for s in services} self.alive = {s: False for s in services} + self.recv_dts = {s: deque([0.0] * AVG_FREQ_HISTORY, maxlen=AVG_FREQ_HISTORY) for s in services} self.sock = {} self.freq = {} self.data = {} @@ -142,10 +149,8 @@ class SubMaster(): self.non_polled_services = [s for s in services if poll is not None and len(poll) and s not in poll] - if ignore_alive is not None: - self.ignore_alive = ignore_alive - else: - self.ignore_alive = [] + self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq + self.ignore_alive = [] if ignore_alive is None else ignore_alive for s in services: if addr is not None: @@ -184,20 +189,34 @@ class SubMaster(): s = msg.which() self.updated[s] = True + + if self.rcv_time[s] > 1e-5 and self.freq[s] > 1e-5 and (s not in self.non_polled_services) \ + and (s not in self.ignore_average_freq): + self.recv_dts[s].append(cur_time - self.rcv_time[s]) + self.rcv_time[s] = cur_time self.rcv_frame[s] = self.frame self.data[s] = getattr(msg, s) self.logMonoTime[s] = msg.logMonoTime self.valid[s] = msg.valid - for s in self.data: - # arbitrary small number to avoid float comparison. If freq is 0, we can skip the check - if self.freq[s] > 1e-5: - # alive if delay is within 10x the expected frequency - self.alive[s] = (cur_time - self.rcv_time[s]) < (10. / self.freq[s]) - else: + if SIMULATION: self.alive[s] = True + if not SIMULATION: + for s in self.data: + # arbitrary small number to avoid float comparison. If freq is 0, we can skip the check + if self.freq[s] > 1e-5: + # alive if delay is within 10x the expected frequency + self.alive[s] = (cur_time - self.rcv_time[s]) < (10. / self.freq[s]) + + # alive if average frequency is higher than 90% of expected frequency + avg_dt = sum(self.recv_dts[s]) / AVG_FREQ_HISTORY + expected_dt = 1 / (self.freq[s] * 0.90) + self.alive[s] = self.alive[s] and (avg_dt < expected_dt) + else: + self.alive[s] = True + def all_alive(self, service_list=None) -> bool: if service_list is None: # check all service_list = self.alive.keys() @@ -223,3 +242,6 @@ class PubMaster(): if not isinstance(dat, bytes): dat = dat.to_bytes() self.sock[s].send(dat) + + def all_readers_updated(self, s: str) -> bool: + return self.sock[s].all_readers_updated() diff --git a/cereal/messaging/bridge.cc b/cereal/messaging/bridge.cc index 8e29566ca..da923835a 100644 --- a/cereal/messaging/bridge.cc +++ b/cereal/messaging/bridge.cc @@ -8,8 +8,8 @@ typedef void (*sighandler_t)(int sig); #include "services.h" -#include "impl_msgq.hpp" -#include "impl_zmq.hpp" +#include "impl_msgq.h" +#include "impl_zmq.h" void sigpipe_handler(int sig) { assert(sig == SIGPIPE); diff --git a/cereal/messaging/impl_msgq.cc b/cereal/messaging/impl_msgq.cc index e211d6abb..862c94cb3 100644 --- a/cereal/messaging/impl_msgq.cc +++ b/cereal/messaging/impl_msgq.cc @@ -6,7 +6,7 @@ #include #include "services.h" -#include "impl_msgq.hpp" +#include "impl_msgq.h" volatile sig_atomic_t msgq_do_exit = 0; @@ -196,6 +196,10 @@ int MSGQPubSocket::send(char *data, size_t size){ return msgq_msg_send(&msg, q); } +bool MSGQPubSocket::all_readers_updated() { + return msgq_all_readers_updated(q); +} + MSGQPubSocket::~MSGQPubSocket(){ if (q != NULL){ msgq_close_queue(q); diff --git a/cereal/messaging/impl_msgq.hpp b/cereal/messaging/impl_msgq.h similarity index 95% rename from cereal/messaging/impl_msgq.hpp rename to cereal/messaging/impl_msgq.h index e89994852..b67aae622 100644 --- a/cereal/messaging/impl_msgq.hpp +++ b/cereal/messaging/impl_msgq.h @@ -1,6 +1,6 @@ #pragma once -#include "messaging.hpp" -#include "msgq.hpp" +#include "messaging.h" +#include "msgq.h" #include #include @@ -48,6 +48,7 @@ public: int connect(Context *context, std::string endpoint, bool check_endpoint=true); int sendMessage(Message *message); int send(char *data, size_t size); + bool all_readers_updated(); ~MSGQPubSocket(); }; diff --git a/cereal/messaging/impl_zmq.cc b/cereal/messaging/impl_zmq.cc index 605165fcf..aeed176ae 100644 --- a/cereal/messaging/impl_zmq.cc +++ b/cereal/messaging/impl_zmq.cc @@ -7,7 +7,7 @@ #include #include "services.h" -#include "impl_zmq.hpp" +#include "impl_zmq.h" static int get_port(std::string endpoint) { int port = -1; @@ -131,6 +131,11 @@ int ZMQPubSocket::send(char *data, size_t size){ return zmq_send(sock, data, size, ZMQ_DONTWAIT); } +bool ZMQPubSocket::all_readers_updated() { + assert(false); // TODO not implemented + return false; +} + ZMQPubSocket::~ZMQPubSocket(){ zmq_close(sock); } diff --git a/cereal/messaging/impl_zmq.hpp b/cereal/messaging/impl_zmq.h similarity index 96% rename from cereal/messaging/impl_zmq.hpp rename to cereal/messaging/impl_zmq.h index f9f6deedb..bb232049e 100644 --- a/cereal/messaging/impl_zmq.hpp +++ b/cereal/messaging/impl_zmq.h @@ -1,5 +1,5 @@ #pragma once -#include "messaging.hpp" +#include "messaging.h" #include #include @@ -47,6 +47,7 @@ public: int connect(Context *context, std::string endpoint, bool check_endpoint=true); int sendMessage(Message *message); int send(char *data, size_t size); + bool all_readers_updated(); ~ZMQPubSocket(); }; diff --git a/cereal/messaging/messaging.cc b/cereal/messaging/messaging.cc index 06bc66ae1..bfa634e61 100644 --- a/cereal/messaging/messaging.cc +++ b/cereal/messaging/messaging.cc @@ -1,6 +1,6 @@ -#include "messaging.hpp" -#include "impl_zmq.hpp" -#include "impl_msgq.hpp" +#include "messaging.h" +#include "impl_zmq.h" +#include "impl_msgq.h" #ifdef __APPLE__ const bool MUST_USE_ZMQ = true; diff --git a/cereal/messaging/messaging.hpp b/cereal/messaging/messaging.h similarity index 93% rename from cereal/messaging/messaging.hpp rename to cereal/messaging/messaging.h index e461f06d2..4acdbb484 100644 --- a/cereal/messaging/messaging.hpp +++ b/cereal/messaging/messaging.h @@ -48,6 +48,7 @@ public: virtual int connect(Context *context, std::string endpoint, bool check_endpoint=true) = 0; virtual int sendMessage(Message *message) = 0; virtual int send(char *data, size_t size) = 0; + virtual bool all_readers_updated() = 0; static PubSocket * create(); static PubSocket * create(Context * context, std::string endpoint, bool check_endpoint=true); static PubSocket * create(Context * context, std::string endpoint, int port, bool check_endpoint=true); @@ -67,7 +68,8 @@ class SubMaster { public: SubMaster(const std::initializer_list &service_list, const char *address = nullptr, const std::initializer_list &ignore_alive = {}); - int update(int timeout = 1000); + void update(int timeout = 1000); + void update_msgs(uint64_t current_time, std::vector> messages); inline bool allAlive(const std::initializer_list &service_list = {}) { return all_(service_list, false, true); } inline bool allValid(const std::initializer_list &service_list = {}) { return all_(service_list, true, false); } inline bool allAliveAndValid(const std::initializer_list &service_list = {}) { return all_(service_list, true, true); } @@ -76,7 +78,10 @@ public: uint64_t frame = 0; bool updated(const char *name) const; + bool alive(const char *name) const; + bool valid(const char *name) const; uint64_t rcv_frame(const char *name) const; + uint64_t rcv_time(const char *name) const; cereal::Event::Reader &operator[](const char *name); private: diff --git a/cereal/messaging/messaging.pxd b/cereal/messaging/messaging.pxd index 8bbb2c7ab..de232da5f 100644 --- a/cereal/messaging/messaging.pxd +++ b/cereal/messaging/messaging.pxd @@ -6,7 +6,7 @@ from libcpp.vector cimport vector from libcpp cimport bool -cdef extern from "messaging.hpp": +cdef extern from "messaging.h": cdef cppclass Context: @staticmethod Context * create() @@ -31,6 +31,7 @@ cdef extern from "messaging.hpp": int connect(Context *, string) int sendMessage(Message *) int send(char *, size_t) + bool all_readers_updated() cdef cppclass Poller: @staticmethod diff --git a/cereal/messaging/messaging_pyx.pyx b/cereal/messaging/messaging_pyx.pyx index fa220c435..eed548bb8 100644 --- a/cereal/messaging/messaging_pyx.pyx +++ b/cereal/messaging/messaging_pyx.pyx @@ -149,3 +149,6 @@ cdef class PubSocket: raise MultiplePublishersError else: raise MessagingError + + def all_readers_updated(self): + return self.socket.all_readers_updated() diff --git a/cereal/messaging/msgq.cc b/cereal/messaging/msgq.cc index a51aef8e8..0c17b2657 100644 --- a/cereal/messaging/msgq.cc +++ b/cereal/messaging/msgq.cc @@ -21,7 +21,7 @@ #include -#include "msgq.hpp" +#include "msgq.h" void sigusr2_handler(int signal) { assert(signal == SIGUSR2); @@ -452,3 +452,13 @@ int msgq_poll(msgq_pollitem_t * items, size_t nitems, int timeout){ return num; } + +bool msgq_all_readers_updated(msgq_queue_t *q) { + uint64_t num_readers = *q->num_readers; + for (uint64_t i = 0; i < num_readers; i++) { + if (*q->read_valids[i] && *q->write_pointer != *q->read_pointers[i]) { + return false; + } + } + return num_readers > 0; +} diff --git a/cereal/messaging/msgq.hpp b/cereal/messaging/msgq.h similarity index 97% rename from cereal/messaging/msgq.hpp rename to cereal/messaging/msgq.h index 3bead13d9..301d5d1a3 100644 --- a/cereal/messaging/msgq.hpp +++ b/cereal/messaging/msgq.h @@ -64,3 +64,5 @@ int msgq_msg_send(msgq_msg_t *msg, msgq_queue_t *q); int msgq_msg_recv(msgq_msg_t *msg, msgq_queue_t *q); int msgq_msg_ready(msgq_queue_t * q); int msgq_poll(msgq_pollitem_t * items, size_t nitems, int timeout); + +bool msgq_all_readers_updated(msgq_queue_t *q); diff --git a/cereal/messaging/socketmaster.cc b/cereal/messaging/socketmaster.cc index 1240009fa..b10133e43 100644 --- a/cereal/messaging/socketmaster.cc +++ b/cereal/messaging/socketmaster.cc @@ -1,7 +1,12 @@ -#include #include -#include "messaging.hpp" +#include +#include +#include + #include "services.h" +#include "messaging.h" + +const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1"); static inline uint64_t nanos_since_boot() { struct timespec t; @@ -35,7 +40,7 @@ struct SubMaster::SubMessage { std::string name; SubSocket *socket = nullptr; int freq = 0; - bool updated = false, alive = false, valid = false, ignore_alive; + bool updated = false, alive = false, valid = true, ignore_alive; uint64_t rcv_time = 0, rcv_frame = 0; void *allocated_msg_reader = nullptr; capnp::FlatArrayMessageReader *msg_reader = nullptr; @@ -53,6 +58,7 @@ SubMaster::SubMaster(const std::initializer_list &service_list, co assert(socket != 0); poller_->registerSocket(socket); SubMessage *m = new SubMessage{ + .name = name, .socket = socket, .freq = serv->frequency, .ignore_alive = inList(ignore_alive, name), @@ -62,37 +68,54 @@ SubMaster::SubMaster(const std::initializer_list &service_list, co } } -int SubMaster::update(int timeout) { - if (++frame == UINT64_MAX) frame = 1; +void SubMaster::update(int timeout) { for (auto &kv : messages_) kv.second->updated = false; - int updated = 0; auto sockets = poller_->poll(timeout); uint64_t current_time = nanos_since_boot(); + + std::vector> messages; + for (auto s : sockets) { Message *msg = s->receive(true); if (msg == nullptr) continue; SubMessage *m = messages_.at(s); + if (m->msg_reader) { m->msg_reader->~FlatArrayMessageReader(); } m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(m->aligned_buf.align(msg)); delete msg; - m->event = m->msg_reader->getRoot(); + messages.push_back({m->name, m->msg_reader->getRoot()}); + } + + update_msgs(current_time, messages); +} + +void SubMaster::update_msgs(uint64_t current_time, std::vector> messages){ + if (++frame == UINT64_MAX) frame = 1; + + for(auto &kv : messages) { + auto m_find = services_.find(kv.first); + if (m_find == services_.end()){ + continue; + } + SubMessage *m = m_find->second; + m->event = kv.second; m->updated = true; m->rcv_time = current_time; m->rcv_frame = frame; m->valid = m->event.getValid(); - - ++updated; + if (SIMULATION) m->alive = true; } - for (auto &kv : messages_) { - SubMessage *m = kv.second; - m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq)); + if (!SIMULATION) { + for (auto &kv : messages_) { + SubMessage *m = kv.second; + m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq)); + } } - return updated; } bool SubMaster::all_(const std::initializer_list &service_list, bool valid, bool alive) { @@ -100,7 +123,7 @@ bool SubMaster::all_(const std::initializer_list &service_list, bo for (auto &kv : messages_) { SubMessage *m = kv.second; if (service_list.size() == 0 || inList(service_list, m->name.c_str())) { - found += (!valid || m->valid) && (!alive || (m->alive && !m->ignore_alive)); + found += (!valid || m->valid) && (!alive || (m->alive || m->ignore_alive)); } } return service_list.size() == 0 ? found == messages_.size() : found == service_list.size(); @@ -123,10 +146,22 @@ bool SubMaster::updated(const char *name) const { return services_.at(name)->updated; } +bool SubMaster::alive(const char *name) const { + return services_.at(name)->alive; +} + +bool SubMaster::valid(const char *name) const { + return services_.at(name)->valid; +} + uint64_t SubMaster::rcv_frame(const char *name) const { return services_.at(name)->rcv_frame; } +uint64_t SubMaster::rcv_time(const char *name) const { + return services_.at(name)->rcv_time; +} + cereal::Event::Reader &SubMaster::operator[](const char *name) { return services_.at(name)->event; }; diff --git a/cereal/services.py b/cereal/services.py old mode 100755 new mode 100644 index 98f80acda..a30436bcd --- a/cereal/services.py +++ b/cereal/services.py @@ -3,6 +3,14 @@ import os from typing import Optional EON = os.path.isfile('/EON') +RESERVED_PORT = 8022 # sshd +STARTING_PORT = 8001 + + +def new_port(port: int): + port += STARTING_PORT + return port + 1 if port >= RESERVED_PORT else port + class Service: def __init__(self, port: int, should_log: bool, frequency: float, decimation: Optional[int] = None): @@ -11,55 +19,58 @@ class Service: self.frequency = frequency self.decimation = decimation -service_list = { - "roadCameraState": Service(8002, True, 20., 1), - "sensorEvents": Service(8003, True, 100., 100), - "gpsNMEA": Service(8004, True, 9.), - "deviceState": Service(8005, True, 2., 1), - "can": Service(8006, True, 100.), - "controlsState": Service(8007, True, 100., 100), - "features": Service(8010, True, 0.), - "pandaState": Service(8011, True, 2., 1), - "radarState": Service(8012, True, 20., 5), - "roadEncodeIdx": Service(8015, True, 20., 1), - "liveTracks": Service(8016, True, 20.), - "sendcan": Service(8017, True, 100.), - "logMessage": Service(8018, True, 0.), - "liveCalibration": Service(8019, True, 4., 4), - "androidLog": Service(8020, True, 0., 1), - "carState": Service(8021, True, 100., 10), - "carControl": Service(8023, True, 100., 10), - "longitudinalPlan": Service(8024, True, 20., 2), - "liveLocation": Service(8025, True, 0., 1), - "procLog": Service(8031, True, 0.5), - "gpsLocationExternal": Service(8032, True, 10., 1), - "ubloxGnss": Service(8033, True, 10.), - "clocks": Service(8034, True, 1., 1), - "liveMpc": Service(8035, False, 20.), - "liveLongitudinalMpc": Service(8036, False, 20.), - "ubloxRaw": Service(8042, True, 20.), - "liveLocationKalman": Service(8054, True, 20., 2), - "uiLayoutState": Service(8060, True, 0.), - "liveParameters": Service(8064, True, 20., 2), - "cameraOdometry": Service(8066, True, 20., 5), - "lateralPlan": Service(8067, True, 20., 2), - "thumbnail": Service(8069, True, 0.2, 1), - "carEvents": Service(8070, True, 1., 1), - "carParams": Service(8071, True, 0.02, 1), - "driverCameraState": Service(8072, True, 10. if EON else 20., 1), - "driverEncodeIdx": Service(8061, True, 10. if EON else 20., 1), - "driverState": Service(8063, True, 10. if EON else 20., 1), - "driverMonitoringState": Service(8073, True, 10. if EON else 20., 1), - "offroadLayout": Service(8074, False, 0.), - "wideRoadEncodeIdx": Service(8075, True, 20., 1), - "wideRoadCameraState": Service(8076, True, 20., 1), - "modelV2": Service(8077, True, 20., 20), - "managerState": Service(8078, True, 2., 1), - "testModel": Service(8040, False, 0.), - "testLiveLocation": Service(8045, False, 0.), - "testJoystick": Service(8056, False, 0.), +services = { + "roadCameraState": (True, 20., 1), # should_log, frequency, decimation (optional) + "sensorEvents": (True, 100., 100), + "gpsNMEA": (True, 9.), + "deviceState": (True, 2., 1), + "can": (True, 100.), + "controlsState": (True, 100., 100), + "features": (True, 0.), + "pandaState": (True, 2., 1), + "radarState": (True, 20., 5), + "roadEncodeIdx": (True, 20., 1), + "liveTracks": (True, 20.), + "sendcan": (True, 100.), + "logMessage": (True, 0.), + "liveCalibration": (True, 4., 4), + "androidLog": (True, 0., 1), + "carState": (True, 100., 10), + "carControl": (True, 100., 10), + "longitudinalPlan": (True, 20., 2), + "liveLocation": (True, 0., 1), + "procLog": (True, 0.5), + "gpsLocationExternal": (True, 10., 1), + "ubloxGnss": (True, 10.), + "clocks": (True, 1., 1), + "liveMpc": (False, 20.), + "liveLongitudinalMpc": (False, 20.), + "ubloxRaw": (True, 20.), + "liveLocationKalman": (True, 20., 2), + "uiLayoutState": (True, 0.), + "liveParameters": (True, 20., 2), + "cameraOdometry": (True, 20., 5), + "lateralPlan": (True, 20., 2), + "thumbnail": (True, 0.2, 1), + "carEvents": (True, 1., 1), + "carParams": (True, 0.02, 1), + "driverCameraState": (True, 10. if EON else 20., 1), + "driverEncodeIdx": (True, 10. if EON else 20., 1), + "driverState": (True, 10. if EON else 20., 1), + "driverMonitoringState": (True, 10. if EON else 20., 1), + "offroadLayout": (False, 0.), + "wideRoadEncodeIdx": (True, 20., 1), + "wideRoadCameraState": (True, 20., 1), + "modelV2": (True, 20., 20), + "managerState": (True, 2., 1), + + "testModel": (False, 0.), + "testLiveLocation": (False, 0.), + "testJoystick": (False, 0.), } +service_list = {name: Service(new_port(idx), *vals) for # type: ignore + idx, (name, vals) in enumerate(services.items())} def build_header(): diff --git a/cereal/visionipc/visionipc_client.h b/cereal/visionipc/visionipc_client.h index 469976239..d2c0085ad 100644 --- a/cereal/visionipc/visionipc_client.h +++ b/cereal/visionipc/visionipc_client.h @@ -3,7 +3,7 @@ #include #include -#include "messaging.hpp" +#include "messaging.h" #include "visionipc.h" #include "visionbuf.h" diff --git a/cereal/visionipc/visionipc_server.cc b/cereal/visionipc/visionipc_server.cc index 7c64cd839..f4020133d 100644 --- a/cereal/visionipc/visionipc_server.cc +++ b/cereal/visionipc/visionipc_server.cc @@ -7,7 +7,7 @@ #include #include -#include "messaging.hpp" +#include "messaging.h" #include "ipc.h" #include "visionipc_server.h" diff --git a/cereal/visionipc/visionipc_server.h b/cereal/visionipc/visionipc_server.h index 4472acf61..05c517b16 100644 --- a/cereal/visionipc/visionipc_server.h +++ b/cereal/visionipc/visionipc_server.h @@ -5,7 +5,7 @@ #include #include -#include "messaging.hpp" +#include "messaging.h" #include "visionipc.h" #include "visionbuf.h" diff --git a/common/SConscript b/common/SConscript index 542e10d43..a41fc8b7e 100644 --- a/common/SConscript +++ b/common/SConscript @@ -1,4 +1,4 @@ -Import('envCython') +Import('envCython', 'common') envCython.Program('clock.so', 'clock.pyx') -envCython.Program('params_pyx.so', 'params_pyx.pyx') +envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [common, 'zmq']) diff --git a/common/params.py b/common/params.py index 0acb61fa6..d0a37cce1 100644 --- a/common/params.py +++ b/common/params.py @@ -1,5 +1,6 @@ -from common.params_pyx import Params, UnknownKeyName, put_nonblocking # pylint: disable=no-name-in-module, import-error +from common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking # pylint: disable=no-name-in-module, import-error assert Params +assert ParamKeyType assert UnknownKeyName assert put_nonblocking diff --git a/common/params_pxd.pxd b/common/params_pxd.pxd index 9faa117cb..b31a5ab70 100644 --- a/common/params_pxd.pxd +++ b/common/params_pxd.pxd @@ -8,9 +8,20 @@ cdef extern from "selfdrive/common/util.cc": pass cdef extern from "selfdrive/common/params.h": + cpdef enum ParamKeyType: + PERSISTENT + CLEAR_ON_MANAGER_START + CLEAR_ON_PANDA_DISCONNECT + CLEAR_ON_IGNITION + ALL + cdef cppclass Params: Params(bool) Params(string) string get(string, bool) nogil - int delete_db_value(string) - int write_db_value(string, string) + bool getBool(string) + int remove(string) + int put(string, string) + int putBool(string, bool) + bool checkKey(string) + void clearAll(ParamKeyType) diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index 3d366b08f..dab8d20fa 100755 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -2,88 +2,19 @@ # cython: language_level = 3 from libcpp cimport bool from libcpp.string cimport string -from common.params_pxd cimport Params as c_Params +from common.params_pxd cimport Params as c_Params, ParamKeyType as c_ParamKeyType import os import threading from common.basedir import BASEDIR -cdef enum TxType: - PERSISTENT = 1 - CLEAR_ON_MANAGER_START = 2 - CLEAR_ON_PANDA_DISCONNECT = 3 -keys = { - b"AccessToken": [TxType.CLEAR_ON_MANAGER_START], - b"ApiCache_DriveStats": [TxType.PERSISTENT], - b"ApiCache_Device": [TxType.PERSISTENT], - b"ApiCache_Owner": [TxType.PERSISTENT], - b"AthenadPid": [TxType.PERSISTENT], - b"CalibrationParams": [TxType.PERSISTENT], - b"CarBatteryCapacity": [TxType.PERSISTENT], - b"CarParams": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"CarParamsCache": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"CarVin": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"CommunityFeaturesToggle": [TxType.PERSISTENT], - b"EndToEndToggle": [TxType.PERSISTENT], - b"CompletedTrainingVersion": [TxType.PERSISTENT], - b"DisablePowerDown": [TxType.PERSISTENT], - b"DisableUpdates": [TxType.PERSISTENT], - b"DoUninstall": [TxType.CLEAR_ON_MANAGER_START], - b"DongleId": [TxType.PERSISTENT], - b"GitDiff": [TxType.PERSISTENT], - b"GitBranch": [TxType.PERSISTENT], - 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], - b"IsDriverViewEnabled": [TxType.CLEAR_ON_MANAGER_START], - b"IMEI": [TxType.PERSISTENT], - b"IsLdwEnabled": [TxType.PERSISTENT], - b"IsMetric": [TxType.PERSISTENT], - b"IsOffroad": [TxType.CLEAR_ON_MANAGER_START], - b"IsRHD": [TxType.PERSISTENT], - b"IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START], - b"IsUpdateAvailable": [TxType.CLEAR_ON_MANAGER_START], - b"IsUploadRawEnabled": [TxType.PERSISTENT], - b"LastAthenaPingTime": [TxType.PERSISTENT], - b"LastGPSPosition": [TxType.PERSISTENT], - b"LastUpdateException": [TxType.PERSISTENT], - b"LastUpdateTime": [TxType.PERSISTENT], - b"LiveParameters": [TxType.PERSISTENT], - b"OpenpilotEnabledToggle": [TxType.PERSISTENT], - b"PandaFirmware": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"PandaFirmwareHex": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"PandaDongleId": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"Passive": [TxType.PERSISTENT], - b"RecordFront": [TxType.PERSISTENT], - b"RecordFrontLock": [TxType.PERSISTENT], # for the internal fleet - b"ReleaseNotes": [TxType.PERSISTENT], - b"ShouldDoUpdate": [TxType.CLEAR_ON_MANAGER_START], - b"SubscriberInfo": [TxType.PERSISTENT], - b"SshEnabled": [TxType.PERSISTENT], - b"TermsVersion": [TxType.PERSISTENT], - b"Timezone": [TxType.PERSISTENT], - b"TrainingVersion": [TxType.PERSISTENT], - b"UpdateAvailable": [TxType.CLEAR_ON_MANAGER_START], - b"UpdateFailedCount": [TxType.CLEAR_ON_MANAGER_START], - b"Version": [TxType.PERSISTENT], - b"VisionRadarToggle": [TxType.PERSISTENT], - b"Offroad_ChargeDisabled": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"Offroad_ConnectivityNeeded": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_ConnectivityNeededPrompt": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_TemperatureTooHigh": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_PandaFirmwareMismatch": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], - b"Offroad_InvalidTime": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_NeosUpdate": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_UpdateFailed": [TxType.CLEAR_ON_MANAGER_START], - b"Offroad_HardwareUnsupported": [TxType.CLEAR_ON_MANAGER_START], - b"ForcePowerDown": [TxType.CLEAR_ON_MANAGER_START], -} +cdef class ParamKeyType: + PERSISTENT = c_ParamKeyType.PERSISTENT + CLEAR_ON_MANAGER_START = c_ParamKeyType.CLEAR_ON_MANAGER_START + CLEAR_ON_PANDA_DISCONNECT = c_ParamKeyType.CLEAR_ON_PANDA_DISCONNECT + CLEAR_ON_IGNITION = c_ParamKeyType.CLEAR_ON_IGNITION + ALL = c_ParamKeyType.ALL def ensure_bytes(v): if isinstance(v, str): @@ -108,23 +39,21 @@ cdef class Params: del self.p def clear_all(self, tx_type=None): - for key in keys: - if tx_type is None or tx_type in keys[key]: - self.delete(key) + if tx_type is None: + tx_type = ParamKeyType.ALL - def manager_start(self): - self.clear_all(TxType.CLEAR_ON_MANAGER_START) + self.p.clearAll(tx_type) - def panda_disconnect(self): - self.clear_all(TxType.CLEAR_ON_PANDA_DISCONNECT) - - def get(self, key, block=False, encoding=None): + def check_key(self, key): key = ensure_bytes(key) - if key not in keys: + if not self.p.checkKey(key): raise UnknownKeyName(key) - cdef string k = key + return key + + def get(self, key, block=False, encoding=None): + cdef string k = self.check_key(key) cdef bool b = block cdef string val @@ -144,6 +73,10 @@ cdef class Params: else: return val + def get_bool(self, key): + cdef string k = self.check_key(key) + return self.p.getBool(k) + def put(self, key, dat): """ Warning: This function blocks until the param is written to disk! @@ -151,23 +84,24 @@ cdef class Params: Use the put_nonblocking helper function in time sensitive code, but in general try to avoid writing params as much as possible. """ - key = ensure_bytes(key) + cdef string k = self.check_key(key) dat = ensure_bytes(dat) + self.p.put(k, dat) - if key not in keys: - raise UnknownKeyName(key) - - self.p.write_db_value(key, dat) + def put_bool(self, key, val): + cdef string k = self.check_key(key) + self.p.putBool(k, val) def delete(self, key): - key = ensure_bytes(key) - self.p.delete_db_value(key) + cdef string k = self.check_key(key) + self.p.remove(k) def put_nonblocking(key, val, d=None): def f(key, val): params = Params(d) - params.put(key, val) + cdef string k = ensure_bytes(key) + params.put(k, val) t = threading.Thread(target=f, args=(key, val)) t.start() diff --git a/common/transformations/coordinates.cc b/common/transformations/coordinates.cc index 8a1aa0ad7..b729ac3d8 100644 --- a/common/transformations/coordinates.cc +++ b/common/transformations/coordinates.cc @@ -6,8 +6,6 @@ #include "coordinates.hpp" -#define DEG2RAD(x) ((x) * M_PI / 180.0) -#define RAD2DEG(x) ((x) * 180.0 / M_PI) double a = 6378137; // lgtm [cpp/short-global-name] diff --git a/common/transformations/coordinates.hpp b/common/transformations/coordinates.hpp index d8beb59ea..f5ba0d3fe 100644 --- a/common/transformations/coordinates.hpp +++ b/common/transformations/coordinates.hpp @@ -1,5 +1,8 @@ #pragma once +#define DEG2RAD(x) ((x) * M_PI / 180.0) +#define RAD2DEG(x) ((x) * 180.0 / M_PI) + struct ECEF { double x, y, z; Eigen::Vector3d to_vector(){ @@ -9,6 +12,9 @@ struct ECEF { struct NED { double n, e, d; + Eigen::Vector3d to_vector(){ + return Eigen::Vector3d(n, e, d); + } }; struct Geodetic { diff --git a/common/transformations/orientation.cc b/common/transformations/orientation.cc index 8d1a304a2..7909c0aff 100644 --- a/common/transformations/orientation.cc +++ b/common/transformations/orientation.cc @@ -30,7 +30,8 @@ Eigen::Vector3d quat2euler(Eigen::Quaterniond quat){ // Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0); // return {euler(2), euler(1), euler(0)}; double gamma = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2 * (quat.x()*quat.x() + quat.y()*quat.y())); - double theta = asin(2 * (quat.w() * quat.y() - quat.z() * quat.x())); + double asin_arg_clipped = std::clamp(2 * (quat.w() * quat.y() - quat.z() * quat.x()), -1.0, 1.0); + double theta = asin(asin_arg_clipped); double psi = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2 * (quat.y()*quat.y() + quat.z()*quat.z())); return {gamma, theta, psi}; } diff --git a/installer/updater/updater b/installer/updater/updater index 729de843467163a63bc15072c267fcc654f07d57..d833cb7825a3f0ce1247f9cdcc4f4fd8b6fbd9c1 100755 GIT binary patch delta 544706 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

(HMrA#?hIu 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%0A8+ZRYFq-R*AAUAj=+ABOP_wxrQUp+~#m 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 delta 541840 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 M)4s4bwRcSVKcUMaHUIzs diff --git a/installer/updater/updater.cc b/installer/updater/updater.cc index 6dd8d0289..b2f9dd45b 100644 --- a/installer/updater/updater.cc +++ b/installer/updater/updater.cc @@ -1,37 +1,33 @@ +#include +#include +#include + +#include #include #include #include -#include - -#include -#include -#include - -#include -#include #include #include -#include #include +#include +#include +#include #include #include #include - -#include #include #include - +#include #include "nanovg.h" #define NANOVG_GLES3_IMPLEMENTATION +#include "json11.hpp" #include "nanovg_gl.h" #include "nanovg_gl_utils.h" -#include "json11.hpp" - -#include "common/framebuffer.h" -#include "common/touch.h" -#include "common/util.h" +#include "selfdrive/common/framebuffer.h" +#include "selfdrive/common/touch.h" +#include "selfdrive/common/util.h" #define USER_AGENT "NEOSUpdater-0.2" @@ -250,7 +246,12 @@ struct Updater { b_y = 720; b_h = 220; - state = CONFIRMATION; + if (download_stage(true)) { + state = RUNNING; + update_thread_handle = std::thread(&Updater::run_stages, this); + } else { + state = CONFIRMATION; + } } int download_file_xferinfo(curl_off_t dltotal, curl_off_t dlno, @@ -351,11 +352,15 @@ struct Updater { state = RUNNING; } - std::string download(std::string url, std::string hash, std::string name) { + std::string download(std::string url, std::string hash, std::string name, bool dry_run) { std::string out_fn = UPDATE_DIR "/" + util::base_name(url); - // start or resume downloading if hash doesn't match std::string fn_hash = sha256_file(out_fn); + if (dry_run) { + return (hash.compare(fn_hash) != 0) ? "" : out_fn; + } + + // start or resume downloading if hash doesn't match if (hash.compare(fn_hash) != 0) { set_progress("Downloading " + name + "..."); bool r = download_file(url, out_fn); @@ -377,14 +382,14 @@ struct Updater { return out_fn; } - bool download_stage() { + bool download_stage(bool dry_run = false) { curl = curl_easy_init(); assert(curl); // ** quick checks before download ** if (!check_space()) { - set_error("2GB of free space required to update"); + if (!dry_run) set_error("2GB of free space required to update"); return false; } @@ -432,7 +437,7 @@ struct Updater { printf("existing recovery hash: %s\n", existing_recovery_hash.c_str()); if (existing_recovery_hash != recovery_hash) { - recovery_fn = download(recovery_url, recovery_hash, "recovery"); + recovery_fn = download(recovery_url, recovery_hash, "recovery", dry_run); if (recovery_fn.empty()) { // error'd return false; @@ -441,7 +446,7 @@ struct Updater { } // ** handle ota download ** - ota_fn = download(ota_url, ota_hash, "update"); + ota_fn = download(ota_url, ota_hash, "update", dry_run); if (ota_fn.empty()) { //error'd return false; diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index c9605cbab..3f9ce9977 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -165,6 +165,9 @@ function launch { # Remove orphaned git lock if it exists on boot [ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock + # Pull time from panda + $DIR/selfdrive/boardd/set_time.py + # Check to see if there's a valid overlay-based update available. Conditions # are as follows: # diff --git a/launch_env.sh b/launch_env.sh index da81aa412..a8ab9ad65 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -11,7 +11,7 @@ if [ -z "$REQUIRED_NEOS_VERSION" ]; then fi if [ -z "$AGNOS_VERSION" ]; then - export AGNOS_VERSION="0.11" + export AGNOS_VERSION="0.14" fi if [ -z "$PASSIVE" ]; then diff --git a/opendbc/can/parser.cc b/opendbc/can/parser.cc index 9e23311c0..7e64199a1 100644 --- a/opendbc/can/parser.cc +++ b/opendbc/can/parser.cc @@ -272,6 +272,8 @@ void CANParser::UpdateValid(uint64_t sec) { if (state.check_threshold > 0 && (sec - state.seen) > state.check_threshold) { if (state.seen > 0) { DEBUG("0x%X TIMEOUT\n", state.address); + } else { + DEBUG("0x%X MISSING\n", state.address); } can_valid = false; } diff --git a/opendbc/can/parser_pyx.pyx b/opendbc/can/parser_pyx.pyx index 39f00a573..20a96a6ce 100644 --- a/opendbc/can/parser_pyx.pyx +++ b/opendbc/can/parser_pyx.pyx @@ -33,14 +33,14 @@ cdef class CANParser: bool can_valid int can_invalid_cnt - def __init__(self, dbc_name, signals, checks=None, bus=0): + def __init__(self, dbc_name, signals, checks=None, bus=0, enforce_checks=True): if checks is None: checks = [] self.can_valid = True self.dbc_name = dbc_name self.dbc = dbc_lookup(dbc_name) if not self.dbc: - raise RuntimeError("Can't lookup" + dbc_name) + raise RuntimeError(f"Can't find DBC: {dbc_name}") self.vl = {} self.ts = {} @@ -74,6 +74,14 @@ cdef class CANParser: c = (self.msg_name_to_address[name], c[1]) checks[i] = c + if enforce_checks: + checked_addrs = {c[0] for c in checks} + signal_addrs = {s[1] for s in signals} + unchecked = signal_addrs - checked_addrs + if len(unchecked): + err_msg = ', '.join(f"{self.address_to_msg_name[addr].decode()} ({hex(addr)})" for addr in unchecked) + raise RuntimeError(f"Unchecked addrs: {err_msg}") + cdef vector[SignalParseOptions] signal_options_v cdef SignalParseOptions spo for sig_name, sig_address, sig_default in signals: @@ -108,7 +116,6 @@ cdef class CANParser: self.can_invalid_cnt = 0 self.can_valid = self.can_invalid_cnt < CAN_INVALID_CNT - for cv in can_values: # Cast char * directly to unicode name = self.address_to_msg_name[cv.address].c_str() @@ -149,8 +156,8 @@ cdef class CANDefine(): self.dbc_name = dbc_name self.dbc = dbc_lookup(dbc_name) if not self.dbc: - raise RuntimeError("Can't lookup" + dbc_name) - + raise RuntimeError(f"Can't find DBC: '{dbc_name}'") + num_vals = self.dbc[0].num_vals address_to_msg_name = {} diff --git a/opendbc/honda_civic_touring_2016_can_generated.dbc b/opendbc/honda_civic_touring_2016_can_generated.dbc index 0d6663325..5fe30ac29 100644 --- a/opendbc/honda_civic_touring_2016_can_generated.dbc +++ b/opendbc/honda_civic_touring_2016_can_generated.dbc @@ -346,6 +346,7 @@ BO_ 862 HIGHBEAM_CONTROL: 8 ADAS SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX BO_ 884 STALK_STATUS: 8 XXX + SG_ DASHBOARD_ALERT : 39|8@0+ (1,0) [0|255] "" EON SG_ AUTO_HEADLIGHTS : 46|1@0+ (1,0) [0|1] "" EON SG_ HIGH_BEAM_HOLD : 47|1@0+ (1,0) [0|1] "" EON SG_ HIGH_BEAM_FLASH : 45|1@0+ (1,0) [0|1] "" EON @@ -389,6 +390,7 @@ VAL_ 545 ECON_ON_2 0 "off" 3 "on" ; VAL_ 662 CRUISE_BUTTONS 7 "tbd" 6 "tbd" 5 "tbd" 4 "accel_res" 3 "decel_set" 2 "cancel" 1 "main" 0 "none" ; VAL_ 662 CRUISE_SETTING 3 "distance_adj" 2 "tbd" 1 "lkas_button" 0 "none" ; VAL_ 806 CMBS_BUTTON 3 "pressed" 0 "released" ; +VAL_ 884 DASHBOARD_ALERT 0 "none" 51 "acc_problem" 55 "cmbs_problem" 75 "key_not_detected" 79 "fasten_seatbelt" 111 "lkas_problem" 131 "brake_system_problem" 132 "brake_hold_problem" 139 "tbd" 161 "door_open" VAL_ 891 WIPERS 4 "High" 2 "Low" 0 "Off" ; VAL_ 927 ACC_ALERTS 29 "esp_active_acc_canceled" 10 "b_pedal_applied" 9 "speed_too_low" 8 "speed_too_high" 7 "p_brake_applied" 6 "gear_no_d" 5 "seatbelt" 4 "too_steep_downhill" 3 "too_steep_uphill" 2 "too_close" 1 "no_vehicle_ahead" ; diff --git a/opendbc/lexus_ct200h_2018_pt_generated.dbc b/opendbc/lexus_ct200h_2018_pt_generated.dbc index 30646e552..20dbdd7d7 100644 --- a/opendbc/lexus_ct200h_2018_pt_generated.dbc +++ b/opendbc/lexus_ct200h_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/lexus_is_2018_pt_generated.dbc b/opendbc/lexus_is_2018_pt_generated.dbc index 9f02ded0f..8956c429b 100644 --- a/opendbc/lexus_is_2018_pt_generated.dbc +++ b/opendbc/lexus_is_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/lexus_nx300_2018_pt_generated.dbc b/opendbc/lexus_nx300_2018_pt_generated.dbc index 0f4ddab95..43f059e6b 100644 --- a/opendbc/lexus_nx300_2018_pt_generated.dbc +++ b/opendbc/lexus_nx300_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/lexus_nx300h_2018_pt_generated.dbc b/opendbc/lexus_nx300h_2018_pt_generated.dbc index 1f232541f..6121973e2 100644 --- a/opendbc/lexus_nx300h_2018_pt_generated.dbc +++ b/opendbc/lexus_nx300h_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/lexus_rx_350_2016_pt_generated.dbc b/opendbc/lexus_rx_350_2016_pt_generated.dbc index d96711e42..e55caa5c5 100644 --- a/opendbc/lexus_rx_350_2016_pt_generated.dbc +++ b/opendbc/lexus_rx_350_2016_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/lexus_rx_hybrid_2017_pt_generated.dbc b/opendbc/lexus_rx_hybrid_2017_pt_generated.dbc index 3d1252dc2..516fd5bef 100644 --- a/opendbc/lexus_rx_hybrid_2017_pt_generated.dbc +++ b/opendbc/lexus_rx_hybrid_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_avalon_2017_pt_generated.dbc b/opendbc/toyota_avalon_2017_pt_generated.dbc index f33f079f8..f1f520eb2 100644 --- a/opendbc/toyota_avalon_2017_pt_generated.dbc +++ b/opendbc/toyota_avalon_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_camry_hybrid_2018_pt_generated.dbc b/opendbc/toyota_camry_hybrid_2018_pt_generated.dbc index 17ef5922d..52b999cfb 100644 --- a/opendbc/toyota_camry_hybrid_2018_pt_generated.dbc +++ b/opendbc/toyota_camry_hybrid_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_corolla_2017_pt_generated.dbc b/opendbc/toyota_corolla_2017_pt_generated.dbc index 2f2dc8bdb..229393698 100644 --- a/opendbc/toyota_corolla_2017_pt_generated.dbc +++ b/opendbc/toyota_corolla_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_highlander_2017_pt_generated.dbc b/opendbc/toyota_highlander_2017_pt_generated.dbc index 6cf6d27cb..81a1caf90 100644 --- a/opendbc/toyota_highlander_2017_pt_generated.dbc +++ b/opendbc/toyota_highlander_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_highlander_hybrid_2018_pt_generated.dbc b/opendbc/toyota_highlander_hybrid_2018_pt_generated.dbc index 2d498cf1b..fbf531dd4 100644 --- a/opendbc/toyota_highlander_hybrid_2018_pt_generated.dbc +++ b/opendbc/toyota_highlander_hybrid_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_nodsu_hybrid_pt_generated.dbc b/opendbc/toyota_nodsu_hybrid_pt_generated.dbc index 09ed0690f..9afca5350 100644 --- a/opendbc/toyota_nodsu_hybrid_pt_generated.dbc +++ b/opendbc/toyota_nodsu_hybrid_pt_generated.dbc @@ -1,7 +1,20 @@ CM_ "AUTOGENERATED FILE, DO NOT EDIT"; -CM_ "Imported file _toyota_nodsu_bsm.dbc starts here"; +CM_ "Imported file _toyota_nodsu_common.dbc starts here"; +BO_ 401 STEERING_LTA: 8 XXX + SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX + SG_ SETME_X3 : 29|2@0+ (1,0) [0|3] "" XXX + SG_ PERCENTAGE : 39|8@0+ (1,0) [0|255] "" XXX + SG_ SETME_X64 : 47|8@0+ (1,0) [0|255] "" XXX + SG_ ANGLE : 55|8@0- (0.5,0) [0|255] "" XXX + SG_ STEER_ANGLE_CMD : 15|16@0- (0.0573,0) [-540|540] "" XXX + SG_ STEER_REQUEST : 25|1@0+ (1,0) [0|1] "" XXX + SG_ BIT : 30|1@0+ (1,0) [0|1] "" XXX + SG_ COUNTER : 6|6@0+ (1,0) [0|255] "" XXX + SG_ STEER_REQUEST_2 : 0|1@0+ (1,0) [0|1] "" XXX + SG_ SETME_X1 : 7|1@0+ (1,0) [0|1] "" XXX + BO_ 1014 BSM: 8 XXX SG_ L_ADJACENT : 0|1@0+ (1,0) [0|1] "" XXX SG_ L_APPROACHING : 8|1@0+ (1,0) [0|1] "" XXX @@ -275,6 +288,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -285,6 +299,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -381,7 +399,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_nodsu_pt_generated.dbc b/opendbc/toyota_nodsu_pt_generated.dbc index bf2f02e4f..2bfabcc23 100644 --- a/opendbc/toyota_nodsu_pt_generated.dbc +++ b/opendbc/toyota_nodsu_pt_generated.dbc @@ -1,7 +1,20 @@ CM_ "AUTOGENERATED FILE, DO NOT EDIT"; -CM_ "Imported file _toyota_nodsu_bsm.dbc starts here"; +CM_ "Imported file _toyota_nodsu_common.dbc starts here"; +BO_ 401 STEERING_LTA: 8 XXX + SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX + SG_ SETME_X3 : 29|2@0+ (1,0) [0|3] "" XXX + SG_ PERCENTAGE : 39|8@0+ (1,0) [0|255] "" XXX + SG_ SETME_X64 : 47|8@0+ (1,0) [0|255] "" XXX + SG_ ANGLE : 55|8@0- (0.5,0) [0|255] "" XXX + SG_ STEER_ANGLE_CMD : 15|16@0- (0.0573,0) [-540|540] "" XXX + SG_ STEER_REQUEST : 25|1@0+ (1,0) [0|1] "" XXX + SG_ BIT : 30|1@0+ (1,0) [0|1] "" XXX + SG_ COUNTER : 6|6@0+ (1,0) [0|255] "" XXX + SG_ STEER_REQUEST_2 : 0|1@0+ (1,0) [0|1] "" XXX + SG_ SETME_X1 : 7|1@0+ (1,0) [0|1] "" XXX + BO_ 1014 BSM: 8 XXX SG_ L_ADJACENT : 0|1@0+ (1,0) [0|1] "" XXX SG_ L_APPROACHING : 8|1@0+ (1,0) [0|1] "" XXX @@ -275,6 +288,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -285,6 +299,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -381,7 +399,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; @@ -392,19 +410,6 @@ CM_ "toyota_nodsu_pt.dbc starts here"; -BO_ 401 STEERING_LTA: 8 XXX - SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX - SG_ SETME_X3 : 29|2@0+ (1,0) [0|3] "" XXX - SG_ PERCENTAGE : 39|8@0+ (1,0) [0|255] "" XXX - SG_ SETME_X64 : 47|8@0+ (1,0) [0|255] "" XXX - SG_ ANGLE : 55|8@0- (0.5,0) [0|255] "" XXX - SG_ STEER_ANGLE_CMD : 15|16@0- (0.0573,0) [-540|540] "" XXX - SG_ STEER_REQUEST : 25|1@0+ (1,0) [0|1] "" XXX - SG_ BIT : 30|1@0+ (1,0) [0|1] "" XXX - SG_ COUNTER : 6|6@0+ (1,0) [0|255] "" XXX - SG_ STEER_REQUEST_2 : 0|1@0+ (1,0) [0|1] "" XXX - SG_ SETME_X1 : 7|1@0+ (1,0) [0|1] "" XXX - BO_ 550 BRAKE_MODULE: 8 XXX SG_ BRAKE_PRESSURE : 0|9@0+ (1,0) [0|511] "" XXX SG_ BRAKE_POSITION : 16|9@0+ (1,0) [0|511] "" XXX diff --git a/opendbc/toyota_prius_2017_pt_generated.dbc b/opendbc/toyota_prius_2017_pt_generated.dbc index e44e776f5..40fa754f4 100644 --- a/opendbc/toyota_prius_2017_pt_generated.dbc +++ b/opendbc/toyota_prius_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_rav4_2017_pt_generated.dbc b/opendbc/toyota_rav4_2017_pt_generated.dbc index 703726026..724aae6bb 100644 --- a/opendbc/toyota_rav4_2017_pt_generated.dbc +++ b/opendbc/toyota_rav4_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_rav4_hybrid_2017_pt_generated.dbc b/opendbc/toyota_rav4_hybrid_2017_pt_generated.dbc index 99f724ea9..0b36f13dc 100644 --- a/opendbc/toyota_rav4_hybrid_2017_pt_generated.dbc +++ b/opendbc/toyota_rav4_hybrid_2017_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/opendbc/toyota_sienna_xle_2018_pt_generated.dbc b/opendbc/toyota_sienna_xle_2018_pt_generated.dbc index 06b9388bc..3a7ad53c0 100644 --- a/opendbc/toyota_sienna_xle_2018_pt_generated.dbc +++ b/opendbc/toyota_sienna_xle_2018_pt_generated.dbc @@ -258,6 +258,7 @@ BO_ 1553 UI_SETTING: 8 XXX BO_ 1556 STEERING_LEVERS: 8 XXX SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX + SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX BO_ 1568 SEATS_DOORS: 8 XXX SG_ SEATBELT_DRIVER_UNLATCHED : 62|1@0+ (1,0) [0|1] "" XXX @@ -268,6 +269,10 @@ BO_ 1568 SEATS_DOORS: 8 XXX BO_ 1570 LIGHT_STALK: 8 SCM SG_ AUTO_HIGH_BEAM : 37|1@0+ (1,0) [0|1] "" XXX + SG_ FRONT_FOG : 27|1@0+ (1,0) [0|1] "" XXX + SG_ PARKING_LIGHT : 28|1@0+ (1,0) [0|1] "" XXX + SG_ LOW_BEAM : 29|1@0+ (1,0) [0|1] "" XXX + SG_ HIGH_BEAM : 30|1@0+ (1,0) [0|1] "" XXX BO_ 1161 RSA1: 8 FCM SG_ TSGN1 : 7|8@0+ (1,0) [0|0] "" XXX @@ -364,7 +369,7 @@ VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left"; VAL_ 1161 TSGN1 1 "speed sign" 0 "none"; VAL_ 1161 TSGN2 1 "speed sign" 0 "none"; VAL_ 1161 SPLSGN2 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; -VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 129 "no entry"; +VAL_ 1162 TSGN3 0 "none" 1 "speed sign" 2 "0 unlimited" 7 "unlimited" 16 "highway" 17 "no highway" 18 "motorway" 19 "no motorway" 20 "in city" 21 "outside city" 22 "pedestrian area" 23 "no pedestrian area" 65 "no overtaking left" 66 "no overtaking right" 67 "overtaking allowed again" 81 "no right turn" 97 "stop" 105 "yield" 113 "stop" 114 "yield us" 129 "no entry" 138 "no entry tss2" 145 "do not enter"; VAL_ 1162 SPLSGN3 15 "conditional blank" 4 "wet road" 5 "rain" 0 "none"; diff --git a/panda/.gitignore b/panda/.gitignore index 2cd2eb8e5..3a8ead1e0 100644 --- a/panda/.gitignore +++ b/panda/.gitignore @@ -3,6 +3,7 @@ .*.swo *.o *.so +*.os *.d *.dump a.out diff --git a/panda/board/SConscript b/panda/board/SConscript index 902498ace..167da9e24 100644 --- a/panda/board/SConscript +++ b/panda/board/SConscript @@ -136,6 +136,11 @@ panda_env = Environment( # Common autogenerated includes version = f'const uint8_t gitversion[] = "{get_version(BUILDER, BUILD_TYPE)}";' gitversion = panda_env.Textfile("obj/gitversion.h", [version, ""]) +Ignore('bootstub.o', gitversion) +Requires('bootstub.o', gitversion) +Ignore('main.o', gitversion) +Requires('main.o', gitversion) + certs = [get_key_header(n) for n in ["debug", "release"]] certheader = panda_env.Textfile("obj/cert.h", certs + [""]) @@ -144,13 +149,11 @@ startup = panda_env.Object(STARTUP_FILE) # Bootstub crypto = ["../crypto/rsa.c", "../crypto/sha.c"] bootstub_elf = panda_env.Program(f"obj/bootstub.{PROJECT}.elf", [startup] + crypto + ["bootstub.c"]) -Requires(bootstub_elf, gitversion) bootstub_bin = panda_env.Objcopy(f"obj/bootstub.{PROJECT}.bin", bootstub_elf) # Build main main_elf = panda_env.Program(f"obj/{PROJECT}.elf", [startup, MAIN], LINKFLAGS=["-Wl,--section-start,.isr_vector=0x8004000"] + flags) -Requires(main_elf, gitversion) main_bin = panda_env.Objcopy(f"obj/{PROJECT}.bin", main_elf) # Sign main diff --git a/panda/board/gpio.h b/panda/board/gpio.h index b50de50c3..01d3b8a3c 100644 --- a/panda/board/gpio.h +++ b/panda/board/gpio.h @@ -12,6 +12,7 @@ void jump_to_bootloader(void) { void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *)0x1fff0004)); // jump to bootloader + enable_interrupts(); bootloader(); // reset on exit @@ -21,14 +22,12 @@ void jump_to_bootloader(void) { void early(void) { // Reset global critical depth + disable_interrupts(); global_critical_depth = 0; // Init register and interrupt tables init_registers(); - // neccesary for DFU flashing on a non-power cycled white panda - enable_interrupts(); - // after it's been in the bootloader, things are initted differently, so we reset if ((enter_bootloader_mode != BOOT_NORMAL) && (enter_bootloader_mode != ENTER_BOOTLOADER_MAGIC) && diff --git a/panda/board/safety/safety_hyundai.h b/panda/board/safety/safety_hyundai.h index a4a6d4c2a..39966e0dc 100644 --- a/panda/board/safety/safety_hyundai.h +++ b/panda/board/safety/safety_hyundai.h @@ -17,11 +17,9 @@ const CanMsg HYUNDAI_TX_MSGS[] = { // {1186, 0, 8} // 4a2SCC, Bus 0 }; -// TODO: missing checksum for wheel speeds message,worst failure case is -// wheel speeds stuck at 0 and we don't disengage on brake press AddrCheckStruct hyundai_rx_checks[] = { {.msg = {{608, 0, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}}}, - {.msg = {{902, 0, 8, .check_checksum = false, .max_counter = 15U, .expected_timestep = 10000U}}}, + {.msg = {{902, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}}}, {.msg = {{916, 0, 8, .check_checksum = true, .max_counter = 7U, .expected_timestep = 10000U}}}, {.msg = {{1057, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, }; @@ -63,6 +61,8 @@ static uint8_t hyundai_get_checksum(CAN_FIFOMailBox_TypeDef *to_push) { uint8_t chksum; if (addr == 608) { chksum = GET_BYTE(to_push, 7) & 0xF; + } else if (addr == 902) { + chksum = ((GET_BYTE(to_push, 7) >> 6) << 2) | (GET_BYTE(to_push, 5) >> 6); } else if (addr == 916) { chksum = GET_BYTE(to_push, 6) & 0xF; } else if (addr == 1057) { @@ -77,15 +77,36 @@ static uint8_t hyundai_compute_checksum(CAN_FIFOMailBox_TypeDef *to_push) { int addr = GET_ADDR(to_push); uint8_t chksum = 0; - // same algorithm, but checksum is in a different place - for (int i = 0; i < 8; i++) { - uint8_t b = GET_BYTE(to_push, i); - if (((addr == 608) && (i == 7)) || ((addr == 916) && (i == 6)) || ((addr == 1057) && (i == 7))) { - b &= (addr == 1057) ? 0x0FU : 0xF0U; // remove checksum + if (addr == 902) { + // count the bits + for (int i = 0; i < 8; i++) { + uint8_t b = GET_BYTE(to_push, i); + for (int j = 0; j < 8; j++) { + uint8_t bit = 0; + // exclude checksum and counter + if (((i != 1) || (j < 6)) && ((i != 3) || (j < 6)) && ((i != 5) || (j < 6)) && ((i != 7) || (j < 6))) { + bit = (b >> (uint8_t)j) & 1U; + } + chksum += bit; + } } - chksum += (b % 16U) + (b / 16U); + chksum = (chksum ^ 9U) & 15U; + } else { + // sum of nibbles + for (int i = 0; i < 8; i++) { + if ((addr == 916) && (i == 7)) { + continue; // exclude + } + uint8_t b = GET_BYTE(to_push, i); + if (((addr == 608) && (i == 7)) || ((addr == 916) && (i == 6)) || ((addr == 1057) && (i == 7))) { + b &= (addr == 1057) ? 0x0FU : 0xF0U; // remove checksum + } + chksum += (b % 16U) + (b / 16U); + } + chksum = (16U - (chksum % 16U)) % 16U; } - return (16U - (chksum % 16U)) % 16U; + + return chksum; } static int hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { diff --git a/panda/board/safety/safety_toyota.h b/panda/board/safety/safety_toyota.h index 2ffe58b5f..241e5798f 100644 --- a/panda/board/safety/safety_toyota.h +++ b/panda/board/safety/safety_toyota.h @@ -30,9 +30,9 @@ const int TOYOTA_GAS_INTERCEPTOR_THRSLD = 845; #define TOYOTA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2) // avg between 2 tracks const CanMsg TOYOTA_TX_MSGS[] = {{0x283, 0, 7}, {0x2E6, 0, 8}, {0x2E7, 0, 8}, {0x33E, 0, 7}, {0x344, 0, 8}, {0x365, 0, 7}, {0x366, 0, 7}, {0x4CB, 0, 8}, // DSU bus 0 - {0x128, 1, 6}, {0x141, 1, 4}, {0x160, 1, 8}, {0x161, 1, 7}, {0x470, 1, 4}, // DSU bus 1 - {0x2E4, 0, 5}, {0x411, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, // LKAS + ACC - {0x200, 0, 6}}; // interceptor + {0x128, 1, 6}, {0x141, 1, 4}, {0x160, 1, 8}, {0x161, 1, 7}, {0x470, 1, 4}, // DSU bus 1 + {0x2E4, 0, 5}, {0x191, 0, 8}, {0x411, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, // LKAS + ACC + {0x200, 0, 6}}; // interceptor AddrCheckStruct toyota_rx_checks[] = { {.msg = {{ 0xaa, 0, 8, .check_checksum = false, .expected_timestep = 12000U}}}, @@ -180,6 +180,21 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { } } + // LTA steering check + // only sent to prevent dash errors, no actuation is accepted + if (addr == 0x191) { + // check the STEER_REQUEST, STEER_REQUEST_2, and STEER_ANGLE_CMD signals + bool lta_request = (GET_BYTE(to_send, 0) & 1) != 0; + bool lta_request2 = ((GET_BYTE(to_send, 3) >> 1) & 1) != 0; + int lta_angle = (GET_BYTE(to_send, 1) << 8) | GET_BYTE(to_send, 2); + lta_angle = to_signed(lta_angle, 16); + + // block LTA msgs with actuation requests + if (lta_request || lta_request2 || (lta_angle != 0)) { + tx = 0; + } + } + // STEER: safety check on bytes 2-3 if (addr == 0x2E4) { int desired_torque = (GET_BYTE(to_send, 1) << 8) | GET_BYTE(to_send, 2); diff --git a/panda/python/__init__.py b/panda/python/__init__.py index 1c02f751c..13d543f8c 100644 --- a/panda/python/__init__.py +++ b/panda/python/__init__.py @@ -179,7 +179,7 @@ class Panda(object): self.bootstub = device.getProductID() == 0xddee self.legacy = (device.getbcdDevice() != 0x2300) self._handle = device.open() - if sys.platform not in ["win32", "cygwin", "msys"]: + if sys.platform not in ["win32", "cygwin", "msys", "darwin"]: self._handle.setAutoDetachKernelDriver(True) if claim: self._handle.claimInterface(0) diff --git a/panda/python/uds.py b/panda/python/uds.py index 243dd5acf..5106e6de8 100644 --- a/panda/python/uds.py +++ b/panda/python/uds.py @@ -240,7 +240,7 @@ _negative_response_codes = { 0x31: 'request out of range', 0x33: 'security access denied', 0x35: 'invalid key', - 0x36: 'exceed numebr of attempts', + 0x36: 'exceed number of attempts', 0x37: 'required time delay not expired', 0x70: 'upload download not accepted', 0x71: 'transfer data suspended', diff --git a/phonelibs/SConscript b/phonelibs/SConscript index a23b02a8e..5a7a62ae5 100644 --- a/phonelibs/SConscript +++ b/phonelibs/SConscript @@ -2,3 +2,5 @@ Import('env') env.Library('json11', ['json11/json11.cpp']) env.Append(CPPPATH=[Dir('json11')]) + +env.Library('kaitai', ['kaitai/kaitaistream.cpp'], CPPDEFINES=['KS_STR_ENCODING_NONE']) diff --git a/phonelibs/kaitai/custom_decoder.h b/phonelibs/kaitai/custom_decoder.h new file mode 100644 index 000000000..6da7f5fd2 --- /dev/null +++ b/phonelibs/kaitai/custom_decoder.h @@ -0,0 +1,16 @@ +#ifndef KAITAI_CUSTOM_DECODER_H +#define KAITAI_CUSTOM_DECODER_H + +#include + +namespace kaitai { + +class custom_decoder { +public: + virtual ~custom_decoder() {}; + virtual std::string decode(std::string src) = 0; +}; + +} + +#endif diff --git a/phonelibs/kaitai/exceptions.h b/phonelibs/kaitai/exceptions.h new file mode 100644 index 000000000..5c09c4672 --- /dev/null +++ b/phonelibs/kaitai/exceptions.h @@ -0,0 +1,189 @@ +#ifndef KAITAI_EXCEPTIONS_H +#define KAITAI_EXCEPTIONS_H + +#include + +#include +#include + +// We need to use "noexcept" in virtual destructor of our exceptions +// subclasses. Different compilers have different ideas on how to +// achieve that: C++98 compilers prefer `throw()`, C++11 and later +// use `noexcept`. We define KS_NOEXCEPT macro for that. + +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +#define KS_NOEXCEPT noexcept +#else +#define KS_NOEXCEPT throw() +#endif + +namespace kaitai { + +/** + * Common ancestor for all error originating from Kaitai Struct usage. + * Stores KSY source path, pointing to an element supposedly guilty of + * an error. + */ +class kstruct_error: public std::runtime_error { +public: + kstruct_error(const std::string what, const std::string src_path): + std::runtime_error(src_path + ": " + what), + m_src_path(src_path) + { + } + + virtual ~kstruct_error() KS_NOEXCEPT {}; + +protected: + const std::string m_src_path; +}; + +/** + * Error that occurs when default endianness should be decided with + * a switch, but nothing matches (although using endianness expression + * implies that there should be some positive result). + */ +class undecided_endianness_error: public kstruct_error { +public: + undecided_endianness_error(const std::string src_path): + kstruct_error("unable to decide on endianness for a type", src_path) + { + } + + virtual ~undecided_endianness_error() KS_NOEXCEPT {}; +}; + +/** + * Common ancestor for all validation failures. Stores pointer to + * KaitaiStream IO object which was involved in an error. + */ +class validation_failed_error: public kstruct_error { +public: + validation_failed_error(const std::string what, kstream* io, const std::string src_path): + kstruct_error("at pos " + kstream::to_string(static_cast(io->pos())) + ": validation failed: " + what, src_path), + m_io(io) + { + } + +// "at pos #{io.pos}: validation failed: #{msg}" + + virtual ~validation_failed_error() KS_NOEXCEPT {}; + +protected: + kstream* m_io; +}; + +/** + * Signals validation failure: we required "actual" value to be equal to + * "expected", but it turned out that it's not. + */ +template +class validation_not_equal_error: public validation_failed_error { +public: + validation_not_equal_error(const T& expected, const T& actual, kstream* io, const std::string src_path): + validation_failed_error("not equal", io, src_path), + m_expected(expected), + m_actual(actual) + { + } + + // "not equal, expected #{expected.inspect}, but got #{actual.inspect}" + + virtual ~validation_not_equal_error() KS_NOEXCEPT {}; + +protected: + const T& m_expected; + const T& m_actual; +}; + +/** + * Signals validation failure: we required "actual" value to be greater + * than or equal to "min", but it turned out that it's not. + */ +template +class validation_less_than_error: public validation_failed_error { +public: + validation_less_than_error(const T& min, const T& actual, kstream* io, const std::string src_path): + validation_failed_error("not in range", io, src_path), + m_min(min), + m_actual(actual) + { + } + + // "not in range, min #{min.inspect}, but got #{actual.inspect}" + + virtual ~validation_less_than_error() KS_NOEXCEPT {}; + +protected: + const T& m_min; + const T& m_actual; +}; + +/** + * Signals validation failure: we required "actual" value to be less + * than or equal to "max", but it turned out that it's not. + */ +template +class validation_greater_than_error: public validation_failed_error { +public: + validation_greater_than_error(const T& max, const T& actual, kstream* io, const std::string src_path): + validation_failed_error("not in range", io, src_path), + m_max(max), + m_actual(actual) + { + } + + // "not in range, max #{max.inspect}, but got #{actual.inspect}" + + virtual ~validation_greater_than_error() KS_NOEXCEPT {}; + +protected: + const T& m_max; + const T& m_actual; +}; + +/** + * Signals validation failure: we required "actual" value to be from + * the list, but it turned out that it's not. + */ +template +class validation_not_any_of_error: public validation_failed_error { +public: + validation_not_any_of_error(const T& actual, kstream* io, const std::string src_path): + validation_failed_error("not any of the list", io, src_path), + m_actual(actual) + { + } + + // "not any of the list, got #{actual.inspect}" + + virtual ~validation_not_any_of_error() KS_NOEXCEPT {}; + +protected: + const T& m_actual; +}; + +/** + * Signals validation failure: we required "actual" value to match + * the expression, but it turned out that it doesn't. + */ +template +class validation_expr_error: public validation_failed_error { +public: + validation_expr_error(const T& actual, kstream* io, const std::string src_path): + validation_failed_error("not matching the expression", io, src_path), + m_actual(actual) + { + } + + // "not matching the expression, got #{actual.inspect}" + + virtual ~validation_expr_error() KS_NOEXCEPT {}; + +protected: + const T& m_actual; +}; + +} + +#endif diff --git a/phonelibs/kaitai/kaitaistream.cpp b/phonelibs/kaitai/kaitaistream.cpp new file mode 100644 index 000000000..d82ddb7e8 --- /dev/null +++ b/phonelibs/kaitai/kaitaistream.cpp @@ -0,0 +1,689 @@ +#include + +#if defined(__APPLE__) +#include +#include +#define bswap_16(x) OSSwapInt16(x) +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#elif defined(_MSC_VER) // !__APPLE__ +#include +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN +#define bswap_16(x) _byteswap_ushort(x) +#define bswap_32(x) _byteswap_ulong(x) +#define bswap_64(x) _byteswap_uint64(x) +#else // !__APPLE__ or !_MSC_VER +#include +#include +#endif + +#include +#include +#include + +kaitai::kstream::kstream(std::istream* io) { + m_io = io; + init(); +} + +kaitai::kstream::kstream(std::string& data): m_io_str(data) { + m_io = &m_io_str; + init(); +} + +void kaitai::kstream::init() { + exceptions_enable(); + align_to_byte(); +} + +void kaitai::kstream::close() { + // m_io->close(); +} + +void kaitai::kstream::exceptions_enable() const { + m_io->exceptions( + std::istream::eofbit | + std::istream::failbit | + std::istream::badbit + ); +} + +// ======================================================================== +// Stream positioning +// ======================================================================== + +bool kaitai::kstream::is_eof() const { + if (m_bits_left > 0) { + return false; + } + char t; + m_io->exceptions( + std::istream::badbit + ); + m_io->get(t); + if (m_io->eof()) { + m_io->clear(); + exceptions_enable(); + return true; + } else { + m_io->unget(); + exceptions_enable(); + return false; + } +} + +void kaitai::kstream::seek(uint64_t pos) { + m_io->seekg(pos); +} + +uint64_t kaitai::kstream::pos() { + return m_io->tellg(); +} + +uint64_t kaitai::kstream::size() { + std::iostream::pos_type cur_pos = m_io->tellg(); + m_io->seekg(0, std::ios::end); + std::iostream::pos_type len = m_io->tellg(); + m_io->seekg(cur_pos); + return len; +} + +// ======================================================================== +// Integer numbers +// ======================================================================== + +// ------------------------------------------------------------------------ +// Signed +// ------------------------------------------------------------------------ + +int8_t kaitai::kstream::read_s1() { + char t; + m_io->get(t); + return t; +} + +// ........................................................................ +// Big-endian +// ........................................................................ + +int16_t kaitai::kstream::read_s2be() { + int16_t t; + m_io->read(reinterpret_cast(&t), 2); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_16(t); +#endif + return t; +} + +int32_t kaitai::kstream::read_s4be() { + int32_t t; + m_io->read(reinterpret_cast(&t), 4); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_32(t); +#endif + return t; +} + +int64_t kaitai::kstream::read_s8be() { + int64_t t; + m_io->read(reinterpret_cast(&t), 8); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_64(t); +#endif + return t; +} + +// ........................................................................ +// Little-endian +// ........................................................................ + +int16_t kaitai::kstream::read_s2le() { + int16_t t; + m_io->read(reinterpret_cast(&t), 2); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_16(t); +#endif + return t; +} + +int32_t kaitai::kstream::read_s4le() { + int32_t t; + m_io->read(reinterpret_cast(&t), 4); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_32(t); +#endif + return t; +} + +int64_t kaitai::kstream::read_s8le() { + int64_t t; + m_io->read(reinterpret_cast(&t), 8); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_64(t); +#endif + return t; +} + +// ------------------------------------------------------------------------ +// Unsigned +// ------------------------------------------------------------------------ + +uint8_t kaitai::kstream::read_u1() { + char t; + m_io->get(t); + return t; +} + +// ........................................................................ +// Big-endian +// ........................................................................ + +uint16_t kaitai::kstream::read_u2be() { + uint16_t t; + m_io->read(reinterpret_cast(&t), 2); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_16(t); +#endif + return t; +} + +uint32_t kaitai::kstream::read_u4be() { + uint32_t t; + m_io->read(reinterpret_cast(&t), 4); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_32(t); +#endif + return t; +} + +uint64_t kaitai::kstream::read_u8be() { + uint64_t t; + m_io->read(reinterpret_cast(&t), 8); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_64(t); +#endif + return t; +} + +// ........................................................................ +// Little-endian +// ........................................................................ + +uint16_t kaitai::kstream::read_u2le() { + uint16_t t; + m_io->read(reinterpret_cast(&t), 2); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_16(t); +#endif + return t; +} + +uint32_t kaitai::kstream::read_u4le() { + uint32_t t; + m_io->read(reinterpret_cast(&t), 4); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_32(t); +#endif + return t; +} + +uint64_t kaitai::kstream::read_u8le() { + uint64_t t; + m_io->read(reinterpret_cast(&t), 8); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_64(t); +#endif + return t; +} + +// ======================================================================== +// Floating point numbers +// ======================================================================== + +// ........................................................................ +// Big-endian +// ........................................................................ + +float kaitai::kstream::read_f4be() { + uint32_t t; + m_io->read(reinterpret_cast(&t), 4); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_32(t); +#endif + return reinterpret_cast(t); +} + +double kaitai::kstream::read_f8be() { + uint64_t t; + m_io->read(reinterpret_cast(&t), 8); +#if __BYTE_ORDER == __LITTLE_ENDIAN + t = bswap_64(t); +#endif + return reinterpret_cast(t); +} + +// ........................................................................ +// Little-endian +// ........................................................................ + +float kaitai::kstream::read_f4le() { + uint32_t t; + m_io->read(reinterpret_cast(&t), 4); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_32(t); +#endif + return reinterpret_cast(t); +} + +double kaitai::kstream::read_f8le() { + uint64_t t; + m_io->read(reinterpret_cast(&t), 8); +#if __BYTE_ORDER == __BIG_ENDIAN + t = bswap_64(t); +#endif + return reinterpret_cast(t); +} + +// ======================================================================== +// Unaligned bit values +// ======================================================================== + +void kaitai::kstream::align_to_byte() { + m_bits_left = 0; + m_bits = 0; +} + +uint64_t kaitai::kstream::read_bits_int_be(int n) { + int bits_needed = n - m_bits_left; + if (bits_needed > 0) { + // 1 bit => 1 byte + // 8 bits => 1 byte + // 9 bits => 2 bytes + int bytes_needed = ((bits_needed - 1) / 8) + 1; + if (bytes_needed > 8) + throw std::runtime_error("read_bits_int: more than 8 bytes requested"); + char buf[8]; + m_io->read(buf, bytes_needed); + for (int i = 0; i < bytes_needed; i++) { + uint8_t b = buf[i]; + m_bits <<= 8; + m_bits |= b; + m_bits_left += 8; + } + } + + // raw mask with required number of 1s, starting from lowest bit + uint64_t mask = get_mask_ones(n); + // shift mask to align with highest bits available in @bits + int shift_bits = m_bits_left - n; + mask <<= shift_bits; + // derive reading result + uint64_t res = (m_bits & mask) >> shift_bits; + // clear top bits that we've just read => AND with 1s + m_bits_left -= n; + mask = get_mask_ones(m_bits_left); + m_bits &= mask; + + return res; +} + +// Deprecated, use read_bits_int_be() instead. +uint64_t kaitai::kstream::read_bits_int(int n) { + return read_bits_int_be(n); +} + +uint64_t kaitai::kstream::read_bits_int_le(int n) { + int bits_needed = n - m_bits_left; + if (bits_needed > 0) { + // 1 bit => 1 byte + // 8 bits => 1 byte + // 9 bits => 2 bytes + int bytes_needed = ((bits_needed - 1) / 8) + 1; + if (bytes_needed > 8) + throw std::runtime_error("read_bits_int_le: more than 8 bytes requested"); + char buf[8]; + m_io->read(buf, bytes_needed); + for (int i = 0; i < bytes_needed; i++) { + uint8_t b = buf[i]; + m_bits |= (static_cast(b) << m_bits_left); + m_bits_left += 8; + } + } + + // raw mask with required number of 1s, starting from lowest bit + uint64_t mask = get_mask_ones(n); + // derive reading result + uint64_t res = m_bits & mask; + // remove bottom bits that we've just read by shifting + m_bits >>= n; + m_bits_left -= n; + + return res; +} + +uint64_t kaitai::kstream::get_mask_ones(int n) { + if (n == 64) { + return 0xFFFFFFFFFFFFFFFF; + } else { + return ((uint64_t) 1 << n) - 1; + } +} + +// ======================================================================== +// Byte arrays +// ======================================================================== + +std::string kaitai::kstream::read_bytes(std::streamsize len) { + std::vector result(len); + + // NOTE: streamsize type is signed, negative values are only *supposed* to not be used. + // http://en.cppreference.com/w/cpp/io/streamsize + if (len < 0) { + throw std::runtime_error("read_bytes: requested a negative amount"); + } + + if (len > 0) { + m_io->read(&result[0], len); + } + + return std::string(result.begin(), result.end()); +} + +std::string kaitai::kstream::read_bytes_full() { + std::iostream::pos_type p1 = m_io->tellg(); + m_io->seekg(0, std::ios::end); + std::iostream::pos_type p2 = m_io->tellg(); + size_t len = p2 - p1; + + // Note: this requires a std::string to be backed with a + // contiguous buffer. Officially, it's a only requirement since + // C++11 (C++98 and C++03 didn't have this requirement), but all + // major implementations had contiguous buffers anyway. + std::string result(len, ' '); + m_io->seekg(p1); + m_io->read(&result[0], len); + + return result; +} + +std::string kaitai::kstream::read_bytes_term(char term, bool include, bool consume, bool eos_error) { + std::string result; + std::getline(*m_io, result, term); + if (m_io->eof()) { + // encountered EOF + if (eos_error) { + throw std::runtime_error("read_bytes_term: encountered EOF"); + } + } else { + // encountered terminator + if (include) + result.push_back(term); + if (!consume) + m_io->unget(); + } + return result; +} + +std::string kaitai::kstream::ensure_fixed_contents(std::string expected) { + std::string actual = read_bytes(expected.length()); + + if (actual != expected) { + // NOTE: I think printing it outright is not best idea, it could contain non-ascii charactes like backspace and beeps and whatnot. It would be better to print hexlified version, and also to redirect it to stderr. + throw std::runtime_error("ensure_fixed_contents: actual data does not match expected data"); + } + + return actual; +} + +std::string kaitai::kstream::bytes_strip_right(std::string src, char pad_byte) { + std::size_t new_len = src.length(); + + while (new_len > 0 && src[new_len - 1] == pad_byte) + new_len--; + + return src.substr(0, new_len); +} + +std::string kaitai::kstream::bytes_terminate(std::string src, char term, bool include) { + std::size_t new_len = 0; + std::size_t max_len = src.length(); + + while (new_len < max_len && src[new_len] != term) + new_len++; + + if (include && new_len < max_len) + new_len++; + + return src.substr(0, new_len); +} + +// ======================================================================== +// Byte array processing +// ======================================================================== + +std::string kaitai::kstream::process_xor_one(std::string data, uint8_t key) { + size_t len = data.length(); + std::string result(len, ' '); + + for (size_t i = 0; i < len; i++) + result[i] = data[i] ^ key; + + return result; +} + +std::string kaitai::kstream::process_xor_many(std::string data, std::string key) { + size_t len = data.length(); + size_t kl = key.length(); + std::string result(len, ' '); + + size_t ki = 0; + for (size_t i = 0; i < len; i++) { + result[i] = data[i] ^ key[ki]; + ki++; + if (ki >= kl) + ki = 0; + } + + return result; +} + +std::string kaitai::kstream::process_rotate_left(std::string data, int amount) { + size_t len = data.length(); + std::string result(len, ' '); + + for (size_t i = 0; i < len; i++) { + uint8_t bits = data[i]; + result[i] = (bits << amount) | (bits >> (8 - amount)); + } + + return result; +} + +#ifdef KS_ZLIB +#include + +std::string kaitai::kstream::process_zlib(std::string data) { + int ret; + + unsigned char *src_ptr = reinterpret_cast(&data[0]); + std::stringstream dst_strm; + + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + ret = inflateInit(&strm); + if (ret != Z_OK) + throw std::runtime_error("process_zlib: inflateInit error"); + + strm.next_in = src_ptr; + strm.avail_in = data.length(); + + unsigned char outbuffer[ZLIB_BUF_SIZE]; + std::string outstring; + + // get the decompressed bytes blockwise using repeated calls to inflate + do { + strm.next_out = reinterpret_cast(outbuffer); + strm.avail_out = sizeof(outbuffer); + + ret = inflate(&strm, 0); + + if (outstring.size() < strm.total_out) + outstring.append(reinterpret_cast(outbuffer), strm.total_out - outstring.size()); + } while (ret == Z_OK); + + if (ret != Z_STREAM_END) { // an error occurred that was not EOF + std::ostringstream exc_msg; + exc_msg << "process_zlib: error #" << ret << "): " << strm.msg; + throw std::runtime_error(exc_msg.str()); + } + + if (inflateEnd(&strm) != Z_OK) + throw std::runtime_error("process_zlib: inflateEnd error"); + + return outstring; +} +#endif + +// ======================================================================== +// Misc utility methods +// ======================================================================== + +int kaitai::kstream::mod(int a, int b) { + if (b <= 0) + throw std::invalid_argument("mod: divisor b <= 0"); + int r = a % b; + if (r < 0) + r += b; + return r; +} + +#include +std::string kaitai::kstream::to_string(int val) { + // if int is 32 bits, "-2147483648" is the longest string representation + // => 11 chars + zero => 12 chars + // if int is 64 bits, "-9223372036854775808" is the longest + // => 20 chars + zero => 21 chars + char buf[25]; + int got_len = snprintf(buf, sizeof(buf), "%d", val); + + // should never happen, but check nonetheless + if (got_len > sizeof(buf)) + throw std::invalid_argument("to_string: integer is longer than string buffer"); + + return std::string(buf); +} + +#include +std::string kaitai::kstream::reverse(std::string val) { + std::reverse(val.begin(), val.end()); + + return val; +} + +uint8_t kaitai::kstream::byte_array_min(const std::string val) { + uint8_t min = 0xff; // UINT8_MAX + std::string::const_iterator end = val.end(); + for (std::string::const_iterator it = val.begin(); it != end; ++it) { + uint8_t cur = static_cast(*it); + if (cur < min) { + min = cur; + } + } + return min; +} + +uint8_t kaitai::kstream::byte_array_max(const std::string val) { + uint8_t max = 0; // UINT8_MIN + std::string::const_iterator end = val.end(); + for (std::string::const_iterator it = val.begin(); it != end; ++it) { + uint8_t cur = static_cast(*it); + if (cur > max) { + max = cur; + } + } + return max; +} + +// ======================================================================== +// Other internal methods +// ======================================================================== + +#ifndef KS_STR_DEFAULT_ENCODING +#define KS_STR_DEFAULT_ENCODING "UTF-8" +#endif + +#ifdef KS_STR_ENCODING_ICONV + +#include +#include +#include + +std::string kaitai::kstream::bytes_to_str(std::string src, std::string src_enc) { + iconv_t cd = iconv_open(KS_STR_DEFAULT_ENCODING, src_enc.c_str()); + + if (cd == (iconv_t) -1) { + if (errno == EINVAL) { + throw std::runtime_error("bytes_to_str: invalid encoding pair conversion requested"); + } else { + throw std::runtime_error("bytes_to_str: error opening iconv"); + } + } + + size_t src_len = src.length(); + size_t src_left = src_len; + + // Start with a buffer length of double the source length. + size_t dst_len = src_len * 2; + std::string dst(dst_len, ' '); + size_t dst_left = dst_len; + + char *src_ptr = &src[0]; + char *dst_ptr = &dst[0]; + + while (true) { + size_t res = iconv(cd, &src_ptr, &src_left, &dst_ptr, &dst_left); + + if (res == (size_t) -1) { + if (errno == E2BIG) { + // dst buffer is not enough to accomodate whole string + // enlarge the buffer and try again + size_t dst_used = dst_len - dst_left; + dst_left += dst_len; + dst_len += dst_len; + dst.resize(dst_len); + + // dst.resize might have allocated destination buffer in another area + // of memory, thus our previous pointer "dst" will be invalid; re-point + // it using "dst_used". + dst_ptr = &dst[dst_used]; + } else { + throw std::runtime_error("bytes_to_str: iconv error"); + } + } else { + // conversion successful + dst.resize(dst_len - dst_left); + break; + } + } + + if (iconv_close(cd) != 0) { + throw std::runtime_error("bytes_to_str: iconv close error"); + } + + return dst; +} +#elif defined(KS_STR_ENCODING_NONE) +std::string kaitai::kstream::bytes_to_str(std::string src, std::string src_enc) { + return src; +} +#else +#error Need to decide how to handle strings: please define one of: KS_STR_ENCODING_ICONV, KS_STR_ENCODING_NONE +#endif diff --git a/phonelibs/kaitai/kaitaistream.h b/phonelibs/kaitai/kaitaistream.h new file mode 100644 index 000000000..e7f4c6ce3 --- /dev/null +++ b/phonelibs/kaitai/kaitaistream.h @@ -0,0 +1,268 @@ +#ifndef KAITAI_STREAM_H +#define KAITAI_STREAM_H + +// Kaitai Struct runtime API version: x.y.z = 'xxxyyyzzz' decimal +#define KAITAI_STRUCT_VERSION 9000L + +#include +#include +#include +#include + +namespace kaitai { + +/** + * Kaitai Stream class (kaitai::kstream) is an implementation of + * Kaitai Struct stream API + * for C++/STL. It's implemented as a wrapper over generic STL std::istream. + * + * It provides a wide variety of simple methods to read (parse) binary + * representations of primitive types, such as integer and floating + * point numbers, byte arrays and strings, and also provides stream + * positioning / navigation methods with unified cross-language and + * cross-toolkit semantics. + * + * Typically, end users won't access Kaitai Stream class manually, but would + * describe a binary structure format using .ksy language and then would use + * Kaitai Struct compiler to generate source code in desired target language. + * That code, in turn, would use this class and API to do the actual parsing + * job. + */ +class kstream { +public: + /** + * Constructs new Kaitai Stream object, wrapping a given std::istream. + * \param io istream object to use for this Kaitai Stream + */ + kstream(std::istream* io); + + /** + * Constructs new Kaitai Stream object, wrapping a given in-memory data + * buffer. + * \param data data buffer to use for this Kaitai Stream + */ + kstream(std::string& data); + + void close(); + + /** @name Stream positioning */ + //@{ + /** + * Check if stream pointer is at the end of stream. Note that the semantics + * are different from traditional STL semantics: one does *not* need to do a + * read (which will fail) after the actual end of the stream to trigger EOF + * flag, which can be accessed after that read. It is sufficient to just be + * at the end of the stream for this method to return true. + * \return "true" if we are located at the end of the stream. + */ + bool is_eof() const; + + /** + * Set stream pointer to designated position. + * \param pos new position (offset in bytes from the beginning of the stream) + */ + void seek(uint64_t pos); + + /** + * Get current position of a stream pointer. + * \return pointer position, number of bytes from the beginning of the stream + */ + uint64_t pos(); + + /** + * Get total size of the stream in bytes. + * \return size of the stream in bytes + */ + uint64_t size(); + //@} + + /** @name Integer numbers */ + //@{ + + // ------------------------------------------------------------------------ + // Signed + // ------------------------------------------------------------------------ + + int8_t read_s1(); + + // ........................................................................ + // Big-endian + // ........................................................................ + + int16_t read_s2be(); + int32_t read_s4be(); + int64_t read_s8be(); + + // ........................................................................ + // Little-endian + // ........................................................................ + + int16_t read_s2le(); + int32_t read_s4le(); + int64_t read_s8le(); + + // ------------------------------------------------------------------------ + // Unsigned + // ------------------------------------------------------------------------ + + uint8_t read_u1(); + + // ........................................................................ + // Big-endian + // ........................................................................ + + uint16_t read_u2be(); + uint32_t read_u4be(); + uint64_t read_u8be(); + + // ........................................................................ + // Little-endian + // ........................................................................ + + uint16_t read_u2le(); + uint32_t read_u4le(); + uint64_t read_u8le(); + + //@} + + /** @name Floating point numbers */ + //@{ + + // ........................................................................ + // Big-endian + // ........................................................................ + + float read_f4be(); + double read_f8be(); + + // ........................................................................ + // Little-endian + // ........................................................................ + + float read_f4le(); + double read_f8le(); + + //@} + + /** @name Unaligned bit values */ + //@{ + + void align_to_byte(); + uint64_t read_bits_int_be(int n); + uint64_t read_bits_int(int n); + uint64_t read_bits_int_le(int n); + + //@} + + /** @name Byte arrays */ + //@{ + + std::string read_bytes(std::streamsize len); + std::string read_bytes_full(); + std::string read_bytes_term(char term, bool include, bool consume, bool eos_error); + std::string ensure_fixed_contents(std::string expected); + + static std::string bytes_strip_right(std::string src, char pad_byte); + static std::string bytes_terminate(std::string src, char term, bool include); + static std::string bytes_to_str(std::string src, std::string src_enc); + + //@} + + /** @name Byte array processing */ + //@{ + + /** + * Performs a XOR processing with given data, XORing every byte of input with a single + * given value. + * @param data data to process + * @param key value to XOR with + * @return processed data + */ + static std::string process_xor_one(std::string data, uint8_t key); + + /** + * Performs a XOR processing with given data, XORing every byte of input with a key + * array, repeating key array many times, if necessary (i.e. if data array is longer + * than key array). + * @param data data to process + * @param key array of bytes to XOR with + * @return processed data + */ + static std::string process_xor_many(std::string data, std::string key); + + /** + * Performs a circular left rotation shift for a given buffer by a given amount of bits, + * using groups of 1 bytes each time. Right circular rotation should be performed + * using this procedure with corrected amount. + * @param data source data to process + * @param amount number of bits to shift by + * @return copy of source array with requested shift applied + */ + static std::string process_rotate_left(std::string data, int amount); + +#ifdef KS_ZLIB + /** + * Performs an unpacking ("inflation") of zlib-compressed data with usual zlib headers. + * @param data data to unpack + * @return unpacked data + * @throws IOException + */ + static std::string process_zlib(std::string data); +#endif + + //@} + + /** + * Performs modulo operation between two integers: dividend `a` + * and divisor `b`. Divisor `b` is expected to be positive. The + * result is always 0 <= x <= b - 1. + */ + static int mod(int a, int b); + + /** + * Converts given integer `val` to a decimal string representation. + * Should be used in place of std::to_string() (which is available only + * since C++11) in older C++ implementations. + */ + static std::string to_string(int val); + + /** + * Reverses given string `val`, so that the first character becomes the + * last and the last one becomes the first. This should be used to avoid + * the need of local variables at the caller. + */ + static std::string reverse(std::string val); + + /** + * Finds the minimal byte in a byte array, treating bytes as + * unsigned values. + * @param val byte array to scan + * @return minimal byte in byte array as integer + */ + static uint8_t byte_array_min(const std::string val); + + /** + * Finds the maximal byte in a byte array, treating bytes as + * unsigned values. + * @param val byte array to scan + * @return maximal byte in byte array as integer + */ + static uint8_t byte_array_max(const std::string val); + +private: + std::istream* m_io; + std::istringstream m_io_str; + int m_bits_left; + uint64_t m_bits; + + void init(); + void exceptions_enable() const; + + static uint64_t get_mask_ones(int n); + + static const int ZLIB_BUF_SIZE = 128 * 1024; +}; + +} + +#endif diff --git a/phonelibs/kaitai/kaitaistruct.h b/phonelibs/kaitai/kaitaistruct.h new file mode 100644 index 000000000..8172ede6c --- /dev/null +++ b/phonelibs/kaitai/kaitaistruct.h @@ -0,0 +1,20 @@ +#ifndef KAITAI_STRUCT_H +#define KAITAI_STRUCT_H + +#include + +namespace kaitai { + +class kstruct { +public: + kstruct(kstream *_io) { m__io = _io; } + virtual ~kstruct() {} +protected: + kstream *m__io; +public: + kstream *_io() { return m__io; } +}; + +} + +#endif diff --git a/rednose/SConscript b/rednose/SConscript new file mode 100644 index 000000000..36daf2cd7 --- /dev/null +++ b/rednose/SConscript @@ -0,0 +1,40 @@ +Import('env', 'envCython', 'arch', 'rednose_config') + +generated_folder = rednose_config['generated_folder'] + +templates = Glob('#rednose/templates/*') + +sympy_helpers = "#rednose/helpers/sympy_helpers.py" +ekf_sym = "#rednose/helpers/ekf_sym.py" +ekf_sym_pyx = "#rednose/helpers/ekf_sym_pyx.pyx" +ekf_sym_cc = env.Object("#rednose/helpers/ekf_sym.cc") +common_ekf = "#rednose/helpers/common_ekf.cc" + +found = {} +for target, (command, combined_lib, extra_generated) in rednose_config['to_build'].items(): + if File(command).exists(): + found[target] = (command, combined_lib, extra_generated) + +lib_target = [common_ekf] +for target, (command, combined_lib, extra_generated) in found.items(): + target_files = File([f'{generated_folder}/{target}.cpp', f'{generated_folder}/{target}.h']) + extra_generated = [File(f'{generated_folder}/{x}') for x in extra_generated] + command_file = File(command) + + env.Command(target_files + extra_generated, + [templates, command_file, sympy_helpers, ekf_sym], + command_file.get_abspath() + " " + target + " " + Dir(generated_folder).get_abspath()) + + if combined_lib: + lib_target.append(target_files[0]) + else: + env.SharedLibrary(f'{generated_folder}/' + target, [target_files[0], common_ekf]) + +libkf = env.SharedLibrary(f'{generated_folder}/libkf', lib_target) + +lenv = envCython.Clone() +lenv["LINKFLAGS"] += [libkf[0].get_labspath()] +ekf_sym_so = lenv.Program('#rednose/helpers/ekf_sym_pyx.so', [ekf_sym_pyx, ekf_sym_cc, common_ekf]) +lenv.Depends(ekf_sym_so, libkf) + +Export('libkf') diff --git a/rednose/helpers/__init__.py b/rednose/helpers/__init__.py index aba6b41fe..bbd239b77 100644 --- a/rednose/helpers/__init__.py +++ b/rednose/helpers/__init__.py @@ -13,14 +13,19 @@ def write_code(folder, name, code, header): open(os.path.join(folder, f"{name}.h"), 'w').write(header) -def load_code(folder, name): +def load_code(folder, name, lib_name=None): + if lib_name is None: + lib_name = name shared_ext = "dylib" if platform.system() == "Darwin" else "so" - shared_fn = os.path.join(folder, f"lib{name}.{shared_ext}") + shared_fn = os.path.join(folder, f"lib{lib_name}.{shared_ext}") header_fn = os.path.join(folder, f"{name}.h") with open(header_fn) as f: header = f.read() + # is the only thing that can be parsed by cffi + header = "\n".join([line for line in header.split("\n") if line.startswith("void ")]) + ffi = FFI() ffi.cdef(header) return (ffi, ffi.dlopen(shared_fn)) diff --git a/rednose/helpers/common_ekf.cc b/rednose/helpers/common_ekf.cc new file mode 100644 index 000000000..1e6390250 --- /dev/null +++ b/rednose/helpers/common_ekf.cc @@ -0,0 +1,19 @@ +#include "common_ekf.h" + +std::vector& get_ekfs() { + static std::vector vec; + return vec; +} + +void ekf_register(const EKF* ekf) { + get_ekfs().push_back(ekf); +} + +const EKF* ekf_lookup(const std::string& ekf_name) { + for (const auto& ekfi : get_ekfs()) { + if (ekf_name == ekfi->name) { + return ekfi; + } + } + return NULL; +} diff --git a/rednose/helpers/common_ekf.h b/rednose/helpers/common_ekf.h new file mode 100644 index 000000000..5dfdd448b --- /dev/null +++ b/rednose/helpers/common_ekf.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef void (*extra_routine_t)(double *, double *); + +struct EKF { + std::string name; + std::vector kinds; + std::vector feature_kinds; + + void (*f_fun)(double *, double, double *); + void (*F_fun)(double *, double, double *); + void (*err_fun)(double *, double *, double *); + void (*inv_err_fun)(double *, double *, double *); + void (*H_mod_fun)(double *, double *); + void (*predict)(double *, double *, double *, double); + std::unordered_map hs = {}; + std::unordered_map Hs = {}; + std::unordered_map updates = {}; + std::unordered_map Hes = {}; + std::unordered_map sets = {}; + std::unordered_map extra_routines = {}; +}; + +std::vector& get_ekfs(); +const EKF* ekf_lookup(const std::string& ekf_name); + +void ekf_register(const EKF* ekf); + +#define ekf_init(ekf) \ +static void __attribute__((constructor)) do_ekf_init_ ## ekf(void) { \ + ekf_register(&ekf); \ +} diff --git a/rednose/helpers/ekf_sym.cc b/rednose/helpers/ekf_sym.cc new file mode 100644 index 000000000..365a6f989 --- /dev/null +++ b/rednose/helpers/ekf_sym.cc @@ -0,0 +1,223 @@ +#include "ekf_sym.h" + +using namespace EKFS; +using namespace Eigen; + +EKFSym::EKFSym(std::string name, Map Q, Map x_initial, Map P_initial, int dim_main, + int dim_main_err, int N, int dim_augment, int dim_augment_err, std::vector maha_test_kinds, + std::vector quaternion_idxs, std::vector global_vars, double max_rewind_age) +{ + // TODO: add logger + + this->ekf = ekf_lookup(name); + assert(this->ekf); + + this->msckf = N > 0; + this->N = N; + this->dim_augment = dim_augment; + this->dim_augment_err = dim_augment_err; + this->dim_main = dim_main; + this->dim_main_err = dim_main_err; + + this->dim_x = x_initial.rows(); + this->dim_err = P_initial.rows(); + + assert(dim_main + dim_augment * N == dim_x); + assert(dim_main_err + dim_augment_err * N == this->dim_err); + assert(Q.rows() == P_initial.rows() && Q.cols() == P_initial.cols()); + + // kinds that should get mahalanobis distance + // tested for outlier rejection + this->maha_test_kinds = maha_test_kinds; + + // quaternions need normalization + this->quaternion_idxs = quaternion_idxs; + + this->global_vars = global_vars; + + // Process noise + this->Q = Q; + + this->max_rewind_age = max_rewind_age; + this->init_state(x_initial, P_initial, NAN); +} + +void EKFSym::init_state(Map state, Map covs, double filter_time) { + this->x = state; + this->P = covs; + this->filter_time = filter_time; + this->augment_times = VectorXd::Zero(this->N); + this->reset_rewind(); +} + +VectorXd EKFSym::state() { + return this->x; +} + +MatrixXdr EKFSym::covs() { + return this->P; +} + +void EKFSym::set_filter_time(double t) { + this->filter_time = t; +} + +double EKFSym::get_filter_time() { + return this->filter_time; +} + +void EKFSym::normalize_quaternions() { + for(std::size_t i = 0; i < this->quaternion_idxs.size(); ++i) { + this->normalize_slice(this->quaternion_idxs[i], this->quaternion_idxs[i] + 4); + } +} + +void EKFSym::normalize_slice(int slice_start, int slice_end_ex) { + this->x.block(slice_start, 0, slice_end_ex - slice_start, this->x.cols()).normalize(); +} + +void EKFSym::set_global(std::string global_var, double val) { + this->ekf->sets.at(global_var)(val); +} + +std::optional EKFSym::predict_and_update_batch(double t, int kind, std::vector> z_map, + std::vector> R_map, std::vector> extra_args, bool augment) +{ + // TODO handle rewinding at this level + + std::deque rewound; + if (!std::isnan(this->filter_time) && t < this->filter_time) { + if (this->rewind_t.empty() || t < this->rewind_t.front() || t < this->rewind_t.back() - this->max_rewind_age) { + std::cout << "observation too old at " << t << " with filter at " << this->filter_time << ", ignoring" << std::endl; + return std::nullopt; + } + rewound = this->rewind(t); + } + + Observation obs; + obs.t = t; + obs.kind = kind; + obs.extra_args = extra_args; + for (Map zi : z_map) { + obs.z.push_back(zi); + } + for (Map Ri : R_map) { + obs.R.push_back(Ri); + } + + std::optional res = std::make_optional(this->predict_and_update_batch(obs, augment)); + + // optional fast forward + while (!rewound.empty()) { + this->predict_and_update_batch(rewound.front(), false); + rewound.pop_front(); + } + + return res; +} + +void EKFSym::reset_rewind() { + this->rewind_obscache.clear(); + this->rewind_t.clear(); + this->rewind_states.clear(); +} + +std::deque EKFSym::rewind(double t) { + std::deque rewound; + + // rewind observations until t is after previous observation + while (this->rewind_t.back() > t) { + rewound.push_front(this->rewind_obscache.back()); + this->rewind_t.pop_back(); + this->rewind_states.pop_back(); + this->rewind_obscache.pop_back(); + } + + // set the state to the time right before that + this->filter_time = this->rewind_t.back(); + this->x = this->rewind_states.back().first; + this->P = this->rewind_states.back().second; + + return rewound; +} + +void EKFSym::checkpoint(Observation& obs) { + // push to rewinder + this->rewind_t.push_back(this->filter_time); + this->rewind_states.push_back(std::make_pair(this->x, this->P)); + this->rewind_obscache.push_back(obs); + + // only keep a certain number around + if (this->rewind_t.size() > REWIND_TO_KEEP) { + this->rewind_t.pop_front(); + this->rewind_states.pop_front(); + this->rewind_obscache.pop_front(); + } +} + +Estimate EKFSym::predict_and_update_batch(Observation& obs, bool augment) { + assert(obs.z.size() == obs.R.size()); + assert(obs.z.size() == obs.extra_args.size()); + + this->predict(obs.t); + + Estimate res; + res.t = obs.t; + res.kind = obs.kind; + res.z = obs.z; + res.extra_args = obs.extra_args; + res.xk1 = this->x; + res.Pk1 = this->P; + + // update batch + std::vector y; + for (int i = 0; i < obs.z.size(); i++) { + assert(obs.z[i].rows() == obs.R[i].rows()); + assert(obs.z[i].rows() == obs.R[i].cols()); + + // update state + y.push_back(this->update(obs.kind, obs.z[i], obs.R[i], obs.extra_args[i])); + } + + res.xk = this->x; + res.Pk = this->P; + res.y = y; + + assert(!augment); // TODO + // if (augment) { + // this->augment(); + // } + + this->checkpoint(obs); + + return res; +} + +void EKFSym::predict(double t) { + // initialize time + if (std::isnan(this->filter_time)) { + this->filter_time = t; + } + + // predict + double dt = t - this->filter_time; + assert(dt >= 0.0); + + this->ekf->predict(this->x.data(), this->P.data(), this->Q.data(), dt); + this->normalize_quaternions(); + this->filter_time = t; +} + +VectorXd EKFSym::update(int kind, VectorXd z, MatrixXdr R, std::vector extra_args) { + this->ekf->updates.at(kind)(this->x.data(), this->P.data(), z.data(), R.data(), extra_args.data()); + this->normalize_quaternions(); + + if (this->msckf && std::find(this->feature_track_kinds.begin(), this->feature_track_kinds.end(), kind) != this->feature_track_kinds.end()) { + return z.head(z.rows() - extra_args.size()); + } + return z; +} + +extra_routine_t EKFSym::get_extra_routine(const std::string& routine) { + return this->ekf->extra_routines.at(routine); +} diff --git a/rednose/helpers/ekf_sym.h b/rednose/helpers/ekf_sym.h new file mode 100644 index 000000000..86d6ca193 --- /dev/null +++ b/rednose/helpers/ekf_sym.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common_ekf.h" + +#define REWIND_TO_KEEP 512 + +namespace EKFS { + +typedef Eigen::Matrix MatrixXdr; + +typedef struct Observation { + double t; + int kind; + std::vector z; + std::vector R; + std::vector> extra_args; +} Observation; + +typedef struct Estimate { + Eigen::VectorXd xk1; + Eigen::VectorXd xk; + MatrixXdr Pk1; + MatrixXdr Pk; + double t; + int kind; + std::vector y; + std::vector z; + std::vector> extra_args; +} Estimate; + +class EKFSym { +public: + EKFSym(std::string name, Eigen::Map Q, Eigen::Map x_initial, + Eigen::Map P_initial, int dim_main, int dim_main_err, int N = 0, int dim_augment = 0, + int dim_augment_err = 0, std::vector maha_test_kinds = std::vector(), + std::vector quaternion_idxs = std::vector(), + std::vector global_vars = std::vector(), double max_rewind_age = 1.0); + void init_state(Eigen::Map state, Eigen::Map covs, double filter_time); + + Eigen::VectorXd state(); + MatrixXdr covs(); + void set_filter_time(double t); + double get_filter_time(); + void normalize_quaternions(); + void normalize_slice(int slice_start, int slice_end_ex); + void set_global(std::string global_var, double val); + void reset_rewind(); + + void predict(double t); + std::optional predict_and_update_batch(double t, int kind, std::vector> z, + std::vector> R, std::vector> extra_args = {{}}, bool augment = false); + + extra_routine_t get_extra_routine(const std::string& routine); + +private: + std::deque rewind(double t); + void checkpoint(Observation& obs); + + Estimate predict_and_update_batch(Observation& obs, bool augment); + Eigen::VectorXd update(int kind, Eigen::VectorXd z, MatrixXdr R, std::vector extra_args); + + // stuct with linked sympy generated functions + const EKF *ekf = NULL; + + Eigen::VectorXd x; // state + MatrixXdr P; // covs + + bool msckf; + int N; + int dim_augment; + int dim_augment_err; + int dim_main; + int dim_main_err; + + // state + int dim_x; + int dim_err; + + double filter_time; + + std::vector maha_test_kinds; + std::vector quaternion_idxs; + + std::vector global_vars; + + // process noise + MatrixXdr Q; + + // rewind stuff + double max_rewind_age; + std::deque rewind_t; + std::deque> rewind_states; + std::deque rewind_obscache; + + Eigen::VectorXd augment_times; + + std::vector feature_track_kinds; +}; + +} diff --git a/rednose/helpers/ekf_sym.py b/rednose/helpers/ekf_sym.py index 9f635c48d..c9cf0bc22 100644 --- a/rednose/helpers/ekf_sym.py +++ b/rednose/helpers/ekf_sym.py @@ -7,7 +7,7 @@ import sympy as sp from numpy import dot from rednose.helpers.sympy_helpers import sympy_into_c -from rednose.helpers import (TEMPLATE_DIR, load_code, write_code) +from rednose.helpers import TEMPLATE_DIR, load_code from rednose.helpers.chi2_lookup import chi2_ppf @@ -27,7 +27,7 @@ def null(H, eps=1e-12): def gen_code(folder, name, f_sym, dt_sym, x_sym, obs_eqs, dim_x, dim_err, eskf_params=None, msckf_params=None, # pylint: disable=dangerous-default-value - maha_test_kinds=[], global_vars=None): + maha_test_kinds=[], quaternion_idxs=[], global_vars=None, extra_routines=[]): # optional state transition matrix, H modifier # and err_function if an error-state kalman filter (ESKF) # is desired. Best described in "Quaternion kinematics @@ -91,6 +91,9 @@ def gen_code(folder, name, f_sym, dt_sym, x_sym, obs_eqs, dim_x, dim_err, eskf_p # collect sympy functions sympy_functions = [] + # extra routines + sympy_functions += extra_routines + # error functions sympy_functions.append(('err_fun', err_eqs[0], [err_eqs[1], err_eqs[2]])) sympy_functions.append(('inv_err_fun', inv_err_eqs[0], [inv_err_eqs[1], inv_err_eqs[2]])) @@ -110,15 +113,26 @@ def gen_code(folder, name, f_sym, dt_sym, x_sym, obs_eqs, dim_x, dim_err, eskf_p sympy_functions.append(('He_%d' % kind, He_sym, [x_sym, ea_sym])) # Generate and wrap all th c code - header, code = sympy_into_c(sympy_functions, global_vars) - extra_header = "#define DIM %d\n" % dim_x - extra_header += "#define EDIM %d\n" % dim_err - extra_header += "#define MEDIM %d\n" % dim_main_err - extra_header += "typedef void (*Hfun)(double *, double *, double *);\n" + sympy_header, code = sympy_into_c(sympy_functions, global_vars) - extra_header += "\nvoid predict(double *x, double *P, double *Q, double dt);" + header = "#pragma once\n" + header += "#include \"rednose/helpers/common_ekf.h\"\n" + header += "extern \"C\" {\n" - extra_post = "" + pre_code = f"#include \"{name}.h\"\n" + pre_code += "\nnamespace {\n" + pre_code += "#define DIM %d\n" % dim_x + pre_code += "#define EDIM %d\n" % dim_err + pre_code += "#define MEDIM %d\n" % dim_main_err + pre_code += "typedef void (*Hfun)(double *, double *, double *);\n" + + if global_vars is not None: + for var in global_vars: + pre_code += f"\ndouble {var.name};\n" + pre_code += f"\nvoid set_{var.name}(double x){{ {var.name} = x;}}\n" + + post_code = "\n}\n" # namespace + post_code += "extern \"C\" {\n\n" for h_sym, kind, ea_sym, H_sym, He_sym in obs_eqs: if msckf and kind in feature_track_kinds: @@ -129,36 +143,80 @@ def gen_code(folder, name, f_sym, dt_sym, x_sym, obs_eqs, dim_x, dim_err, eskf_p # ea_dim = 1 # not really dim of ea but makes c function work maha_thresh = chi2_ppf(0.95, int(h_sym.shape[0])) # mahalanobis distance for outlier detection maha_test = kind in maha_test_kinds - extra_post += """ - void update_%d(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) { - update<%d,%d,%d>(in_x, in_P, h_%d, H_%d, %s, in_z, in_R, in_ea, MAHA_THRESH_%d); - } - """ % (kind, h_sym.shape[0], 3, maha_test, kind, kind, He_str, kind) - extra_header += "\nconst static double MAHA_THRESH_%d = %f;" % (kind, maha_thresh) - extra_header += "\nvoid update_%d(double *, double *, double *, double *, double *);" % kind - code += '\nextern "C"{\n' + extra_header + "\n}\n" - code += "\n" + open(os.path.join(TEMPLATE_DIR, "ekf_c.c")).read() - code += '\nextern "C"{\n' + extra_post + "\n}\n" + pre_code += f"const static double MAHA_THRESH_{kind} = {maha_thresh};\n" + header += f"void {name}_update_{kind}(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);\n" + post_code += f"void {name}_update_{kind}(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) {{\n" + post_code += f" update<{h_sym.shape[0]}, 3, {int(maha_test)}>(in_x, in_P, h_{kind}, H_{kind}, {He_str}, in_z, in_R, in_ea, MAHA_THRESH_{kind});\n" + post_code += "}\n" + + # For ffi loading of specific functions + for line in sympy_header.split("\n"): + if line.startswith("void "): # sympy functions + func_call = line[5: line.index(')') + 1] + header += f"void {name}_{func_call};\n" + post_code += f"void {name}_{func_call} {{\n" + post_code += f" {func_call.replace('double *', '').replace('double', '')};\n" + post_code += "}\n" + header += f"void {name}_predict(double *in_x, double *in_P, double *in_Q, double dt);\n" + post_code += f"void {name}_predict(double *in_x, double *in_P, double *in_Q, double dt) {{\n" + post_code += " predict(in_x, in_P, in_Q, dt);\n" + post_code += "}\n" if global_vars is not None: - global_code = '\nextern "C"{\n' for var in global_vars: - global_code += f"\ndouble {var.name};\n" - global_code += f"\nvoid set_{var.name}(double x){{ {var.name} = x;}}\n" - extra_header += f"\nvoid set_{var.name}(double x);\n" + header += f"void {name}_set_{var.name}(double x);\n" + post_code += f"void {name}_set_{var.name}(double x) {{\n" + post_code += f" set_{var.name}(x);\n" + post_code += "}\n" - global_code += '\n}\n' - code = global_code + code + post_code += "}\n\n" # extern c - header += "\n" + extra_header + funcs = ['f_fun', 'F_fun', 'err_fun', 'inv_err_fun', 'H_mod_fun', 'predict'] + func_lists = { + 'h': [kind for _, kind, _, _, _ in obs_eqs], + 'H': [kind for _, kind, _, _, _ in obs_eqs], + 'update': [kind for _, kind, _, _, _ in obs_eqs], + 'He': [kind for _, kind, _, _, _ in obs_eqs if msckf and kind in feature_track_kinds], + 'set': [var.name for var in global_vars] if global_vars is not None else [], + } + func_extra = [x[0] for x in extra_routines] - write_code(folder, name, code, header) + # For dynamic loading of specific functions + post_code += f"const EKF {name} = {{\n" + post_code += f" .name = \"{name}\",\n" + post_code += f" .kinds = {{ {', '.join([str(kind) for _, kind, _, _, _ in obs_eqs])} }},\n" + post_code += f" .feature_kinds = {{ {', '.join([str(kind) for _, kind, _, _, _ in obs_eqs if msckf and kind in feature_track_kinds])} }},\n" + for func in funcs: + post_code += f" .{func} = {name}_{func},\n" + for group, kinds in func_lists.items(): + post_code += f" .{group}s = {{\n" + for kind in kinds: + str_kind = f"\"{kind}\"" if type(kind) == str else kind + post_code += f" {{ {str_kind}, {name}_{group}_{kind} }},\n" + post_code += " },\n" + post_code += " .extra_routines = {\n" + for f in func_extra: + post_code += f" {{ \"{f}\", {name}_{f} }},\n" + post_code += " },\n" + post_code += "};\n\n" + post_code += f"ekf_init({name});\n" + + # merge code blocks + header += "}" + code = "\n".join([pre_code, code, open(os.path.join(TEMPLATE_DIR, "ekf_c.c")).read(), post_code]) + + # write to file + if not os.path.exists(folder): + os.mkdir(folder) + + open(os.path.join(folder, f"{name}.h"), 'w').write(header) # header is used for ffi import + open(os.path.join(folder, f"{name}.cpp"), 'w').write(code) class EKF_sym(): def __init__(self, folder, name, Q, x_initial, P_initial, dim_main, dim_main_err, # pylint: disable=dangerous-default-value - N=0, dim_augment=0, dim_augment_err=0, maha_test_kinds=[], global_vars=None, max_rewind_age=1.0, logger=logging): + N=0, dim_augment=0, dim_augment_err=0, maha_test_kinds=[], quaternion_idxs=[], global_vars=None, max_rewind_age=1.0, logger=logging): """Generates process function and all observation functions for the kalman filter.""" self.msckf = N > 0 self.N = N @@ -181,7 +239,8 @@ class EKF_sym(): # tested for outlier rejection self.maha_test_kinds = maha_test_kinds - self.global_vars = global_vars + # quaternions need normalization + self.quaternion_idxs = quaternion_idxs # process noise self.Q = Q @@ -193,25 +252,25 @@ class EKF_sym(): self.rewind_obscache = [] self.init_state(x_initial, P_initial, None) - ffi, lib = load_code(folder, name) + ffi, lib = load_code(folder, name, "kf") kinds, self.feature_track_kinds = [], [] for func in dir(lib): - if func[:2] == 'h_': - kinds.append(int(func[2:])) - if func[:3] == 'He_': - self.feature_track_kinds.append(int(func[3:])) + if func[:len(name) + 3] == f'{name}_h_': + kinds.append(int(func[len(name) + 3:])) + if func[:len(name) + 4] == f'{name}_He_': + self.feature_track_kinds.append(int(func[len(name) + 4:])) # wrap all the sympy functions - def wrap_1lists(name): - func = eval("lib.%s" % name, {"lib": lib}) # pylint: disable=eval-used + def wrap_1lists(func_name): + func = eval(f"lib.{name}_{func_name}", {"lib": lib}) # pylint: disable=eval-used def ret(lst1, out): func(ffi.cast("double *", lst1.ctypes.data), ffi.cast("double *", out.ctypes.data)) return ret - def wrap_2lists(name): - func = eval("lib.%s" % name, {"lib": lib}) # pylint: disable=eval-used + def wrap_2lists(func_name): + func = eval(f"lib.{name}_{func_name}", {"lib": lib}) # pylint: disable=eval-used def ret(lst1, lst2, out): func(ffi.cast("double *", lst1.ctypes.data), @@ -219,8 +278,8 @@ class EKF_sym(): ffi.cast("double *", out.ctypes.data)) return ret - def wrap_1list_1float(name): - func = eval("lib.%s" % name, {"lib": lib}) # pylint: disable=eval-used + def wrap_1list_1float(func_name): + func = eval(f"lib.{name}_{func_name}", {"lib": lib}) # pylint: disable=eval-used def ret(lst1, fl, out): func(ffi.cast("double *", lst1.ctypes.data), @@ -237,27 +296,28 @@ class EKF_sym(): self.hs, self.Hs, self.Hes = {}, {}, {} for kind in kinds: - self.hs[kind] = wrap_2lists("h_%d" % kind) - self.Hs[kind] = wrap_2lists("H_%d" % kind) + self.hs[kind] = wrap_2lists(f"h_{kind}") + self.Hs[kind] = wrap_2lists(f"H_{kind}") if self.msckf and kind in self.feature_track_kinds: - self.Hes[kind] = wrap_2lists("He_%d" % kind) + self.Hes[kind] = wrap_2lists(f"He_{kind}") - if self.global_vars is not None: - for var in self.global_vars: - fun_name = f"set_{var.name}" - setattr(self, fun_name, getattr(lib, fun_name)) + self.set_globals = {} + if global_vars is not None: + for global_var in global_vars: + self.set_globals[global_var] = getattr(lib, f"{name}_set_{global_var}") # wrap the C++ predict function def _predict_blas(x, P, dt): - lib.predict(ffi.cast("double *", x.ctypes.data), - ffi.cast("double *", P.ctypes.data), - ffi.cast("double *", self.Q.ctypes.data), - ffi.cast("double", dt)) + func = eval(f"lib.{name}_predict", {"lib": lib}) # pylint: disable=eval-used + func(ffi.cast("double *", x.ctypes.data), + ffi.cast("double *", P.ctypes.data), + ffi.cast("double *", self.Q.ctypes.data), + ffi.cast("double", dt)) return x, P # wrap the C++ update function def fun_wrapper(f, kind): - f = eval("lib.%s" % f, {"lib": lib}) # pylint: disable=eval-used + f = eval(f"lib.{name}_{f}", {"lib": lib}) # pylint: disable=eval-used def _update_inner_blas(x, P, z, R, extra_args): f(ffi.cast("double *", x.ctypes.data), @@ -333,6 +393,25 @@ class EKF_sym(): def covs(self): return self.P + def set_filter_time(self, t): + self.filter_time = t + + def get_filter_time(self): + return self.filter_time + + def normalize_quaternions(self): + for idx in self.quaternion_idxs: + self.normalize_slice(idx, idx+4) + + def normalize_slice(self, slice_start, slice_end_ex): + self.x[slice_start:slice_end_ex] /= np.linalg.norm(self.x[slice_start:slice_end_ex]) + + def get_augment_times(self): + return self.augment_times + + def set_global(self, global_var, val): + self.set_globals[global_var](val) + def rewind(self, t): # find where we are rewinding to idx = bisect_right(self.rewind_t, t) @@ -376,6 +455,7 @@ class EKF_sym(): dt = t - self.filter_time assert dt >= 0 self.x, self.P = self._predict(self.x, self.P, dt) + self.normalize_quaternions() self.filter_time = t def predict_and_update_batch(self, t, kind, z, R, extra_args=[[]], augment=False): # pylint: disable=dangerous-default-value @@ -401,11 +481,9 @@ class EKF_sym(): def _predict_and_update_batch(self, t, kind, z, R, extra_args, augment=False): """The main kalman filter function Predicts the state and then updates a batch of observations - dim_x: dimensionality of the state space dim_z: dimensionality of the observation and depends on kind n: number of observations - Args: t (float): Time of observation kind (int): Type of observation @@ -437,6 +515,7 @@ class EKF_sym(): extra_args_i = np.array(extra_args[i], dtype=np.float64, order='F') # update self.x, self.P, y_i = self._update(self.x, self.P, kind, z_i, R_i, extra_args=extra_args_i) + self.normalize_quaternions() y.append(y_i) xk_k, Pk_k = np.copy(self.x).flatten(), np.copy(self.P) @@ -570,7 +649,6 @@ class EKF_sym(): ''' Returns rts smoothed results of kalman filter estimates - If the kalman state is augmented with old states only the main state is smoothed ''' diff --git a/rednose/helpers/ekf_sym_pyx.pyx b/rednose/helpers/ekf_sym_pyx.pyx new file mode 100644 index 000000000..a5c0d5681 --- /dev/null +++ b/rednose/helpers/ekf_sym_pyx.pyx @@ -0,0 +1,190 @@ +# cython: language_level=3 +# cython: profile=True +# distutils: language = c++ + +cimport cython + +from libcpp.string cimport string +from libcpp.vector cimport vector +from libcpp cimport bool +cimport numpy as np + +import numpy as np + +cdef extern from "" namespace "std" nogil: + cdef cppclass optional[T]: + ctypedef T value_type + bool has_value() + T& value() + +cdef extern from "rednose/helpers/ekf_sym.h" namespace "EKFS": + cdef cppclass MapVectorXd "Eigen::Map": + MapVectorXd(double*, int) + + cdef cppclass MapMatrixXdr "Eigen::Map >": + MapMatrixXdr(double*, int, int) + + cdef cppclass VectorXd "Eigen::VectorXd": + VectorXd() + double* data() + int rows() + + cdef cppclass MatrixXdr "Eigen::Matrix": + MatrixXdr() + double* data() + int rows() + int cols() + + ctypedef struct Estimate: + VectorXd xk1 + VectorXd xk + MatrixXdr Pk1 + MatrixXdr Pk + double t + int kind + vector[VectorXd] y + vector[VectorXd] z + vector[vector[double]] extra_args + + cdef cppclass EKFSym: + EKFSym(string name, MapMatrixXdr Q, MapVectorXd x_initial, MapMatrixXdr P_initial, int dim_main, + int dim_main_err, int N, int dim_augment, int dim_augment_err, vector[int] maha_test_kinds, + vector[int] quaternion_idxs, vector[string] global_vars, double max_rewind_age) + void init_state(MapVectorXd state, MapMatrixXdr covs, double filter_time) + + VectorXd state() + MatrixXdr covs() + void set_filter_time(double t) + double get_filter_time() + void set_global(string name, double val) + void reset_rewind() + + void predict(double t) + optional[Estimate] predict_and_update_batch(double t, int kind, vector[MapVectorXd] z, vector[MapMatrixXdr] z, + vector[vector[double]] extra_args, bool augment) + +# Functions like `numpy_to_matrix` are not possible, cython requires default +# constructor for return variable types which aren't available with Eigen::Map + +@cython.wraparound(False) +@cython.boundscheck(False) +cdef np.ndarray[np.float64_t, ndim=2, mode="c"] matrix_to_numpy(MatrixXdr arr): + cdef double[:,:] mem_view = arr.data() + return np.copy(np.asarray(mem_view, dtype=np.double, order="C")) + +@cython.wraparound(False) +@cython.boundscheck(False) +cdef np.ndarray[np.float64_t, ndim=1, mode="c"] vector_to_numpy(VectorXd arr): + cdef double[:] mem_view = arr.data() + return np.copy(np.asarray(mem_view, dtype=np.double, order="C")) + +cdef class EKF_sym: + cdef EKFSym* ekf + def __cinit__(self, str gen_dir, str name, np.ndarray[np.float64_t, ndim=2] Q, + np.ndarray[np.float64_t, ndim=1] x_initial, np.ndarray[np.float64_t, ndim=2] P_initial, int dim_main, + int dim_main_err, int N=0, int dim_augment=0, int dim_augment_err=0, list maha_test_kinds=[], + list quaternion_idxs=[], list global_vars=[], double max_rewind_age=1.0, logger=None): + # TODO logger + + cdef np.ndarray[np.float64_t, ndim=2, mode='c'] Q_b = np.ascontiguousarray(Q, dtype=np.double) + cdef np.ndarray[np.float64_t, ndim=1, mode='c'] x_initial_b = np.ascontiguousarray(x_initial, dtype=np.double) + cdef np.ndarray[np.float64_t, ndim=2, mode='c'] P_initial_b = np.ascontiguousarray(P_initial, dtype=np.double) + self.ekf = new EKFSym( + name.encode('utf8'), + MapMatrixXdr( Q_b.data, Q.shape[0], Q.shape[1]), + MapVectorXd( x_initial_b.data, x_initial.shape[0]), + MapMatrixXdr( P_initial_b.data, P_initial.shape[0], P_initial.shape[1]), + dim_main, + dim_main_err, + N, + dim_augment, + dim_augment_err, + maha_test_kinds, + quaternion_idxs, + [x.encode('utf8') for x in global_vars], + max_rewind_age + ) + + def init_state(self, np.ndarray[np.float64_t, ndim=1] state, np.ndarray[np.float64_t, ndim=2] covs, filter_time): + cdef np.ndarray[np.float64_t, ndim=1, mode='c'] state_b = np.ascontiguousarray(state, dtype=np.double) + cdef np.ndarray[np.float64_t, ndim=2, mode='c'] covs_b = np.ascontiguousarray(covs, dtype=np.double) + self.ekf.init_state( + MapVectorXd( state_b.data, state.shape[0]), + MapMatrixXdr( covs_b.data, covs.shape[0], covs.shape[1]), + np.nan if filter_time is None else filter_time + ) + + def state(self): + cdef np.ndarray res = vector_to_numpy(self.ekf.state()) + return res + + def covs(self): + return matrix_to_numpy(self.ekf.covs()) + + def set_filter_time(self, double t): + self.ekf.set_filter_time(t) + + def get_filter_time(self): + return self.ekf.get_filter_time() + + def set_global(self, str global_var, double val): + self.ekf.set_global(global_var.encode('utf8'), val) + + def reset_rewind(self): + self.ekf.reset_rewind() + + def predict(self, double t): + self.ekf.predict(t) + + def predict_and_update_batch(self, double t, int kind, z, R, extra_args=[[]], bool augment=False): + cdef vector[MapVectorXd] z_map + cdef np.ndarray[np.float64_t, ndim=1, mode='c'] zi_b + for zi in z: + zi_b = np.ascontiguousarray(zi, dtype=np.double) + z_map.push_back(MapVectorXd( zi_b.data, zi.shape[0])) + + cdef vector[MapMatrixXdr] R_map + cdef np.ndarray[np.float64_t, ndim=2, mode='c'] Ri_b + for Ri in R: + Ri_b = np.ascontiguousarray(Ri, dtype=np.double) + R_map.push_back(MapMatrixXdr( Ri_b.data, Ri.shape[0], Ri.shape[1])) + + cdef vector[vector[double]] extra_args_map + cdef vector[double] args_map + for args in extra_args: + args_map.clear() + for a in args: + args_map.push_back(a) + extra_args_map.push_back(args_map) + + cdef optional[Estimate] res = self.ekf.predict_and_update_batch(t, kind, z_map, R_map, extra_args_map, augment) + if not res.has_value(): + return None + + cdef VectorXd tmpvec + return ( + vector_to_numpy(res.value().xk1), + vector_to_numpy(res.value().xk), + matrix_to_numpy(res.value().Pk1), + matrix_to_numpy(res.value().Pk), + res.value().t, + res.value().kind, + [vector_to_numpy(tmpvec) for tmpvec in res.value().y], + z, # TODO: take return values? + extra_args, + ) + + def augment(self): + raise NotImplementedError() # TODO + + def get_augment_times(self): + raise NotImplementedError() # TODO + + def rts_smooth(self, estimates, norm_quats=False): + raise NotImplementedError() # TODO + + def maha_test(self, x, P, kind, z, R, extra_args=[], maha_thresh=0.95): + raise NotImplementedError() # TODO + + def __dealloc__(self): + del self.ekf diff --git a/rednose/helpers/feature_handler.py b/rednose/helpers/feature_handler.py index f8ac65145..6a20b85e1 100755 --- a/rednose/helpers/feature_handler.py +++ b/rednose/helpers/feature_handler.py @@ -35,7 +35,9 @@ class FeatureHandler(): c_code = "#include \n" c_code += "#include \n" c_code += "#define K %d\n" % K + c_code += "extern \"C\" {\n" c_code += "\n" + open(os.path.join(TEMPLATE_DIR, "feature_handler.c")).read() + c_code += "\n}\n" filename = f"{FeatureHandler.name}_{K}" write_code(generated_dir, filename, c_code, c_header) diff --git a/rednose/__init__.py b/rednose/helpers/kalmanfilter.py similarity index 74% rename from rednose/__init__.py rename to rednose/helpers/kalmanfilter.py index 25f82adc7..0c30e4916 100644 --- a/rednose/__init__.py +++ b/rednose/helpers/kalmanfilter.py @@ -2,8 +2,6 @@ from typing import Any, Dict import numpy as np -from rednose.helpers.ekf_sym import EKF_sym - class KalmanFilter: name = "" @@ -12,12 +10,7 @@ class KalmanFilter: Q = np.zeros((0, 0)) obs_noise: Dict[int, Any] = {} - def __init__(self, generated_dir): - dim_state = self.initial_x.shape[0] - dim_state_err = self.initial_P_diag.shape[0] - - # init filter - self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, np.diag(self.initial_P_diag), dim_state, dim_state_err) + filter = None # Should be initialized when initializating a KalmanFilter implementation @property def x(self): @@ -25,7 +18,7 @@ class KalmanFilter: @property def t(self): - return self.filter.filter_time + return self.filter.get_filter_time() @property def P(self): diff --git a/rednose/helpers/lst_sq_computer.py b/rednose/helpers/lst_sq_computer.py index 18fd6d7f5..56c3bc8c4 100755 --- a/rednose/helpers/lst_sq_computer.py +++ b/rednose/helpers/lst_sq_computer.py @@ -48,14 +48,16 @@ class LstSqComputer(): @staticmethod def generate_code(generated_dir, K=4): sympy_functions = generate_residual(K) - header, code = sympy_into_c(sympy_functions) + header, sympy_code = sympy_into_c(sympy_functions) + code = "\n#include \"rednose/helpers/common_ekf.h\"\n" code += "\n#define KDIM %d\n" % K - code += "\n" + open(os.path.join(TEMPLATE_DIR, "compute_pos.c")).read() + code += "extern \"C\" {\n" + code += sympy_code + code += "\n" + open(os.path.join(TEMPLATE_DIR, "compute_pos.c")).read() + "\n" + code += "}\n" - header += """ - void compute_pos(double *to_c, double *in_poses, double *in_img_positions, double *param, double *pos); - """ + header += "\nvoid compute_pos(double *to_c, double *in_poses, double *in_img_positions, double *param, double *pos);\n" filename = f"{LstSqComputer.name}_{K}" write_code(generated_dir, filename, code, header) diff --git a/rednose/helpers/sympy_helpers.py b/rednose/helpers/sympy_helpers.py index 12b7188e7..716e94e01 100644 --- a/rednose/helpers/sympy_helpers.py +++ b/rednose/helpers/sympy_helpers.py @@ -151,6 +151,5 @@ def sympy_into_c(sympy_functions, global_vars=None): c_header = '\n'.join(x for x in c_header.split("\n") if len(x) > 0 and x[0] != '#') c_code = '\n'.join(x for x in c_code.split("\n") if len(x) > 0 and x[0] != '#') - c_code = 'extern "C" {\n#include \n' + c_code + "\n}\n" return c_header, c_code diff --git a/rednose/templates/compute_pos.c b/rednose/templates/compute_pos.c index 3c7b16efa..742c7d618 100644 --- a/rednose/templates/compute_pos.c +++ b/rednose/templates/compute_pos.c @@ -7,7 +7,6 @@ typedef Eigen::Matrix R1M; typedef Eigen::Matrix O1M; typedef Eigen::Matrix M3D; -extern "C" { void gauss_newton(double *in_x, double *in_poses, double *in_img_positions) { double res[KDIM*2] = {0}; @@ -51,4 +50,3 @@ void compute_pos(double *to_c, double *poses, double *img_positions, double *par ecef_output = rot*ecef_output + ecef_offset; memcpy(pos, ecef_output.data(), 3 * sizeof(double)); } -} diff --git a/rednose/templates/feature_handler.c b/rednose/templates/feature_handler.c index 330972339..9c580c2ea 100644 --- a/rednose/templates/feature_handler.c +++ b/rednose/templates/feature_handler.c @@ -1,4 +1,3 @@ -extern "C"{ bool sane(double track [K + 1][5]) { double diffs_x [K-1]; double diffs_y [K-1]; @@ -55,4 +54,3 @@ void merge_features(double *tracks, double *features, long long *empty_idxs) { } memcpy(tracks, track_arr, (K+1) * 6000 * 5 * sizeof(double)); } -} diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 5191e3224..e71b5b80e 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -17,7 +17,7 @@ from typing import Any import requests from jsonrpc import JSONRPCResponseManager, dispatcher -from websocket import ABNF, WebSocketTimeoutException, create_connection +from websocket import ABNF, WebSocketTimeoutException, WebSocketException, create_connection import cereal.messaging as messaging from cereal.services import service_list @@ -29,6 +29,8 @@ from selfdrive.hardware import HARDWARE, PC from selfdrive.loggerd.config import ROOT from selfdrive.loggerd.xattr_cache import getxattr, setxattr from selfdrive.swaglog import cloudlog, SWAGLOG_DIR +import selfdrive.crash as crash +from selfdrive.version import dirty, origin, branch, commit ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai') HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4")) @@ -409,7 +411,12 @@ def backoff(retries): def main(): params = Params() - dongle_id = params.get("DongleId").decode('utf-8') + dongle_id = params.get("DongleId", encoding='utf-8') + crash.init() + crash.bind_user(id=dongle_id) + crash.bind_extra(dirty=dirty, origin=origin, branch=branch, commit=commit, + device=HARDWARE.get_device_type()) + ws_uri = ATHENA_HOST + "/ws/v2/" + dongle_id api = Api(dongle_id) @@ -426,8 +433,13 @@ def main(): handle_long_poll(ws) except (KeyboardInterrupt, SystemExit): break + except (ConnectionError, TimeoutError, WebSocketException): + conn_retries += 1 + params.delete("LastAthenaPingTime") except Exception: + crash.capture_exception() cloudlog.exception("athenad.main.exception") + conn_retries += 1 params.delete("LastAthenaPingTime") diff --git a/selfdrive/athena/manage_athenad.py b/selfdrive/athena/manage_athenad.py index c16bef07d..7bb717e07 100755 --- a/selfdrive/athena/manage_athenad.py +++ b/selfdrive/athena/manage_athenad.py @@ -3,7 +3,6 @@ import time from multiprocessing import Process -import selfdrive.crash as crash from common.params import Params from selfdrive.manager.process import launcher from selfdrive.swaglog import cloudlog @@ -16,9 +15,6 @@ def main(): params = Params() dongle_id = params.get("DongleId").decode('utf-8') cloudlog.bind_global(dongle_id=dongle_id, version=version, dirty=dirty) - crash.bind_user(id=dongle_id) - crash.bind_extra(version=version, dirty=dirty) - crash.install() try: while 1: diff --git a/selfdrive/registration.py b/selfdrive/athena/registration.py similarity index 67% rename from selfdrive/registration.py rename to selfdrive/athena/registration.py index b38853a9f..6bcb29e4b 100644 --- a/selfdrive/registration.py +++ b/selfdrive/athena/registration.py @@ -10,27 +10,22 @@ from common.params import Params from common.spinner import Spinner from common.file_helpers import mkdirs_exists_ok from common.basedir import PERSIST +from selfdrive.controls.lib.alertmanager import set_offroad_alert from selfdrive.hardware import HARDWARE from selfdrive.swaglog import cloudlog -from selfdrive.version import version, terms_version, training_version, get_git_commit, \ - get_git_branch, get_git_remote -def register(show_spinner=False): +UNREGISTERED_DONGLE_ID = "UnregisteredDevice" + + +def register(show_spinner=False) -> str: params = Params() - params.put("Version", version) - params.put("TermsVersion", terms_version) - params.put("TrainingVersion", training_version) - - params.put("GitCommit", get_git_commit(default="")) - params.put("GitBranch", get_git_branch(default="")) - params.put("GitRemote", get_git_remote(default="")) params.put("SubscriberInfo", HARDWARE.get_subscriber_info()) IMEI = params.get("IMEI", encoding='utf8') HardwareSerial = params.get("HardwareSerial", encoding='utf8') - - needs_registration = (None in [IMEI, HardwareSerial]) + dongle_id = params.get("DongleId", encoding='utf8') + needs_registration = None in (IMEI, HardwareSerial, dongle_id) # create a key for auth # your private key is kept on your device persist partition and never sent to our servers @@ -44,22 +39,15 @@ def register(show_spinner=False): os.rename(PERSIST+"/comma/id_rsa.tmp", PERSIST+"/comma/id_rsa") os.rename(PERSIST+"/comma/id_rsa.tmp.pub", PERSIST+"/comma/id_rsa.pub") - # make key readable by app users (ai.comma.plus.offroad) - os.chmod(PERSIST+'/comma/', 0o755) - os.chmod(PERSIST+'/comma/id_rsa', 0o744) - - dongle_id = params.get("DongleId", encoding='utf8') - needs_registration = needs_registration or dongle_id is None - if needs_registration: if show_spinner: spinner = Spinner() spinner.update("registering device") # Create registration token, in the future, this key will make JWTs directly - private_key = open(PERSIST+"/comma/id_rsa").read() - public_key = open(PERSIST+"/comma/id_rsa.pub").read() - register_token = jwt.encode({'register': True, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256') + with open(PERSIST+"/comma/id_rsa.pub") as f1, open(PERSIST+"/comma/id_rsa") as f2: + public_key = f1.read() + private_key = f2.read() # Block until we get the imei imei1, imei2 = None, None @@ -74,22 +62,32 @@ def register(show_spinner=False): params.put("IMEI", imei1) params.put("HardwareSerial", serial) + backoff = 0 while True: try: + register_token = jwt.encode({'register': True, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256') cloudlog.info("getting pilotauth") resp = api_get("v2/pilotauth/", method='POST', timeout=15, imei=imei1, imei2=imei2, serial=serial, public_key=public_key, register_token=register_token) - dongleauth = json.loads(resp.text) - dongle_id = dongleauth["dongle_id"] - params.put("DongleId", dongle_id) + + if resp.status_code in (402, 403): + cloudlog.info(f"Unable to register device, got {resp.status_code}") + dongle_id = UNREGISTERED_DONGLE_ID + else: + dongleauth = json.loads(resp.text) + dongle_id = dongleauth["dongle_id"] break except Exception: cloudlog.exception("failed to authenticate") - time.sleep(1) + backoff = min(backoff + 1, 15) + time.sleep(backoff) if show_spinner: spinner.close() + if dongle_id: + params.put("DongleId", dongle_id) + set_offroad_alert("Offroad_UnofficialHardware", dongle_id == UNREGISTERED_DONGLE_ID) return dongle_id diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index a93e05d24..f1f885b0c 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -1,36 +1,35 @@ -#include -#include -#include -#include -#include #include +#include +#include +#include +#include #include -#include #include +#include +#include -#include -#include -#include #include -#include -#include #include +#include +#include +#include +#include +#include #include #include #include "cereal/gen/cpp/car.capnp.h" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/locationd/ublox_msg.h" -#include "common/util.h" -#include "common/params.h" -#include "common/swaglog.h" -#include "common/timing.h" -#include "messaging.hpp" -#include "locationd/ublox_msg.h" - -#include "panda.h" -#include "pigeon.h" - +#include "selfdrive/boardd/panda.h" +#include "selfdrive/boardd/pigeon.h" #define MAX_IR_POWER 0.5f #define MIN_IR_POWER 0.0f @@ -64,6 +63,8 @@ void safety_setter_thread() { // diagnostic only is the default, needed for VIN query panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327); + Params p = Params(); + // switch to SILENT when CarVin param is read while (true) { if (do_exit || !panda->connected){ @@ -71,12 +72,11 @@ void safety_setter_thread() { return; }; - std::vector value_vin = Params().read_db_bytes("CarVin"); + std::string value_vin = p.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 +85,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,8 +93,10 @@ void safety_setter_thread() { return; }; - params = Params().read_db_bytes("CarParams"); - if (params.size() > 0) break; + if (p.getBool("ControlsReady")) { + params = p.get("CarParams"); + if (params.size() > 0) break; + } util::sleep_for(100); } LOGW("got %d bytes CarParams", params.size()); @@ -133,7 +135,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 +145,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 +163,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,10 +320,7 @@ 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"); - assert((result == 0) || (result == ERR_NO_VALUE)); - result = params.delete_db_value("CarParams"); - assert((result == 0) || (result == ERR_NO_VALUE)); + params.clearAll(CLEAR_ON_IGNITION); if (!safety_setter_thread_running) { safety_setter_thread_running = true; @@ -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); + } } } @@ -343,13 +361,18 @@ void panda_state_thread(bool spoofing_started) { auto ps = msg.initEvent().initPandaState(); ps.setUptime(pandaState.uptime); -#ifdef QCOM2 - ps.setVoltage(std::stoi(util::read_file("/sys/class/hwmon/hwmon1/in1_input"))); - ps.setCurrent(std::stoi(util::read_file("/sys/class/hwmon/hwmon1/curr1_input"))); -#else - ps.setVoltage(pandaState.voltage); - ps.setCurrent(pandaState.current); -#endif + if (Hardware::TICI()) { + double read_time = millis_since_boot(); + ps.setVoltage(std::stoi(util::read_file("/sys/class/hwmon/hwmon1/in1_input"))); + ps.setCurrent(std::stoi(util::read_file("/sys/class/hwmon/hwmon1/curr1_input"))); + read_time = millis_since_boot() - read_time; + if (read_time > 50) { + LOGW("reading hwmon took %lfms", read_time); + } + } else { + ps.setVoltage(pandaState.voltage); + ps.setCurrent(pandaState.current); + } ps.setIgnitionLine(pandaState.ignition_line); ps.setIgnitionCan(pandaState.ignition_can); @@ -394,17 +417,14 @@ void hardware_control_thread() { uint16_t prev_fan_speed = 999; uint16_t ir_pwr = 0; uint16_t prev_ir_pwr = 999; -#if defined(QCOM) || defined(QCOM2) bool prev_charging_disabled = false; -#endif unsigned int cnt = 0; while (!do_exit && panda->connected) { cnt++; sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update? -#if defined(QCOM) || defined(QCOM2) - if (sm.updated("deviceState")){ + if (!Hardware::PC() && sm.updated("deviceState")){ // Charging mode bool charging_disabled = sm["deviceState"].getDeviceState().getChargingDisabled(); if (charging_disabled != prev_charging_disabled){ @@ -418,7 +438,6 @@ void hardware_control_thread() { prev_charging_disabled = charging_disabled; } } -#endif // Other pandas don't have fan/IR to control if (panda->hw_type != cereal::PandaState::PandaType::UNO && panda->hw_type != cereal::PandaState::PandaType::DOS) continue; @@ -468,16 +487,12 @@ void pigeon_thread() { PubMaster pm({"ubloxRaw"}); bool ignition_last = false; -#ifdef QCOM2 - Pigeon *pigeon = Pigeon::connect("/dev/ttyHS0"); -#else - Pigeon *pigeon = Pigeon::connect(panda); -#endif + Pigeon *pigeon = Hardware::TICI() ? Pigeon::connect("/dev/ttyHS0") : Pigeon::connect(panda); std::unordered_map last_recv_time; std::unordered_map cls_max_dt = { - {(char)ublox::CLASS_NAV, int64_t(250000000ULL)}, // 0.25s - {(char)ublox::CLASS_RXM, int64_t(250000000ULL)}, // 0.25s + {(char)ublox::CLASS_NAV, int64_t(900000000ULL)}, // 0.9s + {(char)ublox::CLASS_RXM, int64_t(900000000ULL)}, // 0.9s }; while (!do_exit && panda->connected) { @@ -548,10 +563,9 @@ int main() { // set process priority and affinity err = set_realtime_priority(54); LOG("set priority returns %d", err); - err = set_core_affinity(3); - LOG("set affinity returns %d", err); - panda_set_power(true); + err = set_core_affinity(Hardware::TICI() ? 4 : 3); + LOG("set affinity returns %d", err); while (!do_exit){ std::vector threads; diff --git a/selfdrive/boardd/boardd_api_impl.pyx b/selfdrive/boardd/boardd_api_impl.pyx index 3f50fbaab..0d428a925 100644 --- a/selfdrive/boardd/boardd_api_impl.pyx +++ b/selfdrive/boardd/boardd_api_impl.pyx @@ -14,6 +14,8 @@ cdef extern void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, st def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True): cdef vector[can_frame] can_list + can_list.reserve(len(can_msgs)) + cdef can_frame f for can_msg in can_msgs: f.address = can_msg[0] diff --git a/selfdrive/boardd/can_list_to_can_capnp.cc b/selfdrive/boardd/can_list_to_can_capnp.cc index bbbceee6e..a4c9f3f6c 100644 --- a/selfdrive/boardd/can_list_to_can_capnp.cc +++ b/selfdrive/boardd/can_list_to_can_capnp.cc @@ -1,4 +1,4 @@ -#include "messaging.hpp" +#include "cereal/messaging/messaging.h" typedef struct { long address; diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index e8cb23e10..71f5770ed 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -1,31 +1,16 @@ -#include -#include -#include -#include +#include "selfdrive/boardd/panda.h" + #include -#include "common/swaglog.h" -#include "common/gpio.h" -#include "common/util.h" -#include "messaging.hpp" -#include "panda.h" +#include +#include +#include +#include -void panda_set_power(bool power){ -#ifdef QCOM2 - int err = 0; - - err += gpio_init(GPIO_STM_RST_N, true); - err += gpio_init(GPIO_STM_BOOT0, true); - - err += gpio_set(GPIO_STM_RST_N, true); - err += gpio_set(GPIO_STM_BOOT0, false); - - util::sleep_for(100); // 100 ms - - err += gpio_set(GPIO_STM_RST_N, !power); - assert(err == 0); -#endif -} +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/gpio.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" Panda::Panda(){ // init libusb diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index d34a01c9b..e725da4fa 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -1,11 +1,13 @@ #pragma once -#include -#include #include + +#include +#include +#include #include -#include #include +#include #include @@ -39,8 +41,6 @@ struct __attribute__((packed)) health_t { }; -void panda_set_power(bool power); - class Panda { private: libusb_context *ctx = NULL; diff --git a/selfdrive/boardd/pigeon.cc b/selfdrive/boardd/pigeon.cc index 3f2588f25..937925e48 100644 --- a/selfdrive/boardd/pigeon.cc +++ b/selfdrive/boardd/pigeon.cc @@ -1,14 +1,15 @@ -#include -#include -#include +#include "selfdrive/boardd/pigeon.h" + #include +#include #include +#include -#include "common/swaglog.h" -#include "common/gpio.h" -#include "common/util.h" +#include -#include "pigeon.h" +#include "selfdrive/common/gpio.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" // Termios on macos doesn't define all baud rate constants #ifndef B460800 @@ -17,6 +18,11 @@ using namespace std::string_literals; +extern ExitHandler do_exit; + +const std::string ack = "\xb5\x62\x05\x01\x02\x00"; +const std::string nack = "\xb5\x62\x05\x00\x02\x00"; + Pigeon * Pigeon::connect(Panda * p){ PandaPigeon * pigeon = new PandaPigeon(); @@ -32,53 +38,83 @@ Pigeon * Pigeon::connect(const char * tty){ return pigeon; } +bool Pigeon::wait_for_ack(){ + std::string s; + while (!do_exit){ + s += receive(); + + if (s.find(ack) != std::string::npos){ + LOGD("Received ACK from ublox"); + return true; + } else if (s.find(nack) != std::string::npos) { + LOGE("Received NACK from ublox"); + return false; + } else if (s.size() > 0x1000) { + LOGE("No response from ublox"); + return false; + } + + util::sleep_for(1); // Allow other threads to be scheduled + } + return false; +} + +bool Pigeon::send_with_ack(std::string cmd){ + send(cmd); + return wait_for_ack(); +} + void Pigeon::init() { - util::sleep_for(1000); - LOGW("panda GPS start"); + for (int i = 0; i < 10; i++){ + if (do_exit) return; + LOGW("panda GPS start"); - // power off pigeon - set_power(false); - util::sleep_for(100); + // power off pigeon + set_power(false); + util::sleep_for(100); - // 9600 baud at init - set_baud(9600); + // 9600 baud at init + set_baud(9600); - // power on pigeon - set_power(true); - util::sleep_for(500); + // power on pigeon + set_power(true); + util::sleep_for(500); - // baud rate upping - send("\x24\x50\x55\x42\x58\x2C\x34\x31\x2C\x31\x2C\x30\x30\x30\x37\x2C\x30\x30\x30\x33\x2C\x34\x36\x30\x38\x30\x30\x2C\x30\x2A\x31\x35\x0D\x0A"s); - util::sleep_for(100); + // baud rate upping + send("\x24\x50\x55\x42\x58\x2C\x34\x31\x2C\x31\x2C\x30\x30\x30\x37\x2C\x30\x30\x30\x33\x2C\x34\x36\x30\x38\x30\x30\x2C\x30\x2A\x31\x35\x0D\x0A"s); + util::sleep_for(100); - // set baud rate to 460800 - set_baud(460800); - util::sleep_for(100); + // set baud rate to 460800 + set_baud(460800); - // init from ubloxd - // To generate this data, run test/ubloxd.py with the print statements enabled in the write function in panda/python/serial.py - send("\xB5\x62\x06\x00\x14\x00\x03\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x1E\x7F"s); - send("\xB5\x62\x06\x3E\x00\x00\x44\xD2"s); - send("\xB5\x62\x06\x00\x14\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x35"s); - send("\xB5\x62\x06\x00\x14\x00\x01\x00\x00\x00\xC0\x08\x00\x00\x00\x08\x07\x00\x01\x00\x01\x00\x00\x00\x00\x00\xF4\x80"s); - send("\xB5\x62\x06\x00\x14\x00\x04\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1D\x85"s); - send("\xB5\x62\x06\x00\x00\x00\x06\x18"s); - send("\xB5\x62\x06\x00\x01\x00\x01\x08\x22"s); - send("\xB5\x62\x06\x00\x01\x00\x02\x09\x23"s); - send("\xB5\x62\x06\x00\x01\x00\x03\x0A\x24"s); - send("\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10"s); - send("\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63"s); - send("\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37"s); - send("\xB5\x62\x06\x24\x00\x00\x2A\x84"s); - send("\xB5\x62\x06\x23\x00\x00\x29\x81"s); - send("\xB5\x62\x06\x1E\x00\x00\x24\x72"s); - send("\xB5\x62\x06\x01\x03\x00\x01\x07\x01\x13\x51"s); - send("\xB5\x62\x06\x01\x03\x00\x02\x15\x01\x22\x70"s); - send("\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C"s); - send("\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70"s); - send("\xB5\x62\x06\x01\x03\x00\x0A\x0B\x01\x20\x74"s); + // init from ubloxd + // To generate this data, run selfdrive/locationd/test/ubloxd.py + if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x03\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x1E\x7F"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x35"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x01\x00\x00\x00\xC0\x08\x00\x00\x00\x08\x07\x00\x01\x00\x01\x00\x00\x00\x00\x00\xF4\x80"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x04\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1D\x85"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x00\x00\x00\x06\x18"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x00\x01\x00\x01\x08\x22"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x00\x01\x00\x03\x0A\x24"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x39\x08\x00\xFF\xAD\x62\xAD\x1E\x63\x00\x00\x83\x0C"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x24\x00\x00\x2A\x84"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x23\x00\x00\x29\x81"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x1E\x00\x00\x24\x72"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x39\x00\x00\x3F\xC3"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x01\x07\x01\x13\x51"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x02\x15\x01\x22\x70"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70"s)) continue; + if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x0A\x0B\x01\x20\x74"s)) continue; - LOGW("panda GPS on"); + + LOGW("panda GPS on"); + return; + } + LOGE("failed to initialize panda GPS"); } void PandaPigeon::connect(Panda * p) { diff --git a/selfdrive/boardd/pigeon.h b/selfdrive/boardd/pigeon.h index 927d74058..0543c4828 100644 --- a/selfdrive/boardd/pigeon.h +++ b/selfdrive/boardd/pigeon.h @@ -1,9 +1,11 @@ #pragma once -#include + #include +#include +#include -#include "panda.h" +#include "selfdrive/boardd/panda.h" class Pigeon { public: @@ -12,6 +14,8 @@ class Pigeon { virtual ~Pigeon(){}; void init(); + bool wait_for_ack(); + bool send_with_ack(std::string cmd); virtual void set_baud(int baud) = 0; virtual void send(const std::string &s) = 0; virtual std::string receive() = 0; diff --git a/selfdrive/boardd/set_time.py b/selfdrive/boardd/set_time.py new file mode 100755 index 000000000..7d17be4de --- /dev/null +++ b/selfdrive/boardd/set_time.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import datetime +import os +import struct +import usb1 + +REQUEST_IN = usb1.ENDPOINT_IN | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE +MIN_DATE = datetime.datetime(year=2021, month=4, day=1) + +def set_time(logger): + sys_time = datetime.datetime.today() + if sys_time > MIN_DATE: + logger.info("System time valid") + return + + try: + ctx = usb1.USBContext() + dev = ctx.openByVendorIDAndProductID(0xbbaa, 0xddcc) + if dev is None: + logger.info("No panda found") + return + + # Set system time from panda RTC time + dat = dev.controlRead(REQUEST_IN, 0xa0, 0, 0, 8) + a = struct.unpack("HBBBBBB", dat) + panda_time = datetime.datetime(a[0], a[1], a[2], a[4], a[5], a[6]) + if panda_time > MIN_DATE: + logger.info(f"adjusting time from '{sys_time}' to '{panda_time}'") + os.system(f"TZ=UTC date -s '{panda_time}'") + except Exception: + logger.warn("Failed to fetch time from panda") + +if __name__ == "__main__": + import logging + logging.basicConfig(level=logging.INFO) + + set_time(logging) diff --git a/selfdrive/camerad/cameras/camera_common.cc b/selfdrive/camerad/cameras/camera_common.cc index b431eecac..6294c1580 100644 --- a/selfdrive/camerad/cameras/camera_common.cc +++ b/selfdrive/camerad/cameras/camera_common.cc @@ -1,29 +1,31 @@ -#include -#include -#include +#include "selfdrive/camerad/cameras/camera_common.h" + #include +#include #include +#include +#include -#if defined(QCOM) && !defined(QCOM_REPLAY) -#include "cameras/camera_qcom.h" -#elif QCOM2 -#include "cameras/camera_qcom2.h" -#elif WEBCAM -#include "cameras/camera_webcam.h" -#else -#include "cameras/camera_frame_stream.h" -#endif - -#include "camera_common.h" -#include +#include "libyuv.h" #include -#include "clutil.h" -#include "common/params.h" -#include "common/swaglog.h" -#include "common/util.h" -#include "modeldata.h" -#include "imgproc/utils.h" +#include "selfdrive/camerad/imgproc/utils.h" +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/modeldata.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" + +#if defined(QCOM) && !defined(QCOM_REPLAY) +#include "selfdrive/camerad/cameras/camera_qcom.h" +#elif QCOM2 +#include "selfdrive/camerad/cameras/camera_qcom2.h" +#elif WEBCAM +#include "selfdrive/camerad/cameras/camera_webcam.h" +#else +#include "selfdrive/camerad/cameras/camera_frame_stream.h" +#endif static cl_program build_debayer_program(cl_device_id device_id, cl_context context, const CameraInfo *ci, const CameraBuf *b, const CameraState *s) { char args[4096]; @@ -35,11 +37,8 @@ static cl_program build_debayer_program(cl_device_id device_id, cl_context conte ci->frame_width, ci->frame_height, ci->frame_stride, b->rgb_width, b->rgb_height, b->rgb_stride, ci->bayer_flip, ci->hdr, s->camera_num); -#ifdef QCOM2 - return cl_program_from_file(context, device_id, "cameras/real_debayer.cl", args); -#else - return cl_program_from_file(context, device_id, "cameras/debayer.cl", args); -#endif + const char *cl_file = Hardware::TICI() ? "cameras/real_debayer.cl" : "cameras/debayer.cl"; + return cl_program_from_file(context, device_id, cl_file, args); } void CameraBuf::init(cl_device_id device_id, cl_context context, CameraState *s, VisionIpcServer * v, int frame_cnt, VisionStreamType rgb_type, VisionStreamType yuv_type, release_cb release_callback) { @@ -64,13 +63,13 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, CameraState *s, rgb_width = ci->frame_width; rgb_height = ci->frame_height; -#ifndef QCOM2 - // debayering does a 2x downscale - if (ci->bayer) { + + if (!Hardware::TICI() && ci->bayer) { + // debayering does a 2x downscale rgb_width = ci->frame_width / 2; rgb_height = ci->frame_height / 2; } -#endif + yuv_transform = get_model_yuv_transform(ci->bayer); vipc_server->create_buffers(rgb_type, UI_BUF_COUNT, true, rgb_width, rgb_height); @@ -84,7 +83,7 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, CameraState *s, CL_CHECK(clReleaseProgram(prg_debayer)); } - rgb_to_yuv_init(&rgb_to_yuv_state, context, device_id, rgb_width, rgb_height, rgb_stride); + rgb2yuv = std::make_unique(context, device_id, rgb_width, rgb_height, rgb_stride); #ifdef __APPLE__ q = CL_CHECK_ERR(clCreateCommandQueue(context, device_id, 0, &err)); @@ -99,7 +98,6 @@ CameraBuf::~CameraBuf() { camera_bufs[i].free(); } - if (rgb_to_yuv_state.rgb_to_yuv_krnl) rgb_to_yuv_destroy(&rgb_to_yuv_state); if (krnl_debayer) CL_CHECK(clReleaseKernel(krnl_debayer)); if (q) CL_CHECK(clReleaseCommandQueue(q)); } @@ -114,7 +112,6 @@ bool CameraBuf::acquire() { } cur_frame_data = camera_bufs_metadata[cur_buf_idx]; - cur_rgb_buf = vipc_server->get_buffer(rgb_type); cl_event debayer_event; @@ -151,7 +148,7 @@ bool CameraBuf::acquire() { CL_CHECK(clReleaseEvent(debayer_event)); cur_yuv_buf = vipc_server->get_buffer(yuv_type); - rgb_to_yuv_queue(&rgb_to_yuv_state, q, cur_rgb_buf->buf_cl, cur_yuv_buf->buf_cl); + rgb2yuv->queue(q, cur_rgb_buf->buf_cl, cur_yuv_buf->buf_cl); VisionIpcBufExtra extra = { cur_frame_data.frame_id, @@ -348,73 +345,60 @@ std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, pro return std::thread(processing_thread, cameras, cs, callback); } -void common_process_driver_camera(SubMaster *sm, PubMaster *pm, CameraState *c, int cnt) { +static void driver_cam_auto_exposure(CameraState *c, SubMaster &sm) { + static const bool is_rhd = Params().getBool("IsRHD"); + struct ExpRect {int x1, x2, x_skip, y1, y2, y_skip;}; 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"); - - // auto exposure - if (cnt % 3 == 0) { - if (sm->update(0) > 0 && sm->updated("driverState")) { - auto state = (*sm)["driverState"].getDriverState(); - // set driver camera metering target - if (state.getFaceProb() > 0.4) { - auto face_position = state.getFacePosition(); + bool hist_ceil = false, hl_weighted = false; + int x_offset = 0, y_offset = 0; + int frame_width = b->rgb_width, frame_height = b->rgb_height; #ifndef QCOM2 - int frame_width = b->rgb_width; - int frame_height = b->rgb_height; + int analog_gain = -1; #else - int frame_width = 668; - int frame_height = frame_width / 1.33; + int analog_gain = c->analog_gain; #endif - int x_offset = is_rhd ? 0 : frame_width - (0.5 * frame_height); - x_offset += (face_position[0] * (is_rhd ? -1.0 : 1.0) + 0.5) * (0.5 * frame_height); - int y_offset = (face_position[1] + 0.5) * frame_height; -#ifdef QCOM2 - x_offset += 630; - y_offset += 156; -#endif - x_min = std::max(0, x_offset - 72); - x_max = std::min(b->rgb_width - 1, x_offset + 72); - y_min = std::max(0, y_offset - 72); - y_max = std::min(b->rgb_height - 1, y_offset + 72); - } else { // use default setting if no face - x_min = x_max = y_min = y_max = 0; - } - } - int skip = 1; - // use driver face crop for AE - if (x_max == 0) { - // default setting -#ifndef QCOM2 - x_min = is_rhd ? 0 : b->rgb_width * 3 / 5; - x_max = is_rhd ? b->rgb_width * 2 / 5 : b->rgb_width; - y_min = b->rgb_height / 3; - y_max = b->rgb_height; -#else - x_min = 96; - x_max = 1832; - y_min = 242; - y_max = 1148; - skip = 4; -#endif - } - -#ifdef QCOM2 - camera_autoexposure(c, set_exposure_target(b, x_min, x_max, 2, y_min, y_max, skip, (int)c->analog_gain, true, true)); -#else - camera_autoexposure(c, set_exposure_target(b, x_min, x_max, 2, y_min, y_max, skip, -1, false, false)); -#endif + ExpRect def_rect; + if (Hardware::TICI()) { + hist_ceil = hl_weighted = true; + x_offset = 630, y_offset = 156; + frame_width = 668, frame_height = frame_width / 1.33; + def_rect = {96, 1832, 2, 242, 1148, 4}; + } else { + def_rect = {is_rhd ? 0 : b->rgb_width * 3 / 5, is_rhd ? b->rgb_width * 2 / 5 : b->rgb_width, 2, + b->rgb_height / 3, b->rgb_height, 1}; } + static ExpRect rect = def_rect; + // use driver face crop for AE + if (sm.updated("driverState")) { + if (auto state = sm["driverState"].getDriverState(); state.getFaceProb() > 0.4) { + auto face_position = state.getFacePosition(); + int x = is_rhd ? 0 : frame_width - (0.5 * frame_height); + x += (face_position[0] * (is_rhd ? -1.0 : 1.0) + 0.5) * (0.5 * frame_height) + x_offset; + int y = (face_position[1] + 0.5) * frame_height + y_offset; + rect = {std::max(0, x - 72), std::min(b->rgb_width - 1, x + 72), 2, + std::max(0, y - 72), std::min(b->rgb_height - 1, y + 72), 1}; + } else { + rect = def_rect; + } + } + + camera_autoexposure(c, set_exposure_target(b, rect.x1, rect.x2, rect.x_skip, rect.y1, rect.y2, rect.y_skip, analog_gain, hist_ceil, hl_weighted)); +} + +void common_process_driver_camera(SubMaster *sm, PubMaster *pm, CameraState *c, int cnt) { + if (cnt % 3 == 0) { + sm->update(0); + driver_cam_auto_exposure(c, *sm); + } MessageBuilder msg; auto framed = msg.initEvent().initDriverCameraState(); framed.setFrameType(cereal::FrameData::FrameType::FRONT); - fill_frame_data(framed, b->cur_frame_data); + fill_frame_data(framed, c->buf.cur_frame_data); if (env_send_driver) { - framed.setImage(get_frame_image(b)); + framed.setImage(get_frame_image(&c->buf)); } pm->send("driverCameraState", msg); } diff --git a/selfdrive/camerad/cameras/camera_common.h b/selfdrive/camerad/cameras/camera_common.h index 55c25214e..337d33bdd 100644 --- a/selfdrive/camerad/cameras/camera_common.h +++ b/selfdrive/camerad/cameras/camera_common.h @@ -1,20 +1,21 @@ #pragma once -#include #include #include +#include + #include #include -#include "common/mat.h" -#include "common/swaglog.h" -#include "common/queue.h" -#include "visionbuf.h" -#include "common/visionimg.h" -#include "messaging.hpp" -#include "transforms/rgb_to_yuv.h" -#include "visionipc.h" -#include "visionipc_server.h" +#include "cereal/messaging/messaging.h" +#include "cereal/visionipc/visionbuf.h" +#include "cereal/visionipc/visionipc.h" +#include "cereal/visionipc/visionipc_server.h" +#include "selfdrive/camerad/transforms/rgb_to_yuv.h" +#include "selfdrive/common/mat.h" +#include "selfdrive/common/queue.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/visionimg.h" #define CAMERA_ID_IMX298 0 #define CAMERA_ID_IMX179 1 @@ -94,7 +95,7 @@ private: CameraState *camera_state; cl_kernel krnl_debayer; - RGBToYUVState rgb_to_yuv_state; + std::unique_ptr rgb2yuv; VisionStreamType rgb_type, yuv_type; diff --git a/selfdrive/camerad/cameras/camera_frame_stream.cc b/selfdrive/camerad/cameras/camera_frame_stream.cc index d6d44748f..a03feb132 100644 --- a/selfdrive/camerad/cameras/camera_frame_stream.cc +++ b/selfdrive/camerad/cameras/camera_frame_stream.cc @@ -1,12 +1,12 @@ -#include "camera_frame_stream.h" +#include "selfdrive/camerad/cameras/camera_frame_stream.h" #include #include #include -#include "messaging.hpp" -#include "common/util.h" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/util.h" #define FRAME_WIDTH 1164 #define FRAME_HEIGHT 874 @@ -35,7 +35,7 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = { }; void camera_init(VisionIpcServer * v, CameraState *s, int camera_id, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) { - assert(camera_id < ARRAYSIZE(cameras_supported)); + assert(camera_id < std::size(cameras_supported)); s->ci = cameras_supported[camera_id]; assert(s->ci.frame_width != 0); @@ -49,25 +49,26 @@ void run_frame_stream(CameraState &camera, const char* frame_pkt) { size_t buf_idx = 0; while (!do_exit) { - if (sm.update(1000) == 0) continue; + sm.update(1000); + if(sm.updated(frame_pkt)){ + auto msg = static_cast(sm[frame_pkt]); + auto frame = msg.get(frame_pkt).as(); + camera.buf.camera_bufs_metadata[buf_idx] = { + .frame_id = frame.get("frameId").as(), + .timestamp_eof = frame.get("timestampEof").as(), + .frame_length = frame.get("frameLength").as(), + .integ_lines = frame.get("integLines").as(), + .global_gain = frame.get("globalGain").as(), + }; - auto msg = static_cast(sm[frame_pkt]); - auto frame = msg.get(frame_pkt).as(); - camera.buf.camera_bufs_metadata[buf_idx] = { - .frame_id = frame.get("frameId").as(), - .timestamp_eof = frame.get("timestampEof").as(), - .frame_length = frame.get("frameLength").as(), - .integ_lines = frame.get("integLines").as(), - .global_gain = frame.get("globalGain").as(), - }; + cl_command_queue q = camera.buf.camera_bufs[buf_idx].copy_q; + cl_mem yuv_cl = camera.buf.camera_bufs[buf_idx].buf_cl; - cl_command_queue q = camera.buf.camera_bufs[buf_idx].copy_q; - cl_mem yuv_cl = camera.buf.camera_bufs[buf_idx].buf_cl; - - auto image = frame.get("image").as(); - clEnqueueWriteBuffer(q, yuv_cl, CL_TRUE, 0, image.size(), image.begin(), 0, NULL, NULL); - camera.buf.queue(buf_idx); - buf_idx = (buf_idx + 1) % FRAME_BUF_COUNT; + auto image = frame.get("image").as(); + clEnqueueWriteBuffer(q, yuv_cl, CL_TRUE, 0, image.size(), image.begin(), 0, NULL, NULL); + camera.buf.queue(buf_idx); + buf_idx = (buf_idx + 1) % FRAME_BUF_COUNT; + } } } diff --git a/selfdrive/camerad/cameras/camera_qcom.cc b/selfdrive/camerad/cameras/camera_qcom.cc index 40628e52f..7d5b1611c 100644 --- a/selfdrive/camerad/cameras/camera_qcom.cc +++ b/selfdrive/camerad/cameras/camera_qcom.cc @@ -1,32 +1,31 @@ -#include -#include +#include "selfdrive/camerad/cameras/camera_qcom.h" + #include -#include #include #include #include +#include +#include +#include #include -#include -#include +#include -#include +#include +#include #include +#include -#include -#include "msmb_isp.h" -#include "msmb_ispif.h" -#include "msmb_camera.h" -#include "msm_cam_sensor.h" - -#include "common/util.h" -#include "common/timing.h" -#include "common/swaglog.h" -#include "common/params.h" -#include "clutil.h" - -#include "sensor_i2c.h" -#include "camera_qcom.h" +#include "selfdrive/camerad/cameras/sensor_i2c.h" +#include "selfdrive/camerad/include/msm_cam_sensor.h" +#include "selfdrive/camerad/include/msmb_camera.h" +#include "selfdrive/camerad/include/msmb_isp.h" +#include "selfdrive/camerad/include/msmb_ispif.h" +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" // leeco actuator (DW9800W H-Bridge Driver IC) // from sniff @@ -34,6 +33,13 @@ const uint16_t INFINITY_DAC = 364; extern ExitHandler do_exit; +static int cam_ioctl(int fd, unsigned long int request, void *arg, const char *log_msg = nullptr) { + int err = ioctl(fd, request, arg); + if (err != 0 && log_msg) { + LOG(util::string_format("%s: %d", log_msg, err).c_str()); + } + return err; +} // global var for AE/AF ops std::atomic road_cam_exp{{0}}; std::atomic driver_cam_exp{{0}}; @@ -93,10 +99,10 @@ int sensor_write_regs(CameraState *s, struct msm_camera_i2c_reg_array* arr, size return ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &cfg_data); } -static int imx298_apply_exposure(CameraState *s, int gain, int integ_lines, int frame_length) { +static int imx298_apply_exposure(CameraState *s, int gain, int integ_lines, uint32_t frame_length) { int analog_gain = std::min(gain, 448); s->digital_gain = gain > 448 ? (512.0/(512-(gain))) / 8.0 : 1.0; - //printf("%5d/%5d %5d %f\n", s->cur_integ_lines, s->cur_frame_length, analog_gain, s->digital_gain); + //printf("%5d/%5d %5d %f\n", s->cur_integ_lines, s->frame_length, analog_gain, s->digital_gain); struct msm_camera_i2c_reg_array reg_array[] = { // REG_HOLD @@ -120,17 +126,17 @@ static int imx298_apply_exposure(CameraState *s, int gain, int integ_lines, int // REG_HOLD {0x104,0x0,0}, }; - return sensor_write_regs(s, reg_array, ARRAYSIZE(reg_array), MSM_CAMERA_I2C_BYTE_DATA); + return sensor_write_regs(s, reg_array, std::size(reg_array), MSM_CAMERA_I2C_BYTE_DATA); } -static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, int frame_length) { +static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, uint32_t frame_length) { //printf("driver camera: %d %d %d\n", gain, integ_lines, frame_length); int coarse_gain_bitmap, fine_gain_bitmap; // get bitmaps from iso static const int gains[] = {0, 100, 200, 400, 800}; int i; - for (i = 1; i < ARRAYSIZE(gains); i++) { + for (i = 1; i < std::size(gains); i++) { if (gain >= gains[i - 1] && gain < gains[i]) break; } @@ -155,7 +161,7 @@ static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, int //{0x104,0x0,0}, }; - return sensor_write_regs(s, reg_array, ARRAYSIZE(reg_array), MSM_CAMERA_I2C_BYTE_DATA); + return sensor_write_regs(s, reg_array, std::size(reg_array), MSM_CAMERA_I2C_BYTE_DATA); } static void camera_init(VisionIpcServer *v, CameraState *s, int camera_id, int camera_num, @@ -165,14 +171,14 @@ static void camera_init(VisionIpcServer *v, CameraState *s, int camera_id, int c s->camera_num = camera_num; s->camera_id = camera_id; - assert(camera_id < ARRAYSIZE(cameras_supported)); + assert(camera_id < std::size(cameras_supported)); s->ci = cameras_supported[camera_id]; assert(s->ci.frame_width != 0); s->pixel_clock = pixel_clock; - s->line_length_pclk = line_length_pclk; s->max_gain = max_gain; s->fps = fps; + s->frame_length = s->pixel_clock / line_length_pclk / s->fps; s->self_recover = 0; s->apply_exposure = (camera_id == CAMERA_ID_IMX298) ? imx298_apply_exposure : ov8865_apply_exposure; @@ -228,18 +234,15 @@ void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_i static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) { int err = 0; - - uint32_t frame_length = s->pixel_clock / s->line_length_pclk / s->fps; - uint32_t gain = s->cur_gain; uint32_t integ_lines = s->cur_integ_lines; if (exposure_frac >= 0) { - exposure_frac = std::clamp(exposure_frac, 2.0f / frame_length, 1.0f); - integ_lines = frame_length * exposure_frac; + exposure_frac = std::clamp(exposure_frac, 2.0f / s->frame_length, 1.0f); + integ_lines = s->frame_length * exposure_frac; // See page 79 of the datasheet, this is the max allowed (-1 for phase adjust) - integ_lines = std::min(integ_lines, frame_length-11); + integ_lines = std::min(integ_lines, s->frame_length - 11); } if (gain_frac >= 0) { @@ -256,19 +259,15 @@ static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) { gain = (s->max_gain/510) * (512 - 512/(256*gain_frac)); } - if (gain != s->cur_gain - || integ_lines != s->cur_integ_lines - || frame_length != s->cur_frame_length) { - + if (gain != s->cur_gain || integ_lines != s->cur_integ_lines) { if (s->apply_exposure == ov8865_apply_exposure) { gain = 800 * gain_frac; // ISO } - err = s->apply_exposure(s, gain, integ_lines, frame_length); + err = s->apply_exposure(s, gain, integ_lines, s->frame_length); if (err == 0) { std::lock_guard lk(s->frame_info_lock); s->cur_gain = gain; s->cur_integ_lines = integ_lines; - s->cur_frame_length = frame_length; } else { LOGE("camera %d apply_exposure err: %d", s->camera_num, err); } @@ -290,9 +289,8 @@ static void do_autoexposure(CameraState *s, float grey_frac) { const float gain_frac_min = 0.015625; const float gain_frac_max = 1.0; // exposure time limits - uint32_t frame_length = s->pixel_clock / s->line_length_pclk / s->fps; const uint32_t exposure_time_min = 16; - const uint32_t exposure_time_max = frame_length - 11; // copied from set_exposure() + const uint32_t exposure_time_max = s->frame_length - 11; // copied from set_exposure() float cur_gain_frac = s->cur_gain_frac; float exposure_factor = pow(1.05, (target_grey - grey_frac) / 0.05); @@ -325,14 +323,8 @@ static void do_autoexposure(CameraState *s, float grey_frac) { } static void sensors_init(MultiCameraState *s) { - unique_fd sensorinit_fd; - sensorinit_fd = open("/dev/v4l-subdev11", O_RDWR | O_NONBLOCK); - assert(sensorinit_fd >= 0); - - // init road camera sensor - - struct msm_camera_sensor_slave_info slave_info = {0}; - slave_info = (struct msm_camera_sensor_slave_info){ + msm_camera_sensor_slave_info slave_infos[2] = { + (msm_camera_sensor_slave_info){ // road camera .sensor_name = "imx298", .eeprom_name = "sony_imx298", .actuator_name = "dw9800w", @@ -367,16 +359,8 @@ static void sensors_init(MultiCameraState *s) { .is_init_params_valid = 0, .sensor_init_params = {.modes_supported = 1, .position = BACK_CAMERA_B, .sensor_mount_angle = 90}, .output_format = MSM_SENSOR_BAYER, - }; - slave_info.power_setting_array.power_setting = &slave_info.power_setting_array.power_setting_a[0]; - slave_info.power_setting_array.power_down_setting = &slave_info.power_setting_array.power_down_setting_a[0]; - sensor_init_cfg_data sensor_init_cfg = {.cfgtype = CFG_SINIT_PROBE, .cfg.setting = &slave_info}; - int err = ioctl(sensorinit_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &sensor_init_cfg); - LOG("sensor init cfg (road camera): %d", err); - assert(err >= 0); - - struct msm_camera_sensor_slave_info slave_info2 = {0}; - slave_info2 = (struct msm_camera_sensor_slave_info){ + }, + (msm_camera_sensor_slave_info){ // driver camera .sensor_name = "ov8865_sunny", .eeprom_name = "ov8865_plus", .actuator_name = "", @@ -409,14 +393,17 @@ static void sensors_init(MultiCameraState *s) { .is_init_params_valid = 0, .sensor_init_params = {.modes_supported = 1, .position = FRONT_CAMERA_B, .sensor_mount_angle = 270}, .output_format = MSM_SENSOR_BAYER, - }; - slave_info2.power_setting_array.power_setting = &slave_info2.power_setting_array.power_setting_a[0]; - slave_info2.power_setting_array.power_down_setting = &slave_info2.power_setting_array.power_down_setting_a[0]; - sensor_init_cfg.cfgtype = CFG_SINIT_PROBE; - sensor_init_cfg.cfg.setting = &slave_info2; - err = ioctl(sensorinit_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &sensor_init_cfg); - LOG("sensor init cfg (driver camera): %d", err); - assert(err >= 0); + }}; + + unique_fd sensorinit_fd = open("/dev/v4l-subdev11", O_RDWR | O_NONBLOCK); + assert(sensorinit_fd >= 0); + for (auto &info : slave_infos) { + info.power_setting_array.power_setting = &info.power_setting_array.power_setting_a[0]; + info.power_setting_array.power_down_setting = &info.power_setting_array.power_down_setting_a[0]; + sensor_init_cfg_data sensor_init_cfg = {.cfgtype = CFG_SINIT_PROBE, .cfg.setting = &info}; + int err = cam_ioctl(sensorinit_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &sensor_init_cfg, "sensor init cfg"); + assert(err >= 0); + } } static void camera_open(CameraState *s, bool is_road_cam) { @@ -463,23 +450,19 @@ static void camera_open(CameraState *s, bool is_road_cam) { struct msm_camera_csi_lane_params csi_lane_params = {0}; csi_lane_params.csi_lane_mask = 0x1f; csiphy_cfg_data csiphy_cfg_data = { .cfg.csi_lane_params = &csi_lane_params, .cfgtype = CSIPHY_RELEASE}; - int err = ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data); - LOG("release csiphy: %d", err); + int err = cam_ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data, "release csiphy"); // CSID: release csid csid_cfg_data.cfgtype = CSID_RELEASE; - err = ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data); - LOG("release csid: %d", err); + cam_ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data, "release csid"); // SENSOR: send power down struct sensorb_cfg_data sensorb_cfg_data = {.cfgtype = CFG_POWER_DOWN}; - err = ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &sensorb_cfg_data); - LOG("sensor power down: %d", err); + cam_ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &sensorb_cfg_data, "sensor power down"); // actuator powerdown actuator_cfg_data.cfgtype = CFG_ACTUATOR_POWERDOWN; - err = ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data); - LOG("actuator powerdown: %d", err); + cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator powerdown"); // reset isp // struct msm_vfe_axi_halt_cmd halt_cmd = { @@ -508,39 +491,35 @@ static void camera_open(CameraState *s, bool is_road_cam) { // CSID: init csid csid_cfg_data.cfgtype = CSID_INIT; - err = ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data); - LOG("init csid: %d", err); + cam_ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data, "init csid"); // CSIPHY: init csiphy csiphy_cfg_data = {.cfgtype = CSIPHY_INIT}; - err = ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data); - LOG("init csiphy: %d", err); + cam_ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data, "init csiphy"); // SENSOR: stop stream struct msm_camera_i2c_reg_setting stop_settings = { .reg_setting = stop_reg_array, - .size = ARRAYSIZE(stop_reg_array), + .size = std::size(stop_reg_array), .addr_type = MSM_CAMERA_I2C_WORD_ADDR, .data_type = MSM_CAMERA_I2C_BYTE_DATA, .delay = 0 }; sensorb_cfg_data.cfgtype = CFG_SET_STOP_STREAM_SETTING; sensorb_cfg_data.cfg.setting = &stop_settings; - err = ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &sensorb_cfg_data); - LOG("stop stream: %d", err); + cam_ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &sensorb_cfg_data, "stop stream"); // SENSOR: send power up sensorb_cfg_data = {.cfgtype = CFG_POWER_UP}; - err = ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &sensorb_cfg_data); - LOG("sensor power up: %d", err); + cam_ioctl(s->sensor_fd, VIDIOC_MSM_SENSOR_CFG, &sensorb_cfg_data, "sensor power up"); // **** configure the sensor **** // SENSOR: send i2c configuration if (s->camera_id == CAMERA_ID_IMX298) { - err = sensor_write_regs(s, init_array_imx298, ARRAYSIZE(init_array_imx298), MSM_CAMERA_I2C_BYTE_DATA); + err = sensor_write_regs(s, init_array_imx298, std::size(init_array_imx298), MSM_CAMERA_I2C_BYTE_DATA); } else if (s->camera_id == CAMERA_ID_OV8865) { - err = sensor_write_regs(s, init_array_ov8865, ARRAYSIZE(init_array_ov8865), MSM_CAMERA_I2C_BYTE_DATA); + err = sensor_write_regs(s, init_array_ov8865, std::size(init_array_ov8865), MSM_CAMERA_I2C_BYTE_DATA); } else { assert(false); } @@ -549,12 +528,10 @@ static void camera_open(CameraState *s, bool is_road_cam) { if (is_road_cam) { // init the actuator actuator_cfg_data.cfgtype = CFG_ACTUATOR_POWERUP; - err = ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data); - LOG("actuator powerup: %d", err); + cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator powerup"); actuator_cfg_data.cfgtype = CFG_ACTUATOR_INIT; - err = ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data); - LOG("actuator init: %d", err); + cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator init"); struct msm_actuator_reg_params_t actuator_reg_params[] = { { @@ -605,12 +582,11 @@ static void camera_open(CameraState *s, bool is_road_cam) { }, }; - err = ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data); - LOG("actuator set info: %d", err); + cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator set info"); } if (s->camera_id == CAMERA_ID_IMX298) { - err = sensor_write_regs(s, mode_setting_array_imx298, ARRAYSIZE(mode_setting_array_imx298), MSM_CAMERA_I2C_BYTE_DATA); + err = sensor_write_regs(s, mode_setting_array_imx298, std::size(mode_setting_array_imx298), MSM_CAMERA_I2C_BYTE_DATA); LOG("sensor setup: %d", err); } @@ -624,8 +600,7 @@ static void camera_open(CameraState *s, bool is_road_cam) { } csiphy_cfg_data.cfgtype = CSIPHY_CFG; csiphy_cfg_data.cfg.csiphy_params = &csiphy_params; - err = ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data); - LOG("csiphy configure: %d", err); + cam_ioctl(s->csiphy_fd, VIDIOC_MSM_CSIPHY_IO_CFG, &csiphy_cfg_data, "csiphy configure"); // CSID: configure csid #define CSI_STATS 0x35 @@ -648,13 +623,11 @@ static void camera_open(CameraState *s, bool is_road_cam) { csid_cfg_data.cfgtype = CSID_CFG; csid_cfg_data.cfg.csid_params = &csid_params; - err = ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data); - LOG("csid configure: %d", err); + cam_ioctl(s->csid_fd, VIDIOC_MSM_CSID_IO_CFG, &csid_cfg_data, "csid configure"); // ISP: SMMU_ATTACH msm_vfe_smmu_attach_cmd smmu_attach_cmd = {.security_mode = 0, .iommu_attach_mode = IOMMU_ATTACH}; - err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_SMMU_ATTACH, &smmu_attach_cmd); - LOG("isp smmu attach: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_SMMU_ATTACH, &smmu_attach_cmd, "isp smmu attach"); // ******************* STREAM RAW ***************************** @@ -714,8 +687,7 @@ static void camera_open(CameraState *s, bool is_road_cam) { ss->buf_request.num_buf = FRAME_BUF_COUNT; ss->buf_request.buf_type = ISP_PRIVATE_BUF; ss->buf_request.handle = 0; - err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_REQUEST_BUF, &ss->buf_request); - LOG("isp request buf: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_REQUEST_BUF, &ss->buf_request, "isp request buf"); LOG("got buf handle: 0x%x", ss->buf_request.handle); // ENQUEUE all buffers @@ -734,16 +706,14 @@ static void camera_open(CameraState *s, bool is_road_cam) { update_cmd.update_info[0].user_stream_id = ss->stream_req.stream_id; update_cmd.update_info[0].stream_handle = ss->stream_req.axi_stream_handle; update_cmd.update_type = UPDATE_STREAM_ADD_BUFQ; - err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_UPDATE_STREAM, &update_cmd); - LOG("isp update stream: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_UPDATE_STREAM, &update_cmd, "isp update stream"); } LOG("******** START STREAMS ********"); sub.id = 0; sub.type = 0x1ff; - err = ioctl(s->isp_fd, VIDIOC_SUBSCRIBE_EVENT, &sub); - LOG("isp subscribe: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_SUBSCRIBE_EVENT, &sub, "isp subscribe"); // ISP: START_STREAM s->stream_cfg.cmd = START_STREAM; @@ -751,14 +721,13 @@ static void camera_open(CameraState *s, bool is_road_cam) { for (int i = 0; i < s->stream_cfg.num_streams; i++) { s->stream_cfg.stream_handle[i] = s->ss[i].stream_req.axi_stream_handle; } - err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_CFG_STREAM, &s->stream_cfg); - LOG("isp start stream: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_CFG_STREAM, &s->stream_cfg, "isp start stream"); } static void road_camera_start(CameraState *s) { set_exposure(s, 1.0, 1.0); - int err = sensor_write_regs(s, start_reg_array, ARRAYSIZE(start_reg_array), MSM_CAMERA_I2C_BYTE_DATA); + int err = sensor_write_regs(s, start_reg_array, std::size(start_reg_array), MSM_CAMERA_I2C_BYTE_DATA); LOG("sensor start regs: %d", err); int inf_step = 512 - INFINITY_DAC; @@ -775,8 +744,7 @@ static void road_camera_start(CameraState *s) { .pos = {INFINITY_DAC, 0}, .delay = {0,} }; - err = ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data); - LOG("actuator set pos: %d", err); + cam_ioctl(s->actuator_fd, VIDIOC_MSM_ACTUATOR_CFG, &actuator_cfg_data, "actuator set pos"); // TODO: confirm this isn't needed /*memset(&actuator_cfg_data, 0, sizeof(actuator_cfg_data)); @@ -881,7 +849,8 @@ static void parse_autofocus(CameraState *s, uint8_t *d) { } static std::optional get_accel_z(SubMaster *sm) { - if (sm->update(0) > 0) { + sm->update(0); + if(sm->updated("sensorEvents")){ for (auto event : (*sm)["sensorEvents"].getSensorEvents()) { if (event.which() == cereal::SensorEventData::ACCELERATION) { if (auto v = event.getAcceleration().getV(); v.size() >= 3) @@ -936,7 +905,7 @@ void camera_autoexposure(CameraState *s, float grey_frac) { static void driver_camera_start(CameraState *s) { set_exposure(s, 1.0, 1.0); - int err = sensor_write_regs(s, start_reg_array, ARRAYSIZE(start_reg_array), MSM_CAMERA_I2C_BYTE_DATA); + int err = sensor_write_regs(s, start_reg_array, std::size(start_reg_array), MSM_CAMERA_I2C_BYTE_DATA); LOG("sensor start regs: %d", err); } @@ -994,16 +963,13 @@ void cameras_open(MultiCameraState *s) { // ISPIF: setup ispif_cfg_data = {.cfg_type = ISPIF_INIT, .csid_version = 0x30050000 /* CSID_VERSION_V35*/}; - err = ioctl(s->ispif_fd, VIDIOC_MSM_ISPIF_CFG, &ispif_cfg_data); - LOG("ispif setup: %d", err); + cam_ioctl(s->ispif_fd, VIDIOC_MSM_ISPIF_CFG, &ispif_cfg_data, "ispif setup"); ispif_cfg_data = {.cfg_type = ISPIF_CFG, .params = ispif_params}; - err = ioctl(s->ispif_fd, VIDIOC_MSM_ISPIF_CFG, &ispif_cfg_data); - LOG("ispif cfg: %d", err); + cam_ioctl(s->ispif_fd, VIDIOC_MSM_ISPIF_CFG, &ispif_cfg_data, "ispif cfg"); ispif_cfg_data.cfg_type = ISPIF_START_FRAME_BOUNDARY; - err = ioctl(s->ispif_fd, VIDIOC_MSM_ISPIF_CFG, &ispif_cfg_data); - LOG("ispif start_frame_boundary: %d", err); + cam_ioctl(s->ispif_fd, VIDIOC_MSM_ISPIF_CFG, &ispif_cfg_data, "ispif start_frame_boundary"); driver_camera_start(&s->driver_cam); road_camera_start(&s->road_cam); @@ -1013,20 +979,17 @@ void cameras_open(MultiCameraState *s) { static void camera_close(CameraState *s) { // ISP: STOP_STREAM s->stream_cfg.cmd = STOP_STREAM; - int err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_CFG_STREAM, &s->stream_cfg); - LOG("isp stop stream: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_CFG_STREAM, &s->stream_cfg, "isp stop stream"); for (int i = 0; i < 3; i++) { StreamState *ss = &s->ss[i]; if (ss->stream_req.axi_stream_handle != 0) { - err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_RELEASE_BUF, &ss->buf_request); - LOG("isp release buf: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_RELEASE_BUF, &ss->buf_request, "isp release buf"); struct msm_vfe_axi_stream_release_cmd stream_release = { .stream_handle = ss->stream_req.axi_stream_handle, }; - err = ioctl(s->isp_fd, VIDIOC_MSM_ISP_RELEASE_STREAM, &stream_release); - LOG("isp release stream: %d", err); + cam_ioctl(s->isp_fd, VIDIOC_MSM_ISP_RELEASE_STREAM, &stream_release, "isp release stream"); } } } @@ -1161,7 +1124,7 @@ void cameras_run(MultiCameraState *s) { while (!do_exit) { struct pollfd fds[2] = {{.fd = cameras[0]->isp_fd, .events = POLLPRI}, {.fd = cameras[1]->isp_fd, .events = POLLPRI}}; - int ret = poll(fds, ARRAYSIZE(fds), 1000); + int ret = poll(fds, std::size(fds), 1000); if (ret < 0) { if (errno == EINTR || errno == EAGAIN) continue; LOGE("poll failed (%d - %d)", ret, errno); @@ -1199,7 +1162,7 @@ void cameras_run(MultiCameraState *s) { c->frame_metadata[c->frame_metadata_idx] = (FrameMetadata){ .frame_id = isp_event_data->frame_id, .timestamp_eof = timestamp, - .frame_length = (uint32_t)c->cur_frame_length, + .frame_length = (uint32_t)c->frame_length, .integ_lines = (uint32_t)c->cur_integ_lines, .global_gain = (uint32_t)c->cur_gain, .lens_pos = c->cur_lens_pos, diff --git a/selfdrive/camerad/cameras/camera_qcom.h b/selfdrive/camerad/cameras/camera_qcom.h index 1ab817f41..55792c4ff 100644 --- a/selfdrive/camerad/cameras/camera_qcom.h +++ b/selfdrive/camerad/cameras/camera_qcom.h @@ -1,24 +1,22 @@ #pragma once -#include -#include #include -#include +#include +#include + #include -#include "messaging.hpp" +#include -#include "msmb_isp.h" -#include "msmb_ispif.h" -#include "msmb_camera.h" -#include "msm_cam_sensor.h" - -#include "visionbuf.h" - -#include "common/mat.h" -#include "common/util.h" -#include "imgproc/utils.h" - -#include "camera_common.h" +#include "cereal/messaging/messaging.h" +#include "cereal/visionipc/visionbuf.h" +#include "selfdrive/camerad/cameras/camera_common.h" +#include "selfdrive/camerad/imgproc/utils.h" +#include "selfdrive/camerad/include/msm_cam_sensor.h" +#include "selfdrive/camerad/include/msmb_camera.h" +#include "selfdrive/camerad/include/msmb_isp.h" +#include "selfdrive/camerad/include/msmb_ispif.h" +#include "selfdrive/common/mat.h" +#include "selfdrive/common/util.h" #define FRAME_BUF_COUNT 4 #define METADATA_BUF_COUNT 4 @@ -35,7 +33,7 @@ typedef struct CameraState CameraState; -typedef int (*camera_apply_exposure_func)(CameraState *s, int gain, int integ_lines, int frame_length); +typedef int (*camera_apply_exposure_func)(CameraState *s, int gain, int integ_lines, uint32_t frame_length); typedef struct StreamState { struct msm_isp_buf_request buf_request; @@ -67,10 +65,10 @@ typedef struct CameraState { // exposure uint32_t pixel_clock, line_length_pclk; - uint32_t max_gain; + uint32_t frame_length; + unsigned int max_gain; float cur_exposure_frac, cur_gain_frac; int cur_gain, cur_integ_lines; - int cur_frame_length; std::atomic digital_gain; camera_apply_exposure_func apply_exposure; diff --git a/selfdrive/camerad/cameras/camera_qcom2.cc b/selfdrive/camerad/cameras/camera_qcom2.cc index ae81db6bb..0f0fb10b5 100644 --- a/selfdrive/camerad/cameras/camera_qcom2.cc +++ b/selfdrive/camerad/cameras/camera_qcom2.cc @@ -1,4 +1,3 @@ - #include #include #include @@ -11,19 +10,17 @@ #include #include -#include "common/util.h" -#include "common/swaglog.h" -#include "camera_qcom2.h" - #include "media/cam_defs.h" #include "media/cam_isp.h" #include "media/cam_isp_ife.h" #include "media/cam_sensor_cmn_header.h" #include "media/cam_sensor.h" #include "media/cam_sync.h" - #include "sensor2_i2c.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/camerad/cameras/camera_qcom2.h" + #define FRAME_WIDTH 1928 #define FRAME_HEIGHT 1208 //#define FRAME_STRIDE 1936 // for 8 bit output @@ -140,7 +137,7 @@ void clear_req_queue(int fd, int32_t session_hdl, int32_t link_hdl) { void sensors_poke(struct CameraState *s, int request_id) { uint32_t cam_packet_handle = 0; int size = sizeof(struct cam_packet); - struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->video0_fd, size, &cam_packet_handle); + struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle); pkt->num_cmd_buf = 0; pkt->kmd_cmd_buf_index = -1; pkt->header.size = size; @@ -157,14 +154,14 @@ void sensors_poke(struct CameraState *s, int request_id) { assert(ret == 0); munmap(pkt, size); - release_fd(s->video0_fd, cam_packet_handle); + release_fd(s->multi_cam_state->video0_fd, cam_packet_handle); } void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int len, int op_code) { // LOGD("sensors_i2c: %d", len); uint32_t cam_packet_handle = 0; int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1; - struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->video0_fd, size, &cam_packet_handle); + struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle); pkt->num_cmd_buf = 1; pkt->kmd_cmd_buf_index = -1; pkt->header.size = size; @@ -174,7 +171,7 @@ void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int l buf_desc[0].size = buf_desc[0].length = sizeof(struct i2c_rdwr_header) + len*sizeof(struct i2c_random_wr_payload); buf_desc[0].type = CAM_CMD_BUF_I2C; - struct cam_cmd_i2c_random_wr *i2c_random_wr = (struct cam_cmd_i2c_random_wr *)alloc_w_mmu_hdl(s->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle); + struct cam_cmd_i2c_random_wr *i2c_random_wr = (struct cam_cmd_i2c_random_wr *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle); i2c_random_wr->header.count = len; i2c_random_wr->header.op_code = 1; i2c_random_wr->header.cmd_type = CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR; @@ -192,10 +189,17 @@ void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int l assert(ret == 0); munmap(i2c_random_wr, buf_desc[0].size); - release_fd(s->video0_fd, buf_desc[0].mem_handle); + release_fd(s->multi_cam_state->video0_fd, buf_desc[0].mem_handle); munmap(pkt, size); - release_fd(s->video0_fd, cam_packet_handle); + release_fd(s->multi_cam_state->video0_fd, cam_packet_handle); } +static cam_cmd_power *power_set_wait(cam_cmd_power *power, int16_t delay_ms) { + cam_cmd_unconditional_wait *unconditional_wait = (cam_cmd_unconditional_wait *)((char *)power + (sizeof(struct cam_cmd_power) + (power->count - 1) * sizeof(struct cam_power_settings))); + unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; + unconditional_wait->delay = delay_ms; + unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; + return (struct cam_cmd_power *)(unconditional_wait + 1); +}; void sensors_init(int video0_fd, int sensor_fd, int camera_num) { uint32_t cam_packet_handle = 0; @@ -246,11 +250,8 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { //buf_desc[1].size = buf_desc[1].length = 148; buf_desc[1].size = buf_desc[1].length = 196; buf_desc[1].type = CAM_CMD_BUF_I2C; - struct cam_cmd_power *power = (struct cam_cmd_power *)alloc_w_mmu_hdl(video0_fd, buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle); - memset(power, 0, buf_desc[1].size); - struct cam_cmd_unconditional_wait *unconditional_wait; - - //void *ptr = power; + struct cam_cmd_power *power_settings = (struct cam_cmd_power *)alloc_w_mmu_hdl(video0_fd, buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle); + memset(power_settings, 0, buf_desc[1].size); // 7750 /*power->count = 2; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; @@ -259,45 +260,28 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { power = (void*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings));*/ // 885a + struct cam_cmd_power *power = power_settings; power->count = 4; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; power->power_settings[0].power_seq_type = 3; // clock?? power->power_settings[1].power_seq_type = 1; // analog power->power_settings[2].power_seq_type = 2; // digital power->power_settings[3].power_seq_type = 8; // reset low - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); - - unconditional_wait = (struct cam_cmd_unconditional_wait *)power; - unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; - unconditional_wait->delay = 5; - unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; - power = (struct cam_cmd_power *)((char*)power + sizeof(struct cam_cmd_unconditional_wait)); + power = power_set_wait(power, 5); // set clock power->count = 1; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; power->power_settings[0].power_seq_type = 0; power->power_settings[0].config_val_low = 24000000; //Hz - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); - - unconditional_wait = (struct cam_cmd_unconditional_wait *)power; - unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; - unconditional_wait->delay = 10; // ms - unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; - power = (struct cam_cmd_power *)((char*)power + sizeof(struct cam_cmd_unconditional_wait)); + power = power_set_wait(power, 10); // 8,1 is this reset? power->count = 1; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; power->power_settings[0].power_seq_type = 8; power->power_settings[0].config_val_low = 1; - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); - - unconditional_wait = (struct cam_cmd_unconditional_wait *)power; - unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; - unconditional_wait->delay = 100; // ms - unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; - power = (struct cam_cmd_power *)((char*)power + sizeof(struct cam_cmd_unconditional_wait)); + power = power_set_wait(power, 100); // probe happens here @@ -306,39 +290,21 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN; power->power_settings[0].power_seq_type = 0; power->power_settings[0].config_val_low = 0; - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); - - unconditional_wait = (struct cam_cmd_unconditional_wait *)power; - unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; - unconditional_wait->delay = 1; - unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; - power = (struct cam_cmd_power *)((char*)power + sizeof(struct cam_cmd_unconditional_wait)); + power = power_set_wait(power, 1); // reset high power->count = 1; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN; power->power_settings[0].power_seq_type = 8; power->power_settings[0].config_val_low = 1; - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); - - unconditional_wait = (struct cam_cmd_unconditional_wait *)power; - unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; - unconditional_wait->delay = 1; - unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; - power = (struct cam_cmd_power *)((char*)power + sizeof(struct cam_cmd_unconditional_wait)); + power = power_set_wait(power, 1); // reset low power->count = 1; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN; power->power_settings[0].power_seq_type = 8; power->power_settings[0].config_val_low = 0; - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); - - unconditional_wait = (struct cam_cmd_unconditional_wait *)power; - unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; - unconditional_wait->delay = 1; - unconditional_wait->op_code = CAMERA_SENSOR_WAIT_OP_SW_UCND; - power = (struct cam_cmd_power *)((char*)power + sizeof(struct cam_cmd_unconditional_wait)); + power = power_set_wait(power, 1); // 7750 /*power->count = 1; @@ -352,7 +318,6 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { power->power_settings[0].power_seq_type = 2; power->power_settings[1].power_seq_type = 1; power->power_settings[2].power_seq_type = 3; - power = (struct cam_cmd_power *)((char*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings))); LOGD("probing the sensor"); int ret = cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0); @@ -360,7 +325,7 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { munmap(i2c_info, buf_desc[0].size); release_fd(video0_fd, buf_desc[0].mem_handle); - munmap(power, buf_desc[1].size); + munmap(power_settings, buf_desc[1].size); release_fd(video0_fd, buf_desc[1].mem_handle); munmap(pkt, size); release_fd(video0_fd, cam_packet_handle); @@ -372,7 +337,7 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request if (io_mem_handle != 0) { size += sizeof(struct cam_buf_io_cfg); } - struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->video0_fd, size, &cam_packet_handle); + struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle); pkt->num_cmd_buf = 2; pkt->kmd_cmd_buf_index = 0; @@ -408,7 +373,7 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request } buf_desc[1].type = CAM_CMD_BUF_GENERIC; buf_desc[1].meta_data = CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON; - uint32_t *buf2 = (uint32_t *)alloc_w_mmu_hdl(s->video0_fd, buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle, 0x20); + uint32_t *buf2 = (uint32_t *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle, 0x20); // cam_isp_packet_generic_blob_handler uint32_t tmp[] = { @@ -466,16 +431,16 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request config_dev_cmd.offset = 0; config_dev_cmd.packet_handle = cam_packet_handle; - int ret = cam_control(s->isp_fd, CAM_CONFIG_DEV, &config_dev_cmd, sizeof(config_dev_cmd)); + int ret = cam_control(s->multi_cam_state->isp_fd, CAM_CONFIG_DEV, &config_dev_cmd, sizeof(config_dev_cmd)); if (ret != 0) { printf("ISP CONFIG FAILED\n"); } munmap(buf2, buf_desc[1].size); - release_fd(s->video0_fd, buf_desc[1].mem_handle); - // release_fd(s->video0_fd, buf_desc[0].mem_handle); + release_fd(s->multi_cam_state->video0_fd, buf_desc[1].mem_handle); + // release_fd(s->multi_cam_state->video0_fd, buf_desc[0].mem_handle); munmap(pkt, size); - release_fd(s->video0_fd, cam_packet_handle); + release_fd(s->multi_cam_state->video0_fd, cam_packet_handle); } void enqueue_buffer(struct CameraState *s, int i, bool dp) { @@ -483,12 +448,12 @@ void enqueue_buffer(struct CameraState *s, int i, bool dp) { int request_id = s->request_ids[i]; if (s->buf_handle[i]) { - release(s->video0_fd, s->buf_handle[i]); + release(s->multi_cam_state->video0_fd, s->buf_handle[i]); // wait struct cam_sync_wait sync_wait = {0}; sync_wait.sync_obj = s->sync_objs[i]; sync_wait.timeout_ms = 50; // max dt tolerance, typical should be 23 - ret = cam_control(s->video1_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait)); + ret = cam_control(s->multi_cam_state->video1_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait)); // LOGD("fence wait: %d %d", ret, sync_wait.sync_obj); s->buf.camera_bufs_metadata[i].timestamp_eof = (uint64_t)nanos_since_boot(); // set true eof @@ -498,7 +463,7 @@ void enqueue_buffer(struct CameraState *s, int i, bool dp) { struct cam_sync_info sync_destroy = {0}; strcpy(sync_destroy.name, "NodeOutputPortFence"); sync_destroy.sync_obj = s->sync_objs[i]; - ret = cam_control(s->video1_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy)); + ret = cam_control(s->multi_cam_state->video1_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy)); // LOGD("fence destroy: %d %d", ret, sync_destroy.sync_obj); } @@ -507,23 +472,23 @@ void enqueue_buffer(struct CameraState *s, int i, bool dp) { req_mgr_sched_request.session_hdl = s->session_handle; req_mgr_sched_request.link_hdl = s->link_handle; req_mgr_sched_request.req_id = request_id; - ret = cam_control(s->video0_fd, CAM_REQ_MGR_SCHED_REQ, &req_mgr_sched_request, sizeof(req_mgr_sched_request)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_SCHED_REQ, &req_mgr_sched_request, sizeof(req_mgr_sched_request)); // LOGD("sched req: %d %d", ret, request_id); // create output fence struct cam_sync_info sync_create = {0}; strcpy(sync_create.name, "NodeOutputPortFence"); - ret = cam_control(s->video1_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create)); + ret = cam_control(s->multi_cam_state->video1_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create)); // LOGD("fence req: %d %d", ret, sync_create.sync_obj); s->sync_objs[i] = sync_create.sync_obj; // configure ISP to put the image in place struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0}; - mem_mgr_map_cmd.mmu_hdls[0] = s->device_iommu; + mem_mgr_map_cmd.mmu_hdls[0] = s->multi_cam_state->device_iommu; mem_mgr_map_cmd.num_hdl = 1; mem_mgr_map_cmd.flags = 1; mem_mgr_map_cmd.fd = s->buf.camera_bufs[i].fd; - ret = cam_control(s->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); // LOGD("map buf req: (fd: %d) 0x%x %d", s->bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret); s->buf_handle[i] = mem_mgr_map_cmd.out.buf_handle; @@ -544,10 +509,10 @@ void enqueue_req_multi(struct CameraState *s, int start, int n, bool dp) { // ******************* camera ******************* -static void camera_init(VisionIpcServer * v, CameraState *s, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) { +static void camera_init(MultiCameraState *multi_cam_state, VisionIpcServer * v, CameraState *s, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) { LOGD("camera init %d", camera_num); - - assert(camera_id < ARRAYSIZE(cameras_supported)); + s->multi_cam_state = multi_cam_state; + assert(camera_id < std::size(cameras_supported)); s->ci = cameras_supported[camera_id]; assert(s->ci.frame_width != 0); @@ -606,10 +571,10 @@ static void camera_open(CameraState *s) { // probe the sensor LOGD("-- Probing sensor %d", s->camera_num); - sensors_init(s->video0_fd, s->sensor_fd, s->camera_num); + sensors_init(s->multi_cam_state->video0_fd, s->sensor_fd, s->camera_num); memset(&s->req_mgr_session_info, 0, sizeof(s->req_mgr_session_info)); - ret = cam_control(s->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &s->req_mgr_session_info, sizeof(s->req_mgr_session_info)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &s->req_mgr_session_info, sizeof(s->req_mgr_session_info)); LOGD("get session: %d 0x%X", ret, s->req_mgr_session_info.session_hdl); s->session_handle = s->req_mgr_session_info.session_hdl; // access the sensor @@ -689,7 +654,7 @@ static void camera_open(CameraState *s) { .comp_grp_id = 0x0, .split_point = 0x0, .secure_mode = 0x0, }; - ret = cam_control(s->isp_fd, CAM_ACQUIRE_DEV, &acquire_dev_cmd, sizeof(acquire_dev_cmd)); + ret = cam_control(s->multi_cam_state->isp_fd, CAM_ACQUIRE_DEV, &acquire_dev_cmd, sizeof(acquire_dev_cmd)); LOGD("acquire isp dev: %d", ret); free(in_port_info); s->isp_dev_handle = acquire_dev_cmd.dev_handle; @@ -710,7 +675,7 @@ static void camera_open(CameraState *s) { // acquires done // config ISP - alloc_w_mmu_hdl(s->video0_fd, 984480, (uint32_t*)&s->buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, s->device_iommu, s->cdm_iommu); + alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, 984480, (uint32_t*)&s->buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, s->multi_cam_state->device_iommu, s->multi_cam_state->cdm_iommu); config_isp(s, 0, 0, 1, s->buf0_handle, 0); LOG("-- Configuring sensor"); @@ -726,7 +691,7 @@ static void camera_open(CameraState *s) { { uint32_t cam_packet_handle = 0; int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1; - struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->video0_fd, size, &cam_packet_handle); + struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle); pkt->num_cmd_buf = 1; pkt->kmd_cmd_buf_index = -1; pkt->header.size = size; @@ -735,7 +700,7 @@ static void camera_open(CameraState *s) { buf_desc[0].size = buf_desc[0].length = sizeof(struct cam_csiphy_info); buf_desc[0].type = CAM_CMD_BUF_GENERIC; - struct cam_csiphy_info *csiphy_info = (struct cam_csiphy_info *)alloc_w_mmu_hdl(s->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle); + struct cam_csiphy_info *csiphy_info = (struct cam_csiphy_info *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle); csiphy_info->lane_mask = 0x1f; csiphy_info->lane_assign = 0x3210;// skip clk. How is this 16 bit for 5 channels?? csiphy_info->csiphy_3phase = 0x0; // no 3 phase, only 2 conductors per lane @@ -754,8 +719,8 @@ static void camera_open(CameraState *s) { int ret = cam_control(s->csiphy_fd, CAM_CONFIG_DEV, &config_dev_cmd, sizeof(config_dev_cmd)); assert(ret == 0); - release(s->video0_fd, buf_desc[0].mem_handle); - release(s->video0_fd, cam_packet_handle); + release(s->multi_cam_state->video0_fd, buf_desc[0].mem_handle); + release(s->multi_cam_state->video0_fd, cam_packet_handle); } // link devices @@ -765,7 +730,7 @@ static void camera_open(CameraState *s) { req_mgr_link_info.num_devices = 2; req_mgr_link_info.dev_hdls[0] = s->isp_dev_handle; req_mgr_link_info.dev_hdls[1] = s->sensor_dev_handle; - ret = cam_control(s->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info)); LOGD("link: %d", ret); s->link_handle = req_mgr_link_info.link_hdl; @@ -774,13 +739,13 @@ static void camera_open(CameraState *s) { req_mgr_link_control.session_hdl = s->session_handle; req_mgr_link_control.num_links = 1; req_mgr_link_control.link_hdls[0] = s->link_handle; - ret = cam_control(s->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control)); LOGD("link control: %d", ret); LOGD("start csiphy: %d", ret); ret = device_control(s->csiphy_fd, CAM_START_DEV, s->session_handle, s->csiphy_dev_handle); LOGD("start isp: %d", ret); - ret = device_control(s->isp_fd, CAM_START_DEV, s->session_handle, s->isp_dev_handle); + ret = device_control(s->multi_cam_state->isp_fd, CAM_START_DEV, s->session_handle, s->isp_dev_handle); LOGD("start sensor: %d", ret); ret = device_control(s->sensor_fd, CAM_START_DEV, s->session_handle, s->sensor_dev_handle); @@ -788,13 +753,13 @@ static void camera_open(CameraState *s) { } void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { - camera_init(v, &s->road_cam, CAMERA_ID_AR0231, 1, 20, device_id, ctx, + camera_init(s, v, &s->road_cam, CAMERA_ID_AR0231, 1, 20, device_id, ctx, VISION_STREAM_RGB_BACK, VISION_STREAM_YUV_BACK); // swap left/right printf("road camera initted \n"); - camera_init(v, &s->wide_road_cam, CAMERA_ID_AR0231, 0, 20, device_id, ctx, + camera_init(s, v, &s->wide_road_cam, CAMERA_ID_AR0231, 0, 20, device_id, ctx, VISION_STREAM_RGB_WIDE, VISION_STREAM_YUV_WIDE); printf("wide road camera initted \n"); - camera_init(v, &s->driver_cam, CAMERA_ID_AR0231, 2, 20, device_id, ctx, + camera_init(s, v, &s->driver_cam, CAMERA_ID_AR0231, 2, 20, device_id, ctx, VISION_STREAM_RGB_FRONT, VISION_STREAM_YUV_FRONT); printf("driver camera initted \n"); @@ -810,19 +775,16 @@ void cameras_open(MultiCameraState *s) { s->video0_fd = open("/dev/v4l/by-path/platform-soc:qcom_cam-req-mgr-video-index0", O_RDWR | O_NONBLOCK); assert(s->video0_fd >= 0); LOGD("opened video0"); - s->road_cam.video0_fd = s->driver_cam.video0_fd = s->wide_road_cam.video0_fd = s->video0_fd; // video1 is cam_sync, the target of some ioctls s->video1_fd = open("/dev/v4l/by-path/platform-cam_sync-video-index0", O_RDWR | O_NONBLOCK); assert(s->video1_fd >= 0); LOGD("opened video1"); - s->road_cam.video1_fd = s->driver_cam.video1_fd = s->wide_road_cam.video1_fd = s->video1_fd; // looks like there's only one of these s->isp_fd = open("/dev/v4l-subdev1", O_RDWR | O_NONBLOCK); assert(s->isp_fd >= 0); LOGD("opened isp"); - s->road_cam.isp_fd = s->driver_cam.isp_fd = s->wide_road_cam.isp_fd = s->isp_fd; // query icp for MMU handles LOG("-- Query ICP for MMU handles"); @@ -835,10 +797,8 @@ void cameras_open(MultiCameraState *s) { assert(ret == 0); LOGD("using MMU handle: %x", isp_query_cap_cmd.device_iommu.non_secure); LOGD("using MMU handle: %x", isp_query_cap_cmd.cdm_iommu.non_secure); - int device_iommu = isp_query_cap_cmd.device_iommu.non_secure; - int cdm_iommu = isp_query_cap_cmd.cdm_iommu.non_secure; - s->road_cam.device_iommu = s->driver_cam.device_iommu = s->wide_road_cam.device_iommu = device_iommu; - s->road_cam.cdm_iommu = s->driver_cam.cdm_iommu = s->wide_road_cam.cdm_iommu = cdm_iommu; + s->device_iommu = isp_query_cap_cmd.device_iommu.non_secure; + s->cdm_iommu = isp_query_cap_cmd.cdm_iommu.non_secure; // subscribe LOG("-- Subscribing"); @@ -863,7 +823,7 @@ static void camera_close(CameraState *s) { LOG("-- Stop devices"); // ret = device_control(s->sensor_fd, CAM_STOP_DEV, s->session_handle, s->sensor_dev_handle); // LOGD("stop sensor: %d", ret); - ret = device_control(s->isp_fd, CAM_STOP_DEV, s->session_handle, s->isp_dev_handle); + ret = device_control(s->multi_cam_state->isp_fd, CAM_STOP_DEV, s->session_handle, s->isp_dev_handle); LOGD("stop isp: %d", ret); ret = device_control(s->csiphy_fd, CAM_STOP_DEV, s->session_handle, s->csiphy_dev_handle); LOGD("stop csiphy: %d", ret); @@ -874,7 +834,7 @@ static void camera_close(CameraState *s) { req_mgr_link_control.session_hdl = s->session_handle; req_mgr_link_control.num_links = 1; req_mgr_link_control.link_hdls[0] = s->link_handle; - ret = cam_control(s->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control)); LOGD("link control stop: %d", ret); // unlink @@ -882,19 +842,19 @@ static void camera_close(CameraState *s) { static struct cam_req_mgr_unlink_info req_mgr_unlink_info = {0}; req_mgr_unlink_info.session_hdl = s->session_handle; req_mgr_unlink_info.link_hdl = s->link_handle; - ret = cam_control(s->video0_fd, CAM_REQ_MGR_UNLINK, &req_mgr_unlink_info, sizeof(req_mgr_unlink_info)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_UNLINK, &req_mgr_unlink_info, sizeof(req_mgr_unlink_info)); LOGD("unlink: %d", ret); // release devices LOGD("-- Release devices"); ret = device_control(s->sensor_fd, CAM_RELEASE_DEV, s->session_handle, s->sensor_dev_handle); LOGD("release sensor: %d", ret); - ret = device_control(s->isp_fd, CAM_RELEASE_DEV, s->session_handle, s->isp_dev_handle); + ret = device_control(s->multi_cam_state->isp_fd, CAM_RELEASE_DEV, s->session_handle, s->isp_dev_handle); LOGD("release isp: %d", ret); ret = device_control(s->csiphy_fd, CAM_RELEASE_DEV, s->session_handle, s->csiphy_dev_handle); LOGD("release csiphy: %d", ret); - ret = cam_control(s->video0_fd, CAM_REQ_MGR_DESTROY_SESSION, &s->req_mgr_session_info, sizeof(s->req_mgr_session_info)); + ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_DESTROY_SESSION, &s->req_mgr_session_info, sizeof(s->req_mgr_session_info)); LOGD("destroyed session: %d", ret); } @@ -923,7 +883,7 @@ void handle_camera_event(CameraState *s, void *evdat) { // check for skipped frames if (main_id > s->frame_id_last + 1 && !s->skipped) { // realign - clear_req_queue(s->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl); + clear_req_queue(s->multi_cam_state->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl); enqueue_req_multi(s, real_id + 1, FRAME_BUF_COUNT - 1, 0); s->skipped = true; } else if (main_id == s->frame_id_last + 1) { @@ -953,7 +913,7 @@ void handle_camera_event(CameraState *s, void *evdat) { } else { // not ready // reset after half second of no response if (main_id > s->frame_id_last + 10) { - clear_req_queue(s->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl); + clear_req_queue(s->multi_cam_state->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl); enqueue_req_multi(s, s->request_id_last + 1, FRAME_BUF_COUNT, 0); s->frame_id_last = main_id; s->skipped = true; @@ -1141,7 +1101,7 @@ void cameras_run(MultiCameraState *s) { fds[0].fd = s->video0_fd; fds[0].events = POLLPRI; - int ret = poll(fds, ARRAYSIZE(fds), 1000); + int ret = poll(fds, std::size(fds), 1000); if (ret < 0) { if (errno == EINTR || errno == EAGAIN) continue; LOGE("poll failed (%d - %d)", ret, errno); diff --git a/selfdrive/camerad/cameras/camera_qcom2.h b/selfdrive/camerad/cameras/camera_qcom2.h index ada2744e1..ac37f557a 100644 --- a/selfdrive/camerad/cameras/camera_qcom2.h +++ b/selfdrive/camerad/cameras/camera_qcom2.h @@ -4,8 +4,10 @@ #include #include -#include "camera_common.h" -#include "media/cam_req_mgr.h" +#include + +#include "selfdrive/camerad/cameras/camera_common.h" +#include "selfdrive/common/util.h" #define FRAME_BUF_COUNT 4 @@ -18,8 +20,9 @@ #define DEBAYER_LOCAL_WORKSIZE 16 typedef struct CameraState { + MultiCameraState *multi_cam_state; CameraInfo ci; - + std::mutex exp_lock; float analog_gain_frac; uint16_t analog_gain; @@ -29,19 +32,11 @@ typedef struct CameraState { int exposure_time_max; float ef_filtered; - int device_iommu; - int cdm_iommu; - - int video0_fd; - int video1_fd; - int isp_fd; - - int sensor_fd; - int csiphy_fd; + unique_fd sensor_fd; + unique_fd csiphy_fd; int camera_num; - uint32_t session_handle; uint32_t sensor_dev_handle; @@ -67,9 +62,12 @@ typedef struct CameraState { typedef struct MultiCameraState { int device; - int video0_fd; - int video1_fd; - int isp_fd; + unique_fd video0_fd; + unique_fd video1_fd; + unique_fd isp_fd; + int device_iommu; + int cdm_iommu; + CameraState road_cam; CameraState wide_road_cam; diff --git a/selfdrive/camerad/imgproc/utils.cc b/selfdrive/camerad/imgproc/utils.cc index 7dd0ab97a..5c2110131 100644 --- a/selfdrive/camerad/imgproc/utils.cc +++ b/selfdrive/camerad/imgproc/utils.cc @@ -1,7 +1,9 @@ -#include "utils.h" +#include "selfdrive/camerad/imgproc/utils.h" + #include #include #include + #include #include diff --git a/selfdrive/camerad/imgproc/utils.h b/selfdrive/camerad/imgproc/utils.h index e33cfe9c8..d7d518c0f 100644 --- a/selfdrive/camerad/imgproc/utils.h +++ b/selfdrive/camerad/imgproc/utils.h @@ -1,9 +1,11 @@ #pragma once -#include #include +#include + #include -#include "clutil.h" + +#include "selfdrive/common/clutil.h" #define NUM_SEGMENTS_X 8 #define NUM_SEGMENTS_Y 6 diff --git a/selfdrive/camerad/main.cc b/selfdrive/camerad/main.cc index 0c6d54d92..6cfa85bdb 100644 --- a/selfdrive/camerad/main.cc +++ b/selfdrive/camerad/main.cc @@ -1,28 +1,30 @@ -#include -#include -#include #include -#include +#include +#include #include +#include + +#include + +#include "libyuv.h" + +#include "cereal/visionipc/visionipc_server.h" +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" #if defined(QCOM) && !defined(QCOM_REPLAY) -#include "cameras/camera_qcom.h" +#include "selfdrive/camerad/cameras/camera_qcom.h" #elif QCOM2 -#include "cameras/camera_qcom2.h" +#include "selfdrive/camerad/cameras/camera_qcom2.h" #elif WEBCAM -#include "cameras/camera_webcam.h" +#include "selfdrive/camerad/cameras/camera_webcam.h" #else -#include "cameras/camera_frame_stream.h" +#include "selfdrive/camerad/cameras/camera_frame_stream.h" #endif -#include - -#include "clutil.h" -#include "common/params.h" -#include "common/swaglog.h" -#include "common/util.h" -#include "visionipc_server.h" - ExitHandler do_exit; void party(cl_device_id device_id, cl_context context) { @@ -43,11 +45,11 @@ void party(cl_device_id device_id, cl_context context) { int main(int argc, char *argv[]) { set_realtime_priority(53); -#if defined(QCOM) - set_core_affinity(2); -#elif defined(QCOM2) - set_core_affinity(6); -#endif + if (Hardware::EON()) { + set_core_affinity(2); + } else if (Hardware::TICI()) { + set_core_affinity(6); + } cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); diff --git a/selfdrive/camerad/snapshot/snapshot.py b/selfdrive/camerad/snapshot/snapshot.py index 60883608f..eb7bb93af 100755 --- a/selfdrive/camerad/snapshot/snapshot.py +++ b/selfdrive/camerad/snapshot/snapshot.py @@ -33,24 +33,30 @@ def get_snapshots(frame="roadCameraState", front_frame="driverCameraState"): frame_sizes = [eon_f_frame_size, eon_d_frame_size, leon_d_frame_size, tici_f_frame_size] frame_sizes = {w * h: (w, h) for (w, h) in frame_sizes} - sm = messaging.SubMaster([frame, front_frame]) + sockets = [] + if frame is not None: + sockets.append(frame) + if front_frame is not None: + sockets.append(front_frame) + + sm = messaging.SubMaster(sockets) while min(sm.logMonoTime.values()) == 0: sm.update() - rear = extract_image(sm[frame].image, frame_sizes) - front = extract_image(sm[front_frame].image, frame_sizes) + rear = extract_image(sm[frame].image, frame_sizes) if frame is not None else None + front = extract_image(sm[front_frame].image, frame_sizes) if front_frame is not None else None return rear, front def snapshot(): params = Params() - front_camera_allowed = int(params.get("RecordFront")) + front_camera_allowed = params.get_bool("RecordFront") - if params.get("IsOffroad") != b"1" or params.get("IsTakingSnapshot") == b"1": + if (not params.get_bool("IsOffroad")) or params.get_bool("IsTakingSnapshot"): print("Already taking snapshot") return None, None - params.put("IsTakingSnapshot", "1") + params.put_bool("IsTakingSnapshot", True) set_offroad_alert("Offroad_IsTakingSnapshot", True) time.sleep(2.0) # Give thermald time to read the param, or if just started give camerad time to start @@ -59,7 +65,7 @@ def snapshot(): subprocess.check_call(["pgrep", "camerad"]) print("Camerad already running") - params.put("IsTakingSnapshot", "0") + params.put_bool("IsTakingSnapshot", False) params.delete("Offroad_IsTakingSnapshot") return None, None except subprocess.CalledProcessError: @@ -68,18 +74,22 @@ def snapshot(): env = os.environ.copy() env["SEND_ROAD"] = "1" env["SEND_WIDE_ROAD"] = "1" - env["SEND_DRIVER"] = "1" + + if front_camera_allowed: + env["SEND_DRIVER"] = "1" + proc = subprocess.Popen(os.path.join(BASEDIR, "selfdrive/camerad/camerad"), cwd=os.path.join(BASEDIR, "selfdrive/camerad"), env=env) time.sleep(3.0) frame = "wideRoadCameraState" if TICI else "roadCameraState" - rear, front = get_snapshots(frame) + front_frame = "driverCameraState" if front_camera_allowed else None + rear, front = get_snapshots(frame, front_frame) proc.send_signal(signal.SIGINT) proc.communicate() - params.put("IsTakingSnapshot", "0") + params.put_bool("IsTakingSnapshot", False) set_offroad_alert("Offroad_IsTakingSnapshot", False) if not front_camera_allowed: diff --git a/selfdrive/camerad/transforms/rgb_to_yuv.cc b/selfdrive/camerad/transforms/rgb_to_yuv.cc index c0ac19207..1fdeb593d 100644 --- a/selfdrive/camerad/transforms/rgb_to_yuv.cc +++ b/selfdrive/camerad/transforms/rgb_to_yuv.cc @@ -1,17 +1,9 @@ -#include -#include - -#include "clutil.h" - #include "rgb_to_yuv.h" -void rgb_to_yuv_init(RGBToYUVState* s, cl_context ctx, cl_device_id device_id, int width, int height, int rgb_stride) { - memset(s, 0, sizeof(*s)); - printf("width %d, height %d, rgb_stride %d\n", width, height, rgb_stride); - assert(width % 2 == 0); - assert(height % 2 == 0); - s->width = width; - s->height = height; +#include + +Rgb2Yuv::Rgb2Yuv(cl_context ctx, cl_device_id device_id, int width, int height, int rgb_stride) { + assert(width % 2 == 0 && height % 2 == 0); char args[1024]; snprintf(args, sizeof(args), "-cl-fast-relaxed-math -cl-denorms-are-zero " @@ -19,27 +11,25 @@ void rgb_to_yuv_init(RGBToYUVState* s, cl_context ctx, cl_device_id device_id, i "-DCL_DEBUG " #endif "-DWIDTH=%d -DHEIGHT=%d -DUV_WIDTH=%d -DUV_HEIGHT=%d -DRGB_STRIDE=%d -DRGB_SIZE=%d", - width, height, width/ 2, height / 2, rgb_stride, width * height); + width, height, width / 2, height / 2, rgb_stride, width * height); + cl_program prg = cl_program_from_file(ctx, device_id, "transforms/rgb_to_yuv.cl", args); - - s->rgb_to_yuv_krnl = CL_CHECK_ERR(clCreateKernel(prg, "rgb_to_yuv", &err)); - // done with this + krnl = CL_CHECK_ERR(clCreateKernel(prg, "rgb_to_yuv", &err)); CL_CHECK(clReleaseProgram(prg)); + + work_size[0] = (width + (width % 4 == 0 ? 0 : (4 - width % 4))) / 4; + work_size[1] = (height + (height % 4 == 0 ? 0 : (4 - height % 4))) / 4; } -void rgb_to_yuv_destroy(RGBToYUVState* s) { - CL_CHECK(clReleaseKernel(s->rgb_to_yuv_krnl)); +Rgb2Yuv::~Rgb2Yuv() { + CL_CHECK(clReleaseKernel(krnl)); } -void rgb_to_yuv_queue(RGBToYUVState* s, cl_command_queue q, cl_mem rgb_cl, cl_mem yuv_cl) { - CL_CHECK(clSetKernelArg(s->rgb_to_yuv_krnl, 0, sizeof(cl_mem), &rgb_cl)); - CL_CHECK(clSetKernelArg(s->rgb_to_yuv_krnl, 1, sizeof(cl_mem), &yuv_cl)); - const size_t work_size[2] = { - (size_t)(s->width + (s->width % 4 == 0 ? 0 : (4 - s->width % 4))) / 4, - (size_t)(s->height + (s->height % 4 == 0 ? 0 : (4 - s->height % 4))) / 4 - }; +void Rgb2Yuv::queue(cl_command_queue q, cl_mem rgb_cl, cl_mem yuv_cl) { + CL_CHECK(clSetKernelArg(krnl, 0, sizeof(cl_mem), &rgb_cl)); + CL_CHECK(clSetKernelArg(krnl, 1, sizeof(cl_mem), &yuv_cl)); cl_event event; - CL_CHECK(clEnqueueNDRangeKernel(q, s->rgb_to_yuv_krnl, 2, NULL, &work_size[0], NULL, 0, 0, &event)); + CL_CHECK(clEnqueueNDRangeKernel(q, krnl, 2, NULL, &work_size[0], NULL, 0, 0, &event)); CL_CHECK(clWaitForEvents(1, &event)); CL_CHECK(clReleaseEvent(event)); } diff --git a/selfdrive/camerad/transforms/rgb_to_yuv.h b/selfdrive/camerad/transforms/rgb_to_yuv.h index 05d5c5ece..3bb50669e 100644 --- a/selfdrive/camerad/transforms/rgb_to_yuv.h +++ b/selfdrive/camerad/transforms/rgb_to_yuv.h @@ -1,21 +1,14 @@ #pragma once -#include -#include +#include "selfdrive/common/clutil.h" -#ifdef __APPLE__ -#include -#else -#include -#endif +class Rgb2Yuv { +public: + Rgb2Yuv(cl_context ctx, cl_device_id device_id, int width, int height, int rgb_stride); + ~Rgb2Yuv(); + void queue(cl_command_queue q, cl_mem rgb_cl, cl_mem yuv_cl); +private: + size_t work_size[2]; + cl_kernel krnl; +}; -typedef struct { - int width, height; - cl_kernel rgb_to_yuv_krnl; -} RGBToYUVState; - -void rgb_to_yuv_init(RGBToYUVState* s, cl_context ctx, cl_device_id device_id, int width, int height, int rgb_stride); - -void rgb_to_yuv_destroy(RGBToYUVState* s); - -void rgb_to_yuv_queue(RGBToYUVState* s, cl_command_queue q, cl_mem rgb_cl, cl_mem yuv_cl); diff --git a/selfdrive/camerad/transforms/rgb_to_yuv_test.cc b/selfdrive/camerad/transforms/rgb_to_yuv_test.cc index a2fd4035b..04b6afd09 100644 --- a/selfdrive/camerad/transforms/rgb_to_yuv_test.cc +++ b/selfdrive/camerad/transforms/rgb_to_yuv_test.cc @@ -1,18 +1,19 @@ -#include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include + #include #include +#include +#include +#include +#include +#include +#include +#include #ifdef ANDROID @@ -26,13 +27,11 @@ #endif -#include - #include -#include "clutil.h" -#include "rgb_to_yuv.h" - +#include "libyuv.h" +#include "selfdrive/camerad/transforms/rgb_to_yuv.h" +#include "selfdrive/common/clutil.h" static inline double millis_since_boot() { struct timespec t; diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 7701f90a6..9cd13a58d 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -119,17 +119,5 @@ def create_gas_command(packer, gas_amount, idx): return packer.make_can_msg("GAS_COMMAND", 0, values) -def is_ecu_disconnected(fingerprint, fingerprint_list, ecu_fingerprint, car, ecu): - # check if a stock ecu is disconnected by looking for specific CAN msgs in the fingerprint - # return True if the reference car fingerprint contains the ecu fingerprint msg and - # fingerprint does not contains messages normally sent by a given ecu - ecu_in_car = False - for car_finger in fingerprint_list[car]: - if any(msg in car_finger for msg in ecu_fingerprint[ecu]): - ecu_in_car = True - - return ecu_in_car and not any(msg in fingerprint for msg in ecu_fingerprint[ecu]) - - def make_can_msg(addr, dat, bus): return [addr, 0, dat, bus] diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 2af6df269..9f3ebfa08 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -13,7 +13,7 @@ from cereal import car EventName = car.CarEvent.EventName -def get_startup_event(car_recognized, controller_available): +def get_startup_event(car_recognized, controller_available, fuzzy_fingerprint): if comma_remote and tested_branch: event = EventName.startup else: @@ -23,6 +23,8 @@ def get_startup_event(car_recognized, controller_available): event = EventName.startupNoCar elif car_recognized and not controller_available: event = EventName.startupNoControl + elif car_recognized and fuzzy_fingerprint: + event = EventName.startupFuzzyFingerprint return event @@ -104,10 +106,10 @@ def fingerprint(logcan, sendcan): _, vin = get_vin(logcan, sendcan, bus) car_fw = get_fw_versions(logcan, sendcan, bus) - fw_candidates = match_fw_to_car(car_fw) + exact_fw_match, fw_candidates = match_fw_to_car(car_fw) else: vin = VIN_UNKNOWN - fw_candidates, car_fw = set(), [] + exact_fw_match, fw_candidates, car_fw = True, set(), [] cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) @@ -146,29 +148,31 @@ def fingerprint(logcan, sendcan): car_fingerprint = candidate_cars[b][0] # bail if no cars left or we've been waiting for more than 2s - failed = all(len(cc) == 0 for cc in candidate_cars.values()) or frame > 200 + failed = (all(len(cc) == 0 for cc in candidate_cars.values()) and frame > frame_fingerprint) or frame > 200 succeeded = car_fingerprint is not None done = failed or succeeded frame += 1 + exact_match = True source = car.CarParams.FingerprintSource.can # If FW query returns exactly 1 candidate, use it if len(fw_candidates) == 1: car_fingerprint = list(fw_candidates)[0] source = car.CarParams.FingerprintSource.fw + exact_match = exact_fw_match if fixed_fingerprint: car_fingerprint = fixed_fingerprint source = car.CarParams.FingerprintSource.fixed cloudlog.warning("fingerprinted %s", car_fingerprint) - return car_fingerprint, finger, vin, car_fw, source + return car_fingerprint, finger, vin, car_fw, source, exact_match def get_car(logcan, sendcan): - candidate, fingerprints, vin, car_fw, source = fingerprint(logcan, sendcan) + candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan) if candidate is None: cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints) @@ -179,5 +183,6 @@ def get_car(logcan, sendcan): car_params.carVin = vin car_params.carFw = car_fw car_params.fingerprintSource = source + car_params.fuzzyFingerprint = not exact_match return CarInterface(car_params, CarController, CarState), car_params diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index 2d3c1a2ec..e7f8ee65b 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -59,6 +59,10 @@ class CarState(CarStateBase): ret.steerError = steer_state == 4 or (steer_state == 0 and ret.vEgo > self.CP.minSteerSpeed) ret.genericToggle = bool(cp.vl["STEERING_LEVERS"]['HIGH_BEAM_FLASH']) + + if self.CP.enableBsm: + ret.leftBlindspot = cp.vl["BLIND_SPOT_WARNINGS"]['BLIND_SPOT_LEFT'] == 1 + ret.rightBlindspot = cp.vl["BLIND_SPOT_WARNINGS"]['BLIND_SPOT_RIGHT'] == 1 self.lkas_counter = cp_cam.vl["LKAS_COMMAND"]['COUNTER'] self.lkas_car_model = cp_cam.vl["LKAS_HUD"]['CAR_MODEL'] @@ -115,6 +119,13 @@ class CarState(CarStateBase): ("TRACTION_BUTTON", 1), ] + if CP.enableBsm: + signals += [ + ("BLIND_SPOT_RIGHT", "BLIND_SPOT_WARNINGS", 0), + ("BLIND_SPOT_LEFT", "BLIND_SPOT_WARNINGS", 0), + ] + checks += [("BLIND_SPOT_WARNINGS", 2)] + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) @staticmethod diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index ccf3bc9fe..f37ae953a 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase): # Speed conversion: 20, 45 mph ret.wheelbase = 3.089 # in meters for Pacifica Hybrid 2017 ret.steerRatio = 16.2 # Pacifica Hybrid 2017 - ret.mass = 2858. + STD_CARGO_KG # kg curb weight Pacifica Hybrid 2017 + ret.mass = 2242. + STD_CARGO_KG # kg curb weight Pacifica Hybrid 2017 ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] ret.lateralTuning.pid.kf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594 @@ -50,6 +50,8 @@ class CarInterface(CarInterfaceBase): ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) ret.enableCamera = True + + ret.enableBsm = 720 in fingerprint[0] return ret diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 17e636a04..2ded7b685 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -59,12 +59,9 @@ FINGERPRINTS = { { 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1562: 8, 1570: 8 }, - { - 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 650: 8, 653: 8, 654: 8, 655: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 683: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 2015: 8, 2016: 8, 2024: 8 - }, # Based on "8190c7275a24557b|2020-02-24--09-57-23" { - 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 650: 8, 656: 4, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 683: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 711: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 793: 8, 794: 8, 795: 8, 796: 8, 797: 8, 798: 8, 799: 8, 800: 8, 801: 8, 802: 8, 803: 8, 804: 8, 805: 8, 807: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 886: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1258: 8, 1259: 8, 1260: 8, 1262: 8, 1284: 8, 1568: 8, 1570: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 1898: 8, 1899: 8, 1900: 8, 1902: 8, 2015: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2023: 8, 2024: 8, 2026: 8, 2027: 8, 2028: 8, 2031: 8 + 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 650: 8, 653: 8, 654: 8, 655: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 683: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 711: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 793: 8, 794: 8, 795: 8, 796: 8, 797: 8, 798: 8, 799: 8, 800: 8, 801: 8, 802: 8, 803: 8, 804: 8, 805: 8, 807: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 886: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1258: 8, 1259: 8, 1260: 8, 1262: 8, 1284: 8, 1568: 8, 1570: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 1898: 8, 1899: 8, 1900: 8, 1902: 8, 2015: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2023: 8, 2024: 8, 2026: 8, 2027: 8, 2028: 8, 2031: 8 } ], CAR.JEEP_CHEROKEE: [ diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 2a776b45d..756c4b876 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -53,4 +53,4 @@ class CarState(CarStateBase): ("Brake_Lights", "BCM_to_HS_Body", 0.), ] checks = [] - return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, enforce_checks=False) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 9def1ca86..aec368cd0 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -61,7 +61,7 @@ class CarInterface(CarInterfaceBase): events = self.create_common_events(ret) if self.CS.lkas_state not in [2, 3] and ret.vEgo > 13. * CV.MPH_TO_MS and ret.cruiseState.enabled: - events.add(car.CarEvent.EventName.steerTempUnavailableMute) + events.add(car.CarEvent.EventName.steerTempUnavailable) ret.events = events.to_msg() diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 468b17ba8..0e3e03822 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -2,6 +2,7 @@ import struct import traceback from typing import Any +from collections import defaultdict from tqdm import tqdm @@ -136,30 +137,82 @@ def chunks(l, n=128): yield l[i:i + n] -def match_fw_to_car(fw_versions): - candidates = FW_VERSIONS - invalid = [] - +def build_fw_dict(fw_versions): fw_versions_dict = {} for fw in fw_versions: addr = fw.address sub_addr = fw.subAddress if fw.subAddress != 0 else None fw_versions_dict[(addr, sub_addr)] = fw.fwVersion + return fw_versions_dict + + +def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): + """Do a fuzzy FW match. This function will return a match, and the number of firmware version + that were matched uniquely to that specific car. If multiple ECUs uniquely match to different cars + the match is rejected.""" + + # These ECUs are known to be shared between models (EPS only between hybrid/ICE version) + # Getting this exactly right isn't crucial, but excluding camera and radar makes it almost + # impossible to get 3 matching versions, even if two models with shared parts are released at the same + # time and only one is in our database. + exclude_types = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps] + + # Build lookup table from (addr, subaddr, fw) to list of candidate cars + all_fw_versions = defaultdict(list) + for candidate, fw_by_addr in FW_VERSIONS.items(): + if candidate == exclude: + continue + + for addr, fws in fw_by_addr.items(): + if addr[0] in exclude_types: + continue + for f in fws: + all_fw_versions[(addr[1], addr[2], f)].append(candidate) + + match_count = 0 + candidate = None + for addr, version in fw_versions_dict.items(): + # All cars that have this FW response on the specified address + candidates = all_fw_versions[(addr[0], addr[1], version)] + + if len(candidates) == 1: + match_count += 1 + if candidate is None: + candidate = candidates[0] + # We uniquely matched two different cars. No fuzzy match possible + elif candidate != candidates[0]: + return set() + + if match_count >= 2: + if log: + cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {match_count} matching ECUs") + return set([candidate]) + else: + return set() + + +def match_fw_to_car_exact(fw_versions_dict): + """Do an exact FW match. Returns all cars that match the given + FW versions for a list of "essential" ECUs. If an ECU is not considered + essential the FW version can be missing to get a fingerprint, but if it's present it + needs to match the database.""" + invalid = [] + candidates = FW_VERSIONS for candidate, fws in candidates.items(): for ecu, expected_versions in fws.items(): ecu_type = ecu[0] addr = ecu[1:] found_version = fw_versions_dict.get(addr, None) - ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.esp, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa, Ecu.electricBrakeBooster] + ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.esp, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa] if ecu_type == Ecu.esp and candidate in [TOYOTA.RAV4, TOYOTA.COROLLA, TOYOTA.HIGHLANDER] and found_version is None: continue - # TODO: on some toyota, the engine can show on two different addresses + # On some Toyota models, the engine can show on two different addresses if ecu_type == Ecu.engine and candidate in [TOYOTA.COROLLA_TSS2, TOYOTA.CHR, TOYOTA.LEXUS_IS, TOYOTA.AVALON] and found_version is None: continue - # ignore non essential ecus + # Ignore non essential ecus if ecu_type not in ESSENTIAL_ECUS and found_version is None: continue @@ -170,6 +223,21 @@ def match_fw_to_car(fw_versions): return set(candidates.keys()) - set(invalid) +def match_fw_to_car(fw_versions, allow_fuzzy=True): + fw_versions_dict = build_fw_dict(fw_versions) + matches = match_fw_to_car_exact(fw_versions_dict) + + exact_match = True + if allow_fuzzy and len(matches) == 0: + matches = match_fw_to_car_fuzzy(fw_versions_dict) + + # Fuzzy match found + if len(matches) == 1: + exact_match = False + + return exact_match, matches + + def get_fw_versions(logcan, sendcan, bus, extra=None, timeout=0.1, debug=False, progress=False): ecu_types = {} @@ -264,7 +332,7 @@ if __name__ == "__main__": t = time.time() fw_vers = get_fw_versions(logcan, sendcan, 1, extra=extra, debug=args.debug, progress=True) - candidates = match_fw_to_car(fw_vers) + _, candidates = match_fw_to_car(fw_vers) print() print("Found FW versions") diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index a59740c6f..954b3ec74 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -104,9 +104,29 @@ class CarState(CarStateBase): ("CruiseMainOn", "ECMEngineStatus", 0), ] + checks = [ + ("BCMTurnSignals", 1), + ("ECMPRDNL", 10), + ("PSCMStatus", 10), + ("ESPStatus", 10), + ("BCMDoorBeltStatus", 10), + ("EPBStatus", 20), + ("EBCMWheelSpdFront", 20), + ("EBCMWheelSpdRear", 20), + ("AcceleratorPedal", 33), + ("AcceleratorPedal2", 33), + ("ASCMSteeringButton", 33), + ("ECMEngineStatus", 100), + ("PSCMSteeringAngle", 100), + ("EBCMBrakePedalPosition", 100), + ] + if CP.carFingerprint == CAR.VOLT: signals += [ ("RegenPaddle", "EBCMRegenPaddle", 0), ] + checks += [ + ("EBCMRegenPaddle", 50), + ] - return CANParser(DBC[CP.carFingerprint]['pt'], signals, [], CanBus.POWERTRAIN) + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, CanBus.POWERTRAIN) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 2f7d8f473..7c28406cb 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -156,7 +156,7 @@ class CarInterface(CarInterfaceBase): if ret.cruiseState.standstill: events.add(EventName.resumeRequired) if self.CS.pcm_acc_status == AccState.FAULTED: - events.add(EventName.controlsFailed) + events.add(EventName.accFaulted) if ret.vEgo < self.CP.minSteerSpeed: events.add(car.CarEvent.EventName.belowSteerSpeed) diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py index dc2c2f7b7..7e475c568 100755 --- a/selfdrive/car/gm/radar_interface.py +++ b/selfdrive/car/gm/radar_interface.py @@ -34,7 +34,7 @@ def create_radar_can_parser(car_fingerprint): [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS + [0] * NUM_SLOTS)) - checks = [] + checks = list({(s[1], 14) for s in signals}) return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CanBus.OBSTACLE) diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 410d34a73..0de09f5fc 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -22,41 +22,43 @@ def calc_cruise_offset(offset, speed): def get_can_signals(CP): # this function generates lists for signal, messages and initial values signals = [ - ("XMISSION_SPEED", "ENGINE_DATA", 0), - ("WHEEL_SPEED_FL", "WHEEL_SPEEDS", 0), - ("WHEEL_SPEED_FR", "WHEEL_SPEEDS", 0), - ("WHEEL_SPEED_RL", "WHEEL_SPEEDS", 0), - ("WHEEL_SPEED_RR", "WHEEL_SPEEDS", 0), - ("STEER_ANGLE", "STEERING_SENSORS", 0), - ("STEER_ANGLE_RATE", "STEERING_SENSORS", 0), - ("MOTOR_TORQUE", "STEER_MOTOR_TORQUE", 0), - ("STEER_TORQUE_SENSOR", "STEER_STATUS", 0), - ("LEFT_BLINKER", "SCM_FEEDBACK", 0), - ("RIGHT_BLINKER", "SCM_FEEDBACK", 0), - ("GEAR", "GEARBOX", 0), - ("SEATBELT_DRIVER_LAMP", "SEATBELT_STATUS", 1), - ("SEATBELT_DRIVER_LATCHED", "SEATBELT_STATUS", 0), - ("BRAKE_PRESSED", "POWERTRAIN_DATA", 0), - ("BRAKE_SWITCH", "POWERTRAIN_DATA", 0), - ("CRUISE_BUTTONS", "SCM_BUTTONS", 0), - ("ESP_DISABLED", "VSA_STATUS", 1), - ("USER_BRAKE", "VSA_STATUS", 0), - ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0), - ("STEER_STATUS", "STEER_STATUS", 5), - ("GEAR_SHIFTER", "GEARBOX", 0), - ("PEDAL_GAS", "POWERTRAIN_DATA", 0), - ("CRUISE_SETTING", "SCM_BUTTONS", 0), - ("ACC_STATUS", "POWERTRAIN_DATA", 0), + ("XMISSION_SPEED", "ENGINE_DATA", 0), + ("WHEEL_SPEED_FL", "WHEEL_SPEEDS", 0), + ("WHEEL_SPEED_FR", "WHEEL_SPEEDS", 0), + ("WHEEL_SPEED_RL", "WHEEL_SPEEDS", 0), + ("WHEEL_SPEED_RR", "WHEEL_SPEEDS", 0), + ("STEER_ANGLE", "STEERING_SENSORS", 0), + ("STEER_ANGLE_RATE", "STEERING_SENSORS", 0), + ("MOTOR_TORQUE", "STEER_MOTOR_TORQUE", 0), + ("STEER_TORQUE_SENSOR", "STEER_STATUS", 0), + ("LEFT_BLINKER", "SCM_FEEDBACK", 0), + ("RIGHT_BLINKER", "SCM_FEEDBACK", 0), + ("GEAR", "GEARBOX", 0), + ("SEATBELT_DRIVER_LAMP", "SEATBELT_STATUS", 1), + ("SEATBELT_DRIVER_LATCHED", "SEATBELT_STATUS", 0), + ("BRAKE_PRESSED", "POWERTRAIN_DATA", 0), + ("BRAKE_SWITCH", "POWERTRAIN_DATA", 0), + ("CRUISE_BUTTONS", "SCM_BUTTONS", 0), + ("ESP_DISABLED", "VSA_STATUS", 1), + ("USER_BRAKE", "VSA_STATUS", 0), + ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0), + ("STEER_STATUS", "STEER_STATUS", 5), + ("GEAR_SHIFTER", "GEARBOX", 0), + ("PEDAL_GAS", "POWERTRAIN_DATA", 0), + ("CRUISE_SETTING", "SCM_BUTTONS", 0), + ("ACC_STATUS", "POWERTRAIN_DATA", 0), ] checks = [ - ("ENGINE_DATA", 100), - ("WHEEL_SPEEDS", 50), - ("STEERING_SENSORS", 100), - ("SEATBELT_STATUS", 10), - ("CRUISE", 10), - ("POWERTRAIN_DATA", 100), - ("VSA_STATUS", 50), + ("ENGINE_DATA", 100), + ("WHEEL_SPEEDS", 50), + ("STEERING_SENSORS", 100), + ("SEATBELT_STATUS", 10), + ("CRUISE", 10), + ("POWERTRAIN_DATA", 100), + ("VSA_STATUS", 50), + ("STEER_STATUS", 100), + ("STEER_MOTOR_TORQUE", 0), # TODO: not on every car ] if CP.carFingerprint == CAR.ODYSSEY_CHN: @@ -84,12 +86,22 @@ def get_can_signals(CP): if CP.carFingerprint not in (CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT): signals += [("BRAKE_PRESSED", "BRAKE_MODULE", 0)] checks += [("BRAKE_MODULE", 50)] - signals += [("CAR_GAS", "GAS_PEDAL_2", 0), - ("MAIN_ON", "SCM_FEEDBACK", 0), - ("CRUISE_CONTROL_LABEL", "ACC_HUD", 0), - ("EPB_STATE", "EPB_STATUS", 0), - ("CRUISE_SPEED", "ACC_HUD", 0)] - checks += [("GAS_PEDAL_2", 100)] + + signals += [ + ("CAR_GAS", "GAS_PEDAL_2", 0), + ("MAIN_ON", "SCM_FEEDBACK", 0), + ("CRUISE_CONTROL_LABEL", "ACC_HUD", 0), + ("EPB_STATE", "EPB_STATUS", 0), + ("CRUISE_SPEED", "ACC_HUD", 0), + ("ACCEL_COMMAND", "ACC_CONTROL", 0), + ("AEB_STATUS", "ACC_CONTROL", 0), + ] + checks += [ + ("ACC_HUD", 10), + ("EPB_STATUS", 50), + ("GAS_PEDAL_2", 100), + ("ACC_CONTROL", 50), + ] if CP.openpilotLongitudinalControl: signals += [("BRAKE_ERROR_1", "STANDSTILL", 1), ("BRAKE_ERROR_2", "STANDSTILL", 1)] @@ -119,27 +131,43 @@ def get_can_signals(CP): ("DOOR_OPEN_RL", "DOORS_STATUS", 1), ("DOOR_OPEN_RR", "DOORS_STATUS", 1), ("WHEELS_MOVING", "STANDSTILL", 1)] - checks += [("DOORS_STATUS", 3)] + checks += [ + ("DOORS_STATUS", 3), + ("STANDSTILL", 50), + ] if CP.carFingerprint == CAR.CIVIC: signals += [("CAR_GAS", "GAS_PEDAL_2", 0), ("MAIN_ON", "SCM_FEEDBACK", 0), ("IMPERIAL_UNIT", "HUD_SETTING", 0), ("EPB_STATE", "EPB_STATUS", 0)] + checks += [ + ("HUD_SETTING", 50), + ("EPB_STATUS", 50), + ("GAS_PEDAL_2", 100), + ] elif CP.carFingerprint == CAR.ACURA_ILX: signals += [("CAR_GAS", "GAS_PEDAL_2", 0), ("MAIN_ON", "SCM_BUTTONS", 0)] + checks += [ + ("GAS_PEDAL_2", 100), + ] elif CP.carFingerprint in (CAR.CRV, CAR.CRV_EU, CAR.ACURA_RDX, CAR.PILOT_2019, CAR.RIDGELINE): signals += [("MAIN_ON", "SCM_BUTTONS", 0)] elif CP.carFingerprint == CAR.FIT: signals += [("CAR_GAS", "GAS_PEDAL_2", 0), ("MAIN_ON", "SCM_BUTTONS", 0), ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0)] + checks += [ + ("GAS_PEDAL_2", 100), + ] elif CP.carFingerprint == CAR.HRV: signals += [("CAR_GAS", "GAS_PEDAL", 0), ("MAIN_ON", "SCM_BUTTONS", 0), ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0)] - + checks += [ + ("GAS_PEDAL", 100), + ] elif CP.carFingerprint == CAR.ODYSSEY: signals += [("MAIN_ON", "SCM_FEEDBACK", 0), ("EPB_STATE", "EPB_STATUS", 0)] @@ -147,6 +175,9 @@ def get_can_signals(CP): elif CP.carFingerprint == CAR.PILOT: signals += [("MAIN_ON", "SCM_BUTTONS", 0), ("CAR_GAS", "GAS_PEDAL_2", 0)] + checks += [ + ("GAS_PEDAL_2", 0), # TODO: fix this freq, seems this signal isn't present at all on some models + ] elif CP.carFingerprint == CAR.ODYSSEY_CHN: signals += [("MAIN_ON", "SCM_BUTTONS", 0), ("EPB_STATE", "EPB_STATUS", 0)] @@ -278,9 +309,9 @@ class CarState(CarStateBase): ret.cruiseState.standstill = cp.vl["ACC_HUD"]['CRUISE_SPEED'] == 252. ret.cruiseState.speedOffset = calc_cruise_offset(0, ret.vEgo) if self.CP.carFingerprint in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.ACCORDH, CAR.CRV_HYBRID, CAR.INSIGHT): - ret.brakePressed = cp.vl["POWERTRAIN_DATA"]['BRAKE_PRESSED'] != 0 or \ - (self.brake_switch and self.brake_switch_prev and - cp.ts["POWERTRAIN_DATA"]['BRAKE_SWITCH'] != self.brake_switch_ts) + ret.brakePressed = bool(cp.vl["POWERTRAIN_DATA"]['BRAKE_PRESSED'] or + (self.brake_switch and self.brake_switch_prev and + cp.ts["POWERTRAIN_DATA"]['BRAKE_SWITCH'] != self.brake_switch_ts)) self.brake_switch_prev = self.brake_switch self.brake_switch_ts = cp.ts["POWERTRAIN_DATA"]['BRAKE_SWITCH'] else: @@ -313,7 +344,7 @@ class CarState(CarStateBase): self.is_metric = not cp.vl["HUD_SETTING"]['IMPERIAL_UNIT'] if self.CP.carFingerprint in (CAR.CIVIC) else False if self.CP.carFingerprint in HONDA_BOSCH: - ret.stockAeb = bool(cp_cam.vl["ACC_CONTROL"]["AEB_STATUS"] and cp_cam.vl["ACC_CONTROL"]["ACCEL_COMMAND"] < -1e-5) + ret.stockAeb = bool(cp.vl["ACC_CONTROL"]["AEB_STATUS"] and cp.vl["ACC_CONTROL"]["ACCEL_COMMAND"] < -1e-5) else: ret.stockAeb = bool(cp_cam.vl["BRAKE_COMMAND"]["AEB_REQ_1"] and cp_cam.vl["BRAKE_COMMAND"]["COMPUTER_BRAKE"] > 1e-5) @@ -325,7 +356,7 @@ class CarState(CarStateBase): self.stock_hud = cp_cam.vl["ACC_HUD"] self.stock_brake = cp_cam.vl["BRAKE_COMMAND"] - if self.CP.carFingerprint in (CAR.CRV_5G, ): + if self.CP.enableBsm and self.CP.carFingerprint in (CAR.CRV_5G, ): # BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0 # more info here: https://github.com/commaai/openpilot/pull/1867 ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]['BSM_ALERT'] == 1 @@ -343,10 +374,12 @@ class CarState(CarStateBase): def get_cam_can_parser(CP): signals = [] - if CP.carFingerprint in HONDA_BOSCH: - signals += [("ACCEL_COMMAND", "ACC_CONTROL", 0), - ("AEB_STATUS", "ACC_CONTROL", 0)] - else: + # all hondas except CRV, RDX and 2019 Odyssey@China use 0xe4 for steering + checks = [(0xe4, 100)] + if CP.carFingerprint in [CAR.CRV, CAR.CRV_EU, CAR.ACURA_RDX, CAR.ODYSSEY_CHN]: + checks = [(0x194, 100)] + + if CP.carFingerprint not in HONDA_BOSCH: signals += [("COMPUTER_BRAKE", "BRAKE_COMMAND", 0), ("AEB_REQ_1", "BRAKE_COMMAND", 0), ("FCW", "BRAKE_COMMAND", 0), @@ -355,24 +388,23 @@ class CarState(CarStateBase): ("FCM_OFF_2", "ACC_HUD", 0), ("FCM_PROBLEM", "ACC_HUD", 0), ("ICONS", "ACC_HUD", 0)] - - # all hondas except CRV, RDX and 2019 Odyssey@China use 0xe4 for steering - checks = [(0xe4, 100)] - if CP.carFingerprint in [CAR.CRV, CAR.CRV_EU, CAR.ACURA_RDX, CAR.ODYSSEY_CHN]: - checks = [(0x194, 100)] + checks += [ + ("ACC_HUD", 10), + ("BRAKE_COMMAND", 50), + ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) @staticmethod def get_body_can_parser(CP): - signals = [] - checks = [] - - if CP.carFingerprint == CAR.CRV_5G: - signals += [("BSM_ALERT", "BSM_STATUS_RIGHT", 0), - ("BSM_ALERT", "BSM_STATUS_LEFT", 0)] + if CP.enableBsm and CP.carFingerprint == CAR.CRV_5G: + signals = [("BSM_ALERT", "BSM_STATUS_RIGHT", 0), + ("BSM_ALERT", "BSM_STATUS_LEFT", 0)] + checks = [ + ("BSM_STATUS_LEFT", 3), + ("BSM_STATUS_RIGHT", 3), + ] bus_body = 0 # B-CAN is forwarded to ACC-CAN radar side (CAN 0 on fake ethernet port) return CANParser(DBC[CP.carFingerprint]['body'], signals, checks, bus_body) - return None diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 112bfdbc2..86c39b124 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -135,6 +135,9 @@ class CarInterface(CarInterfaceBase): ret.enableGasInterceptor = 0x201 in fingerprint[0] ret.openpilotLongitudinalControl = ret.enableCamera + if candidate == CAR.CRV_5G: + ret.enableBsm = 0x12f8bfa7 in fingerprint[0] + cloudlog.warning("ECU Camera Simulated: %r", ret.enableCamera) cloudlog.warning("ECU Gas Interceptor: %r", ret.enableGasInterceptor) diff --git a/selfdrive/car/honda/radar_interface.py b/selfdrive/car/honda/radar_interface.py index 6acec73d3..45e015af6 100755 --- a/selfdrive/car/honda/radar_interface.py +++ b/selfdrive/car/honda/radar_interface.py @@ -11,7 +11,7 @@ def _create_nidec_can_parser(car_fingerprint): ['REL_SPEED'] * 16, [0x400] + radar_messages[1:] * 4, [0] + [255] * 16 + [1] * 16 + [0] * 16 + [0] * 16)) - checks = list(zip([0x445], [20])) + checks = [(s[1], 20) for s in signals] return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index fe9a29080..a63b45976 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -34,27 +34,27 @@ VISUAL_HUD = { VisualAlert.speedTooHigh: 8} class CAR: - ACCORD = "HONDA ACCORD 2018 SPORT 2T" - ACCORD_15 = "HONDA ACCORD 2018 LX 1.5T" - ACCORDH = "HONDA ACCORD 2018 HYBRID TOURING" - CIVIC = "HONDA CIVIC 2016 TOURING" - CIVIC_BOSCH = "HONDA CIVIC HATCHBACK 2017 SEDAN/COUPE 2019" - CIVIC_BOSCH_DIESEL = "HONDA CIVIC SEDAN 1.6 DIESEL" - ACURA_ILX = "ACURA ILX 2016 ACURAWATCH PLUS" - CRV = "HONDA CR-V 2016 TOURING" - CRV_5G = "HONDA CR-V 2017 EX" - CRV_EU = "HONDA CR-V 2016 EXECUTIVE" - CRV_HYBRID = "HONDA CR-V 2019 HYBRID" - FIT = "HONDA FIT 2018 EX" - HRV = "HONDA HRV 2019 TOURING" - ODYSSEY = "HONDA ODYSSEY 2018 EX-L" - ODYSSEY_CHN = "HONDA ODYSSEY 2019 EXCLUSIVE CHN" - ACURA_RDX = "ACURA RDX 2018 ACURAWATCH PLUS" - ACURA_RDX_3G = "ACURA RDX 2020 TECH" - PILOT = "HONDA PILOT 2017 TOURING" - PILOT_2019 = "HONDA PILOT 2019 ELITE" - RIDGELINE = "HONDA RIDGELINE 2017 BLACK EDITION" - INSIGHT = "HONDA INSIGHT 2019 TOURING" + ACCORD = "HONDA ACCORD 2T 2018" + ACCORD_15 = "HONDA ACCORD 1.5T 2018" + ACCORDH = "HONDA ACCORD HYBRID 2018" + CIVIC = "HONDA CIVIC 2016" + CIVIC_BOSCH = "HONDA CIVIC (BOSCH) 2019" + CIVIC_BOSCH_DIESEL = "HONDA CIVIC SEDAN 1.6 DIESEL 2019" + ACURA_ILX = "ACURA ILX 2016" + CRV = "HONDA CR-V 2016" + CRV_5G = "HONDA CR-V 2017" + CRV_EU = "HONDA CR-V EU 2016" + CRV_HYBRID = "HONDA CR-V HYBRID 2019" + FIT = "HONDA FIT 2018" + HRV = "HONDA HRV 2019" + ODYSSEY = "HONDA ODYSSEY 2018" + ODYSSEY_CHN = "HONDA ODYSSEY CHN 2019" + ACURA_RDX = "ACURA RDX 2018" + ACURA_RDX_3G = "ACURA RDX 2020" + PILOT = "HONDA PILOT 2017" + PILOT_2019 = "HONDA PILOT 2019" + RIDGELINE = "HONDA RIDGELINE 2017" + INSIGHT = "HONDA INSIGHT 2019" # diag message that in some Nidec cars only appear with 1s freq if VIN query is performed DIAG_MSGS = {1600: 5, 1601: 8} @@ -169,6 +169,9 @@ FW_VERSIONS = { b'37805-6B2-A650\x00\x00', b'37805-6B2-A660\x00\x00', b'37805-6B2-A720\x00\x00', + b'37805-6B2-A810\x00\x00', + b'37805-6B2-A820\x00\x00', + b'37805-6B2-A920\x00\x00', b'37805-6B2-M520\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ @@ -177,6 +180,7 @@ FW_VERSIONS = { (Ecu.transmission, 0x18da1ef1, None): [ b'28102-6B8-A560\x00\x00', b'28102-6B8-A570\x00\x00', + b'28102-6B8-A700\x00\x00', b'28102-6B8-A800\x00\x00', b'28102-6B8-C570\x00\x00', b'28102-6B8-M520\x00\x00', @@ -185,16 +189,19 @@ FW_VERSIONS = { b'46114-TVA-A060\x00\x00', b'46114-TVA-A080\x00\x00', b'46114-TVA-A120\x00\x00', + b'46114-TVA-A320\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TVA-C040\x00\x00', b'57114-TVA-C050\x00\x00', b'57114-TVA-C060\x00\x00', + b'57114-TVA-C530\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TVA,A150\x00\x00', # modified firmware b'39990-TVA-A150\x00\x00', b'39990-TVA-A160\x00\x00', + b'39990-TVA-A340\x00\x00', b'39990-TVA-X030\x00\x00', ], (Ecu.unknown, 0x18da3af1, None): [ @@ -202,15 +209,21 @@ FW_VERSIONS = { ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TVA-A460\x00\x00', + b'77959-TVA-L420\x00\x00', b'77959-TVA-X330\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TVA-A210\x00\x00', b'78109-TVC-A010\x00\x00', b'78109-TVC-A020\x00\x00', + b'78109-TVC-A030\x00\x00', b'78109-TVC-A110\x00\x00', + b'78109-TVC-A130\x00\x00', b'78109-TVC-A210\x00\x00', + b'78109-TVC-A220\x00\x00', b'78109-TVC-C110\x00\x00', + b'78109-TVC-L010\x00\x00', + b'78109-TVC-L210\x00\x00', b'78109-TVC-M510\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ @@ -219,20 +232,26 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36802-TVA-A160\x00\x00', b'36802-TVA-A170\x00\x00', + b'36802-TVC-A330\x00\x00', b'36802-TWA-A070\x00\x00', ], (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TVA-A060\x00\x00', + b'36161-TVC-A330\x00\x00', b'36161-TWA-A070\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TVA-A010\x00\x00', + b'38897-TVA-A020\x00\x00', ], }, CAR.ACCORD_15: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ + b'37805-6A0-9520\x00\x00', b'37805-6A0-9620\x00\x00', + b'37805-6A0-9720\x00\x00', b'37805-6A0-A540\x00\x00', + b'37805-6A0-A550\x00\x00', b'37805-6A0-A640\x00\x00', b'37805-6A0-A650\x00\x00', b'37805-6A0-A740\x00\x00', @@ -248,6 +267,7 @@ FW_VERSIONS = { b'28101-6A7-A230\x00\x00', b'28101-6A7-A320\x00\x00', b'28101-6A7-A330\x00\x00', + b'28101-6A7-A410\x00\x00', b'28101-6A7-A510\x00\x00', b'28101-6A9-H140\x00\x00', b'28101-6A9-H420\x00\x00', @@ -264,15 +284,19 @@ FW_VERSIONS = { b'46114-TVE-H560\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TBX-H310\x00\x00', b'78109-TVA-A010\x00\x00', + b'78109-TVA-A020\x00\x00', b'78109-TVA-A110\x00\x00', + b'78109-TVA-A120\x00\x00', b'78109-TVA-A210\x00\x00', b'78109-TVA-A220\x00\x00', b'78109-TVA-A310\x00\x00', b'78109-TVA-C010\x00\x00', + b'78109-TVA-L010\x00\x00', + b'78109-TVA-L210\x00\x00', b'78109-TVE-H610\x00\x00', b'78109-TWA-A210\x00\x00', - b'78109-TBX-H310\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ b'78209-TVA-A010\x00\x00', @@ -288,8 +312,9 @@ FW_VERSIONS = { b'77959-TBX-H230\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ - b'57114-TVA-B050\x00\x00', b'57114-TVA-B040\x00\x00', + b'57114-TVA-B050\x00\x00', + b'57114-TVA-B060\x00\x00', b'57114-TVE-H250\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ @@ -310,39 +335,47 @@ FW_VERSIONS = { CAR.ACCORDH: { (Ecu.gateway, 0x18daeff1, None): [ b'38897-TWA-A120\x00\x00', + b'38897-TWD-J020\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TWA-A040\x00\x00', b'57114-TWA-A050\x00\x00', + b'57114-TWA-B520\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TWA-A440\x00\x00', + b'77959-TWA-L420\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TWA-A010\x00\x00', b'78109-TWA-A020\x00\x00', + b'78109-TWA-A030\x00\x00', b'78109-TWA-A110\x00\x00', b'78109-TWA-A120\x00\x00', b'78109-TWA-A210\x00\x00', b'78109-TWA-A220\x00\x00', - + b'78109-TWA-L010\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TWA-A910\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ b'78209-TVA-A010\x00\x00', + b'78209-TVA-A110\x00\x00', ], (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TWA-A070\x00\x00', + b'36161-TWA-A330\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36802-TWA-A080\x00\x00', b'36802-TWA-A070\x00\x00', + b'36802-TWA-A330\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TVA-A160\x00\x00', b'39990-TVA-A150\x00\x00', + b'39990-TVA-A340\x00\x00', ], }, CAR.CIVIC: { @@ -352,23 +385,29 @@ FW_VERSIONS = { b'37805-5AA-A670\x00\x00', b'37805-5AA-A680\x00\x00', b'37805-5AA-A810\x00\x00', + b'37805-5AA-C640\x00\x00', b'37805-5AA-C680\x00\x00', b'37805-5AA-C820\x00\x00', b'37805-5AA-L650\x00\x00', b'37805-5AA-L660\x00\x00', b'37805-5AA-L680\x00\x00', b'37805-5AA-L690\x00\x00', + b'37805-5AG-Q710\x00\x00', b'37805-5AJ-A610\x00\x00', b'37805-5AJ-A620\x00\x00', + b'37805-5AJ-L610\x00\x00', b'37805-5BA-A310\x00\x00', b'37805-5BA-A510\x00\x00', b'37805-5BA-A740\x00\x00', b'37805-5BA-A760\x00\x00', + b'37805-5BA-A930\x00\x00', b'37805-5BA-A960\x00\x00', + b'37805-5BA-C860\x00\x00', + b'37805-5BA-L410\x00\x00', + b'37805-5BA-L760\x00\x00', b'37805-5BA-L930\x00\x00', b'37805-5BA-L940\x00\x00', b'37805-5BA-L960\x00\x00', - b'37805-5AG-Q710\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5CG-A040\x00\x00', @@ -406,6 +445,7 @@ FW_VERSIONS = { b'78109-TBA-A510\x00\x00', b'78109-TBA-A520\x00\x00', b'78109-TBA-A530\x00\x00', + b'78109-TBA-C520\x00\x00', b'78109-TBC-A310\x00\x00', b'78109-TBC-A320\x00\x00', b'78109-TBC-A510\x00\x00', @@ -414,9 +454,10 @@ FW_VERSIONS = { b'78109-TBC-C510\x00\x00', b'78109-TBC-C520\x00\x00', b'78109-TBC-C530\x00\x00', + b'78109-TBH-A510\x00\x00', b'78109-TBH-A530\x00\x00', - b'78109-TEG-A310\x00\x00', b'78109-TED-Q510\x00\x00', + b'78109-TEG-A310\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ b'36161-TBA-A020\x00\x00', @@ -439,6 +480,9 @@ FW_VERSIONS = { b'37805-5AA-A950\x00\x00', b'37805-5AA-L940\x00\x00', b'37805-5AA-L950\x00\x00', + b'37805-5AG-Z910\x00\x00', + b'37805-5AJ-A750\x00\x00', + b'37805-5AJ-L750\x00\x00', b'37805-5AN-A750\x00\x00', b'37805-5AN-A830\x00\x00', b'37805-5AN-A840\x00\x00', @@ -452,6 +496,9 @@ FW_VERSIONS = { b'37805-5AN-AR20\x00\x00', b'37805-5AN-CH20\x00\x00', b'37805-5AN-E630\x00\x00', + b'37805-5AN-E720\x00\x00', + b'37805-5AN-E820\x00\x00', + b'37805-5AN-J820\x00\x00', b'37805-5AN-L840\x00\x00', b'37805-5AN-L930\x00\x00', b'37805-5AN-L940\x00\x00', @@ -461,15 +508,19 @@ FW_VERSIONS = { b'37805-5AN-LR20\x00\x00', b'37805-5AN-LS20\x00\x00', b'37805-5AW-G720\x00\x00', - b'37805-5AN-E820\x00\x00', b'37805-5AZ-E850\x00\x00', + b'37805-5AZ-G740\x00\x00', + b'37805-5AZ-G840\x00\x00', + b'37805-5BB-A530\x00\x00', + b'37805-5BB-A540\x00\x00', b'37805-5BB-A630\x00\x00', b'37805-5BB-A640\x00\x00', b'37805-5BB-C540\x00\x00', b'37805-5BB-C630\x00\x00', + b'37805-5BB-C640\x00\x00', b'37805-5BB-L540\x00\x00', + b'37805-5BB-L630\x00\x00', b'37805-5BB-L640\x00\x00', - b'37805-5AZ-G740\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5CG-A920\x00\x00', @@ -478,6 +529,7 @@ FW_VERSIONS = { b'28101-5CG-C220\x00\x00', b'28101-5CG-C320\x00\x00', b'28101-5CG-G020\x00\x00', + b'28101-5CG-L020\x00\x00', b'28101-5CK-A130\x00\x00', b'28101-5CK-A140\x00\x00', b'28101-5CK-A150\x00\x00', @@ -485,35 +537,45 @@ FW_VERSIONS = { b'28101-5CK-C140\x00\x00', b'28101-5CK-C150\x00\x00', b'28101-5CK-G210\x00\x00', + b'28101-5CK-J710\x00\x00', + b'28101-5CK-Q610\x00\x00', b'28101-5DJ-A610\x00\x00', b'28101-5DJ-A710\x00\x00', b'28101-5DV-E330\x00\x00', b'28101-5DV-E610\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TBG-A330\x00\x00', b'57114-TBG-A340\x00\x00', b'57114-TBG-A350\x00\x00', b'57114-TGG-A340\x00\x00', b'57114-TGG-C320\x00\x00', + b'57114-TGG-G320\x00\x00', b'57114-TGG-L320\x00\x00', b'57114-TGG-L330\x00\x00', + b'57114-TGK-T320\x00\x00', b'57114-TGL-G330\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TBA-C020\x00\x00', b'39990-TBA-C120\x00\x00', + b'39990-TEA-T820\x00\x00', b'39990-TEZ-T020\x00\x00', b'39990-TGG-A020\x00\x00', b'39990-TGG-A120\x00\x00', - b'39990-TGN-E120\x00\x00', + b'39990-TGG-J510\x00\x00', b'39990-TGL-E130\x00\x00', + b'39990-TGN-E120\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TBA-A060\x00\x00', + b'77959-TBG-A050\x00\x00', b'77959-TEA-G020\x00\x00', b'77959-TGG-A020\x00\x00', b'77959-TGG-A030\x00\x00', b'77959-TGG-G010\x00\x00', + b'77959-TGG-J320\x00\x00', + b'77959-TGG-Z820\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TBA-A110\x00\x00', @@ -521,7 +583,10 @@ FW_VERSIONS = { b'78109-TBA-C340\x00\x00', b'78109-TBA-C910\x00\x00', b'78109-TBC-A740\x00\x00', + b'78109-TBG-A110\x00\x00', + b'78109-TEG-A720\x00\x00', b'78109-TFJ-G020\x00\x00', + b'78109-TGG-9020\x00\x00', b'78109-TGG-A210\x00\x00', b'78109-TGG-A220\x00\x00', b'78109-TGG-A310\x00\x00', @@ -533,17 +598,23 @@ FW_VERSIONS = { b'78109-TGG-A820\x00\x00', b'78109-TGG-C220\x00\x00', b'78109-TGG-G030\x00\x00', + b'78109-TGG-G230\x00\x00', + b'78109-TGG-G410\x00\x00', + b'78109-TGK-Z410\x00\x00', b'78109-TGL-G120\x00\x00', b'78109-TGL-G130\x00\x00', - b'78109-TGG-G410\x00\x00', + b'78109-TGL-G230\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36802-TBA-A150\x00\x00', + b'36802-TBA-A160\x00\x00', b'36802-TFJ-G060\x00\x00', b'36802-TGG-A050\x00\x00', b'36802-TGG-A060\x00\x00', b'36802-TGG-A130\x00\x00', b'36802-TGG-G040\x00\x00', + b'36802-TGG-G130\x00\x00', + b'36802-TGK-Q120\x00\x00', b'36802-TGL-G040\x00\x00', ], (Ecu.fwdCamera, 0x18dab5f1, None): [ @@ -554,13 +625,19 @@ FW_VERSIONS = { b'36161-TGG-A080\x00\x00', b'36161-TGG-A120\x00\x00', b'36161-TGG-G050\x00\x00', + b'36161-TGG-G130\x00\x00', + b'36161-TGK-Q120\x00\x00', b'36161-TGL-G050\x00\x00', b'36161-TGL-G070\x00\x00', + b'36161-TGG-G070\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TBA-A110\x00\x00', b'38897-TBA-A020\x00\x00', ], + (Ecu.electricBrakeBooster, 0x18da2bf1, None): [ + b'39494-TGL-G030\x00\x00', + ], }, CAR.CIVIC_BOSCH_DIESEL: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ @@ -601,21 +678,42 @@ FW_VERSIONS = { ], }, CAR.CRV: { - (Ecu.vsa, 0x18da28f1, None): [b'57114-T1W-A230\x00\x00',], - (Ecu.srs, 0x18da53f1, None): [b'77959-T0A-A230\x00\x00',], - (Ecu.combinationMeter, 0x18da60f1, None): [b'78109-T1W-A210\x00\x00',], - (Ecu.fwdRadar, 0x18dab0f1, None): [b'36161-T1W-A830\x00\x00',], + (Ecu.vsa, 0x18da28f1, None): [ + b'57114-T1W-A230\x00\x00', + b'57114-T1W-A240\x00\x00', + b'57114-TFF-A940\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-T0A-A230\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-T1W-A210\x00\x00', + b'78109-T1W-C210\x00\x00', + b'78109-T1X-A210\x00\x00', + ], + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-T1W-A830\x00\x00', + b'36161-T1W-C830\x00\x00', + b'36161-T1X-A830\x00\x00', + ], }, CAR.CRV_5G: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-5PA-3060\x00\x00', b'37805-5PA-3080\x00\x00', + b'37805-5PA-3180\x00\x00', b'37805-5PA-4050\x00\x00', + b'37805-5PA-4150\x00\x00', b'37805-5PA-6520\x00\x00', b'37805-5PA-6530\x00\x00', b'37805-5PA-6630\x00\x00', + b'37805-5PA-6640\x00\x00', + b'37805-5PA-7630\x00\x00', + b'37805-5PA-9630\x00\x00', b'37805-5PA-9640\x00\x00', + b'37805-5PA-9730\x00\x00', b'37805-5PA-9830\x00\x00', + b'37805-5PA-9840\x00\x00', b'37805-5PA-A650\x00\x00', b'37805-5PA-A670\x00\x00', b'37805-5PA-A680\x00\x00', @@ -623,8 +721,13 @@ FW_VERSIONS = { b'37805-5PA-A870\x00\x00', b'37805-5PA-A880\x00\x00', b'37805-5PA-A890\x00\x00', + b'37805-5PA-AB10\x00\x00', + b'37805-5PA-AD10\x00\x00', b'37805-5PA-AF20\x00\x00', + b'37805-5PA-C680\x00\x00', b'37805-5PD-Q630\x00\x00', + b'37805-5PF-F730\x00\x00', + b'37805-5PF-M630\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5RG-A020\x00\x00', @@ -638,19 +741,24 @@ FW_VERSIONS = { b'28101-5RH-A120\x00\x00', b'28101-5RH-A220\x00\x00', b'28101-5RL-Q010\x00\x00', + b'28101-5RM-F010\x00\x00', + b'28101-5RM-K010\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TLA-A040\x00\x00', b'57114-TLA-A050\x00\x00', b'57114-TLA-A060\x00\x00', b'57114-TLB-A830\x00\x00', + b'57114-TMC-Z040\x00\x00', b'57114-TMC-Z050\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ - b'39990-TLA,A040\x00\x00', # modified firmware b'39990-TLA-A040\x00\x00', b'39990-TLA-A110\x00\x00', b'39990-TLA-A220\x00\x00', + b'39990-TLA,A040\x00\x00', # modified firmware + b'39990-TME-T030\x00\x00', + b'39990-TME-T120\x00\x00', b'39990-TMT-T010\x00\x00', ], (Ecu.electricBrakeBooster, 0x18da2bf1, None): [ @@ -664,11 +772,17 @@ FW_VERSIONS = { b'78109-TLA-A120\x00\x00', b'78109-TLA-A210\x00\x00', b'78109-TLA-A220\x00\x00', + b'78109-TLA-C110\x00\x00', b'78109-TLA-C210\x00\x00', + b'78109-TLA-C310\x00\x00', + b'78109-TLB-A020\x00\x00', b'78109-TLB-A110\x00\x00', + b'78109-TLB-A120\x00\x00', b'78109-TLB-A210\x00\x00', b'78109-TLB-A220\x00\x00', b'78109-TMC-Q210\x00\x00', + b'78109-TMM-F210\x00\x00', + b'78109-TMM-M110\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TLA-A010\x00\x00', @@ -679,6 +793,7 @@ FW_VERSIONS = { b'36802-TLA-A040\x00\x00', b'36802-TLA-A050\x00\x00', b'36802-TLA-A060\x00\x00', + b'36802-TMC-Q040\x00\x00', b'36802-TMC-Q070\x00\x00', b'36802-TNY-A030\x00\x00', ], @@ -686,6 +801,8 @@ FW_VERSIONS = { b'36161-TLA-A060\x00\x00', b'36161-TLA-A070\x00\x00', b'36161-TLA-A080\x00\x00', + b'36161-TMC-Q020\x00\x00', + b'36161-TMC-Q030\x00\x00', b'36161-TMC-Q040\x00\x00', b'36161-TNY-A020\x00\x00', ], @@ -696,6 +813,8 @@ FW_VERSIONS = { b'77959-TLA-A410\x00\x00', b'77959-TLA-A420\x00\x00', b'77959-TLA-Q040\x00\x00', + b'77959-TLA-Z040\x00\x00', + b'77959-TMM-F040\x00\x00', ], }, CAR.CRV_EU: { @@ -730,20 +849,23 @@ FW_VERSIONS = { (Ecu.gateway, 0x18daeff1, None): [ b'38897-TMA-H110\x00\x00', b'38897-TPG-A110\x00\x00', + b'38897-TPG-A210\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TMB-H510\x00\x00', b'54008-TMB-H610\x00\x00', ], (Ecu.fwdCamera, 0x18dab5f1, None): [ + b'36161-TMB-H040\x00\x00', b'36161-TPA-E050\x00\x00', b'36161-TPG-A030\x00\x00', - b'36161-TMB-H040\x00\x00', + b'36161-TPG-A040\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TMB-H220\x00\x00', b'78109-TPA-G520\x00\x00', b'78109-TPG-A110\x00\x00', - b'78109-TMB-H220\x00\x00', + b'78109-TPG-A210\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ b'78209-TLA-X010\x00\x00', @@ -754,8 +876,10 @@ FW_VERSIONS = { b'36802-TMB-H040\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ - b'77959-TLA-G220\x00\x00', b'77959-TLA-C320\x00\x00', + b'77959-TLA-C410\x00\x00', + b'77959-TLA-C420\x00\x00', + b'77959-TLA-G220\x00\x00', b'77959-TLA-H240\x00\x00', ], }, @@ -771,6 +895,7 @@ FW_VERSIONS = { b'38897-T5A-J010\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-T5A-A410\x00\x00', b'78109-T5A-A420\x00\x00', b'78109-T5A-A910\x00\x00', ], @@ -788,11 +913,15 @@ FW_VERSIONS = { b'38897-THR-A020\x00\x00', ], (Ecu.programmedFuelInjection, 0x18da10f1, None): [ + b'37805-5MR-A240\x00\x00', b'37805-5MR-A250\x00\x00', b'37805-5MR-A310\x00\x00', + b'37805-5MR-A740\x00\x00', b'37805-5MR-A750\x00\x00', b'37805-5MR-A840\x00\x00', b'37805-5MR-C620\x00\x00', + b'37805-5MR-D530\x00\x00', + b'37805-5MR-K730\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-THR-A020\x00\x00', @@ -801,8 +930,10 @@ FW_VERSIONS = { (Ecu.srs, 0x18da53f1, None): [ b'77959-THR-A010\x00\x00', b'77959-THR-A110\x00\x00', + b'77959-THR-X010\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ + b'36161-THR-A020\x00\x00', b'36161-THR-A030\x00\x00', b'36161-THR-A110\x00\x00', b'36161-THR-A720\x00\x00', @@ -810,8 +941,11 @@ FW_VERSIONS = { b'36161-THR-A810\x00\x00', b'36161-THR-A910\x00\x00', b'36161-THR-C010\x00\x00', + b'36161-THR-D110\x00\x00', + b'36161-THR-K020\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ + b'28101-5NZ-A110\x00\x00', b'28101-5NZ-A310\x00\x00', b'28101-5NZ-C310\x00\x00', b'28102-5MX-A001\x00\x00', @@ -821,6 +955,10 @@ FW_VERSIONS = { b'28102-5MX-A900\x00\x00', b'28102-5MX-A910\x00\x00', b'28102-5MX-C001\x00\x00', + b'28102-5MX-D001\x00\x00', + b'28102-5MX-D710\x00\x00', + b'28102-5MX-K610\x00\x00', + b'28103-5NZ-A100\x00\x00', b'28103-5NZ-A300\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ @@ -828,8 +966,11 @@ FW_VERSIONS = { b'57114-THR-A110\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-THR-A220\x00\x00', b'78109-THR-A230\x00\x00', + b'78109-THR-A420\x00\x00', b'78109-THR-A430\x00\x00', + b'78109-THR-A720\x00\x00', b'78109-THR-A820\x00\x00', b'78109-THR-A830\x00\x00', b'78109-THR-AB20\x00\x00', @@ -837,12 +978,17 @@ FW_VERSIONS = { b'78109-THR-AB40\x00\x00', b'78109-THR-AC20\x00\x00', b'78109-THR-AC40\x00\x00', + b'78109-THR-AC50\x00\x00', b'78109-THR-AE20\x00\x00', b'78109-THR-AE40\x00\x00', + b'78109-THR-AK10\x00\x00', b'78109-THR-AL10\x00\x00', b'78109-THR-AN10\x00\x00', b'78109-THR-C330\x00\x00', b'78109-THR-CE20\x00\x00', + b'78109-THR-DA20\x00\x00', + b'78109-THR-DA40\x00\x00', + b'78109-THR-K120\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-THR-A020\x00\x00', @@ -851,57 +997,79 @@ FW_VERSIONS = { CAR.PILOT: { (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TG7-A520\x00\x00', + b'54008-TG7-A530\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ - b'28101-5EZ-A210\x00\x00', - b'28101-5EZ-A100\x00\x00', - b'28101-5EZ-A060\x00\x00', + b'28101-5EY-A050\x00\x00', + b'28101-5EY-A100\x00\x00', b'28101-5EZ-A050\x00\x00', + b'28101-5EZ-A060\x00\x00', + b'28101-5EZ-A100\x00\x00', + b'28101-5EZ-A210\x00\x00', ], (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-RLV-C910\x00\x00', - b'37805-RLV-C520\x00\x00', - b'37805-RLV-C510\x00\x00', + b'37805-RLV-4060\x00\x00', b'37805-RLV-4070\x00\x00', b'37805-RLV-A830\x00\x00', + b'37805-RLV-A840\x00\x00', + b'37805-RLV-C430\x00\x00', + b'37805-RLV-C510\x00\x00', + b'37805-RLV-C520\x00\x00', + b'37805-RLV-C530\x00\x00', + b'37805-RLV-C910\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ - b'39990-TG7-A040\x00\x00', b'39990-TG7-A030\x00\x00', + b'39990-TG7-A040\x00\x00', + b'39990-TG7-A060\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ b'36161-TG7-A520\x00\x00', - b'36161-TG7-A820\x00\x00', b'36161-TG7-A720\x00\x00', + b'36161-TG7-A820\x00\x00', + b'36161-TG7-C520\x00\x00', + b'36161-TG7-D520\x00\x00', + b'36161-TG8-A520\x00\x00', + b'36161-TG8-A720\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TG7-A110\x00\x00', b'77959-TG7-A020\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ - b'78109-TG7-A720\x00\x00', - b'78109-TG7-A520\x00\x00', - b'78109-TG7-A420\x00\x00', b'78109-TG7-A040\x00\x00', + b'78109-TG7-A050\x00\x00', + b'78109-TG7-A420\x00\x00', + b'78109-TG7-A520\x00\x00', + b'78109-TG7-A720\x00\x00', + b'78109-TG7-D020\x00\x00', + b'78109-TG8-A420\x00\x00', + b'78109-TG8-A520\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TG7-A130\x00\x00', b'57114-TG7-A140\x00\x00', - b'57114-TG7-A240\x00\x00', b'57114-TG7-A230\x00\x00', + b'57114-TG7-A240\x00\x00', + b'57114-TG8-A140\x00\x00', + b'57114-TG8-A240\x00\x00', ], }, CAR.PILOT_2019: { (Ecu.eps, 0x18da30f1, None): [ b'39990-TG7-A060\x00\x00', + b'39990-TG7-A070\x00\x00', b'39990-TGS-A230\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TG7-A030\x00\x00', + b'38897-TG7-A040\x00\x00', b'38897-TG7-A110\x00\x00', b'38897-TG7-A210\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ + b'36161-TG7-A310\x00\x00', b'36161-TG7-A630\x00\x00', b'36161-TG7-A930\x00\x00', b'36161-TG8-A630\x00\x00', @@ -913,11 +1081,16 @@ FW_VERSIONS = { b'77959-TGS-A010\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TG7-AJ10\x00\x00', b'78109-TG7-AJ20\x00\x00', b'78109-TG7-AK10\x00\x00', b'78109-TG7-AK20\x00\x00', + b'78109-TG7-AM20\x00\x00', b'78109-TG7-AP10\x00\x00', b'78109-TG7-AP20\x00\x00', + b'78109-TG7-AS20\x00\x00', + b'78109-TG7-AU20\x00\x00', + b'78109-TG8-AJ10\x00\x00', b'78109-TG8-AJ20\x00\x00', b'78109-TGS-AK20\x00\x00', b'78109-TGS-AP20\x00\x00', @@ -931,12 +1104,36 @@ FW_VERSIONS = { b'57114-TGT-A530\x00\x00', ], }, + CAR.ACURA_RDX: { + (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TX5-A220\x00\x00', + b'57114-TX4-A220\x00\x00', + ], + (Ecu.fwdCamera, 0x18dab0f1, None): [ + b'36161-TX5-A030\x00\x00', + b'36161-TX4-A030\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-TX4-C010\x00\x00', + b'77959-TX4-B010\x00\x00', + b'77959-TX4-C020\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TX5-A310\x00\x00', + b'78109-TX4-A210\x00\x00', + b'78109-TX4-A310\x00\x00', + ], + }, CAR.ACURA_RDX_3G: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-5YF-A230\x00\x00', + b'37805-5YF-A320\x00\x00', + b'37805-5YF-A330\x00\x00', b'37805-5YF-A420\x00\x00', b'37805-5YF-A430\x00\x00', + b'37805-5YF-A870\x00\x00', b'37805-5YF-C210\x00\x00', + b'37805-5YF-C410\000\000', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TJB-A040\x00\x00', @@ -952,14 +1149,20 @@ FW_VERSIONS = { b'54008-TJB-A520\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ + b'28102-5YK-A630\x00\x00', b'28102-5YK-A700\x00\x00', b'28102-5YK-A711\x00\x00', + b'28102-5YL-A700\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TJB-A240\x00\x00', b'78109-TJB-AB10\x00\x00', b'78109-TJB-AD10\x00\x00', b'78109-TJB-AF10\x00\x00', b'78109-TJB-AW10\x00\x00', + b'78109-TJC-AA10\x00\x00', + b'78109-TJC-AD10\x00\x00', + b'78109-TJB-AS10\000\000', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TJB-A040\x00\x00', @@ -970,12 +1173,14 @@ FW_VERSIONS = { b'46114-TJB-A060\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ + b'38897-TJB-A040\x00\x00', b'38897-TJB-A110\x00\x00', b'38897-TJB-A120\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TJB-A030\x00\x00', b'39990-TJB-A040\x00\x00', + b'39990-TJB-A130\x00\x00' ], }, CAR.RIDGELINE: { @@ -1001,6 +1206,7 @@ FW_VERSIONS = { b'78109-T6Z-A510\x00\x00', b'78109-T6Z-A710\x00\x00', b'78109-T6Z-AA10\x00\x00', + b'78109-T6Z-C620\x00\x00', b'78109-TJZ-A510\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ @@ -1073,14 +1279,17 @@ FW_VERSIONS = { b'38897-TX6-A010\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-TV9-A140\x00\x00', b'36161-TX6-A030\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ + b'77959-TX6-A230\x00\x00', b'77959-TX6-C210\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-T3R-A120\x00\x00', b'78109-T3R-A410\x00\x00', + b'78109-TV9-A510\x00\x00', ], }, } diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index b0803698b..c74a83b92 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -34,7 +34,7 @@ class CarState(CarStateBase): ret.steeringTorque = cp.vl["MDPS12"]['CR_Mdps_StrColTq'] ret.steeringTorqueEps = cp.vl["MDPS12"]['CR_Mdps_OutTq'] ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD - ret.steerWarning = cp.vl["MDPS12"]['CF_Mdps_ToiUnavail'] != 0 + ret.steerWarning = cp.vl["MDPS12"]['CF_Mdps_ToiUnavail'] != 0 or cp.vl["MDPS12"]['CF_Mdps_ToiFlt'] != 0 # cruise state if self.CP.openpilotLongitudinalControl: @@ -125,7 +125,7 @@ class CarState(CarStateBase): ret.stockAeb = cp.vl["SCC12"]['AEB_CmdAct'] != 0 ret.stockFcw = cp.vl["SCC12"]['CF_VSM_Warn'] == 2 - if self.CP.carFingerprint in FEATURES["use_bsm"]: + if self.CP.enableBsm: ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0 ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0 @@ -189,12 +189,10 @@ class CarState(CarStateBase): ("ESC_Off_Step", "TCS15", 0), ("AVH_LAMP", "TCS15", 0), - ("CF_Lvr_GearInf", "LVR11", 0), # Transmission Gear (0 = N or P, 1-8 = Fwd, 14 = Rev) - ("CR_Mdps_StrColTq", "MDPS12", 0), ("CF_Mdps_ToiActive", "MDPS12", 0), ("CF_Mdps_ToiUnavail", "MDPS12", 0), - ("CF_Mdps_FailStat", "MDPS12", 0), + ("CF_Mdps_ToiFlt", "MDPS12", 0), ("CR_Mdps_OutTq", "MDPS12", 0), ("SAS_Angle", "SAS11", 0), @@ -215,6 +213,7 @@ class CarState(CarStateBase): ("CLU11", 50), ("ESP12", 100), ("CGW1", 10), + ("CGW2", 5), ("CGW4", 5), ("WHL_SPD11", 50), ("SAS11", 100), @@ -226,7 +225,7 @@ class CarState(CarStateBase): ("SCC12", 50), ] - if CP.carFingerprint in FEATURES["use_bsm"]: + if CP.enableBsm: signals += [ ("CF_Lca_IndLeft", "LCA11", 0), ("CF_Lca_IndRight", "LCA11", 0), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 9af39af08..5334471a7 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -144,13 +144,19 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.KIA_SELTOS: - ret.lateralTuning.pid.kf = 0.00005 - ret.mass = 1310. + STD_CARGO_KG - ret.wheelbase = 2.6 - ret.steerRatio = 13.73 # Spec - tire_stiffness_factor = 0.5 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] + ret.mass = 1337. + STD_CARGO_KG + ret.wheelbase = 2.63 + ret.steerRatio = 14.56 + tire_stiffness_factor = 1 + ret.lateralTuning.init('indi') + ret.lateralTuning.indi.innerLoopGainBP = [0.] + ret.lateralTuning.indi.innerLoopGainV = [4.] + ret.lateralTuning.indi.outerLoopGainBP = [0.] + ret.lateralTuning.indi.outerLoopGainV = [3.] + ret.lateralTuning.indi.timeConstantBP = [0.] + ret.lateralTuning.indi.timeConstantV = [1.4] + ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] + ret.lateralTuning.indi.actuatorEffectivenessV = [1.8] elif candidate in [CAR.KIA_OPTIMA, CAR.KIA_OPTIMA_H]: ret.lateralTuning.pid.kf = 0.00005 ret.mass = 3558. * CV.LB_TO_KG @@ -231,6 +237,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor=tire_stiffness_factor) ret.enableCamera = True + ret.enableBsm = 0x58b in fingerprint[0] return ret diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 54fa98f4f..9f778ebfd 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -7,7 +7,7 @@ Ecu = car.CarParams.Ecu # Steer torque limits class CarControllerParams: def __init__(self, CP): - if CP.carFingerprint in [CAR.SONATA, CAR.PALISADE, CAR.SANTA_FE, CAR.VELOSTER, CAR.GENESIS_G70, CAR.IONIQ_EV_2020]: + if CP.carFingerprint in [CAR.SONATA, CAR.PALISADE, CAR.SANTA_FE, CAR.VELOSTER, CAR.GENESIS_G70, CAR.IONIQ_EV_2020, CAR.KIA_CEED, CAR.KIA_SELTOS]: self.STEER_MAX = 384 else: self.STEER_MAX = 255 @@ -20,7 +20,7 @@ class CarControllerParams: class CAR: # Hyundai - ELANTRA = "HYUNDAI ELANTRA LIMITED ULTIMATE 2017" + ELANTRA = "HYUNDAI ELANTRA 2017" ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT" HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016" IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019" @@ -28,7 +28,7 @@ class CAR: IONIQ_EV_2020 = "HYUNDAI IONIQ ELECTRIC 2020" KONA = "HYUNDAI KONA 2020" KONA_EV = "HYUNDAI KONA ELECTRIC 2019" - SANTA_FE = "HYUNDAI SANTA FE LIMITED 2019" + SANTA_FE = "HYUNDAI SANTA FE 2019" SONATA = "HYUNDAI SONATA 2020" SONATA_LF = "HYUNDAI SONATA 2019" PALISADE = "HYUNDAI PALISADE 2020" @@ -171,70 +171,103 @@ IGNORED_FINGERPRINTS = [CAR.VELOSTER, CAR.GENESIS_G70, CAR.KONA, CAR.KIA_CEED, C FW_VERSIONS = { CAR.IONIQ_EV_2020: { (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7200 ', ], (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7560 4APEC101', ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.01 95740-G2600 190819', + b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.03 95740-G2500 190516', b'\xf1\x00AEE MFC AT EUR RHD 1.00 1.01 95740-G2600 190819', ], }, CAR.IONIQ_EV_LTD: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00AEev SCC F-CUP 1.00 1.00 96400-G7000 ', + b'\xf1\x00AEev SCC F-CUP 1.00 1.00 96400-G7100 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00AE MDPS C 1.00 1.02 56310G7300\x00 4AEEC102', + b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7501 4AEEC104', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G7200 160418', + b'\xf1\x00AEE MFC AT USA LHD 1.00 1.00 95740-G2400 180222', ], }, CAR.SONATA: { (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ', - b'\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ', b'\xf1\x00DN8_ SCC F-CU- 1.00 1.00 99110-L0000 ', b'\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ', + b'\xf1\x00DN8_ SCC F-CUP 1.00 1.02 99110-L1000 ', + b'\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ', + b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ', b'\xf1\x00DN89110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa \xf1\xa01.00\xaa\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x00', b'\xf1\x00DN8 1.00 99110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa \xf1\xa01.00\xaa\xaa\xaa', - b'\xf1\xa01.00', ], (Ecu.esp, 0x7d1, None): [ + b'\xf1\x00DN ESC \a 106 \a\x01 58910-L0100', b'\xf1\x00DN ESC \x01 102\x19\x04\x13 58910-L1300\xf1\xa01.02', b'\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100', - b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100\xf1\xa01.04', - b'\xf1\x8758910-L0100\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100\xf1\xa01.04', - b'\xf1\x8758910-L0100\xf1\x00DN ESC \a 106 \a\x01 58910-L0100\xf1\xa01.06', - b'\xf1\x00DN ESC \a 106 \a\x01 58910-L0100', b'\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100', + b'\xf1\x00DN ESC \x08 103\x19\x06\x01 58910-L1300\xf1\xa01.03', + b'\xf1\x8758910-L0100\xf1\x00DN ESC \a 106 \a\x01 58910-L0100\xf1\xa01.06', + b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100\xf1\xa01.04', + b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100\xf1\xa01.06', + b'\xf1\x8758910-L0100\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100\xf1\xa01.04', ], (Ecu.engine, 0x7e0, None): [ - b'HM6M2_0a0_BD0', + b'\xf1\x81HM6M1_0a0_F00', + b'\xf1\x82DNBVN5GMCCXXXDCA', + b'\xf1\x82DNCVN5GMCCXXXG2B', b'\xf1\x87391162M003\xf1\xa0000F', b'\xf1\x87391162M003\xf1\xa00240', + b'\xf1\x87391162M013\xf1\xa00240', b'HM6M1_0a0_F00', - b'\xf1\x81HM6M1_0a0_F00', + b'HM6M2_0a0_BD0', ], (Ecu.eps, 0x7d4, None): [ - b'\xf1\x8756310-L1010\xf1\x00DN8 MDPS C 1.00 1.03 56310-L1010 4DNDC103\xf1\xa01.03', - b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101\xf1\xa01.01', - b'\xf1\x8756310-L0010\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101\xf1\xa01.01', - b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00DN8 MDPS C 1.00 1.01 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4DNAC101\xf1\xa01.01', - b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101', b'\xf1\x00DN8 MDPS C 1.00 1.01 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4DNAC101', + b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101', + b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101', + b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00DN8 MDPS C 1.00 1.01 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4DNAC101\xf1\xa01.01', + b'\xf1\x8756310-L0010\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101\xf1\xa01.01', + b'\xf1\x8756310-L0210\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC101\xf1\xa01.01', + b'\xf1\x8756310-L1010\xf1\x00DN8 MDPS C 1.00 1.03 56310-L1010 4DNDC103\xf1\xa01.03', + b'\xf1\x8756310-L1030\xf1\x00DN8 MDPS C 1.00 1.03 56310-L1030 4DNDC103\xf1\xa01.03', + b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101\xf1\xa01.01', + b'\xf1\x8756310L0210\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC101\xf1\xa01.01', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.02 99211-L1000 190422', + b'\xf1\x00DN8 MFC AT RUS LHD 1.00 1.03 99211-L1000 190705', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.00 99211-L0000 190716', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L0000 191016', ], (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x00HT6TA260BLHT6TA800A1TDN8C20KS4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', - b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92', + b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB1\xe3\xc10\xa1', + b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', + b'\xf1\x00HT6TA260BLHT6TA800A1TDN8C20KS4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x00HT6TA260BLHT6TA810A1TDN8M25GS0\x00\x00\x00\x00\x00\x00\xaa\x8c\xd9p', b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92', + b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB2\x00\x00\x00\x00\x00\x00\x08\xc9O:', + b'\xf1\x87SALDBA3510954GJ3ww\x87xUUuWx\x88\x87\x88\x87w\x88wvfwfc_\xf9\xff\x98wO\xffl\xe0\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA3573534GJ3\x89\x98\x89\x88EUuWgwvwwwwww\x88\x87xTo\xfa\xff\x86f\x7f\xffo\x0e\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA3601464GJ3\x88\x88\x88\x88ffvggwvwvw\x87gww\x87wvo\xfb\xff\x98\x88\x7f\xffjJ\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA3753044GJ3UUeVff\x86hwwwwvwwgvfgfvo\xf9\xfffU_\xffC\xae\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA3873834GJ3fefVwuwWx\x88\x97\x88w\x88\x97xww\x87wU_\xfb\xff\x86f\x8f\xffN\x04\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA4525334GJ3\x89\x99\x99\x99fevWh\x88\x86\x88fwvgw\x88\x87xfo\xfa\xffuDo\xff\xd1>\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA4626804GJ3wwww\x88\x87\x88xx\x88\x87\x88wwgw\x88\x88\x98\x88\x95_\xf9\xffuDo\xff|\xe7\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA4803224GJ3wwwwwvwg\x88\x88\x98\x88wwww\x87\x88\x88xu\x9f\xfc\xff\x87f\x8f\xff\xea\xea\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA6347404GJ3wwwwff\x86hx\x88\x97\x88\x88\x88\x88\x88vfgf\x88?\xfc\xff\x86Uo\xff\xec/\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA6901634GJ3UUuWVeVUww\x87wwwwwvUge\x86/\xfb\xff\xbb\x99\x7f\xff]2\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SALDBA7077724GJ3\x98\x88\x88\x88ww\x97ygwvwww\x87ww\x88\x87x\x87_\xfd\xff\xba\x99o\xff\x99\x01\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00', + b'\xf1\x87SAMDBA8054504GJ3gw\x87xffvgffffwwwweUVUf?\xfc\xffvU_\xff\xddl\xf1\x89HT6WAD10A1\xf1\x82SDN8G25NB2\x00\x00\x00\x00\x00\x00', ], }, CAR.SONATA_LF: { @@ -246,10 +279,10 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x81606D5K51\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x81606G1051\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00LFF LKAS AT USA LHD 1.00 1.01 95740-C1000 E51', - b'\xf1\xa01.01', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B4051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24NL1\xb0\x9f\xee\xf5', @@ -259,37 +292,88 @@ FW_VERSIONS = { }, CAR.SANTA_FE: { (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\x00TM__ SCC F-CUP 1.00 1.03 99110-S2000 \xf1\xa01.03', + b'\xf1\x00TM__ SCC F-CUP 1.00 1.01 99110-S2000 \xf1\xa01.01', b'\xf1\x00TM__ SCC F-CUP 1.00 1.02 99110-S2000 \xf1\xa01.02', + b'\xf1\x00TM__ SCC F-CUP 1.00 1.03 99110-S2000 \xf1\xa01.03', ], (Ecu.esp, 0x7d1, None): [ + b'\xf1\x00TM ESC \r 100\x18\x031 58910-S2650\xf1\xa01.00', + b'\xf1\x00TM ESC \r 103\x18\x11\x08 58910-S2650\xf1\xa01.03', b'\xf1\x00TM ESC \r 104\x19\a\b 58910-S2650\xf1\xa01.04', b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600\xf1\xa01.00', + b'\xf1\x00TM ESC \x02 102\x18\x07\x01 58910-S2600\xf1\xa01.02', + b'\xf1\x00TM ESC \x02 103\x18\x11\x07 58910-S2600\xf1\xa01.03', + b'\xf1\x00TM ESC \x02 104\x19\x07\x07 58910-S2600\xf1\xa01.04', + b'\xf1\x00TM ESC \x03 103\x18\x11\x07 58910-S2600\xf1\xa01.03', + b'\xf1\x00TM ESC \x0c 103\x18\x11\x08 58910-S2650', + b'\xf1\x00TM ESC \x0c 103\x18\x11\x08 58910-S2650\xf1\xa01.03', ], (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81606EA051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x81606G1051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x81606G3051\x00\x00\x00\x00\x00\x00\x00\x00', - b'\xf1\x81606EA051\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409', + b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8A12', b'\xf1\x00TM MDPS C 1.00 1.01 56340-S2000 9129', - b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x87LBJSGA7082574HG0\x87www\x98\x88\x88\x88\x99\xaa\xb9\x9afw\x86gx\x99\xa7\x89co\xf8\xffvU_\xffR\xaf\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\xa6\xe0\x91', + b'\xf1\x87LBKSGA0458404HG0vfvg\x87www\x89\x99\xa8\x99y\xaa\xa7\x9ax\x88\xa7\x88t_\xf9\xff\x86w\x8f\xff\x15x\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\x00\x00\x00', + b'\xf1\x87LDJUEA6010814HG1\x87w\x87x\x86gvw\x88\x88\x98\x88gw\x86wx\x88\x97\x88\x85o\xf8\xff\x86f_\xff\xd37\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g', + b'\xf1\x87LDJUEA6458264HG1ww\x87x\x97x\x87\x88\x88\x99\x98\x89g\x88\x86xw\x88\x97x\x86o\xf7\xffvw\x8f\xff3\x9a\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g', + b'\xf1\x87LDKUEA2045844HG1wwww\x98\x88x\x87\x88\x88\xa8\x88x\x99\x97\x89x\x88\xa7\x88U\x7f\xf8\xffvfO\xffC\x1e\xf1\x816W3E0051\x00\x00\xf1\x006W351_C2\x00\x006W3E0051\x00\x00TTM4T20NS3\x00\x00\x00\x00', + b'\xf1\x87LDKUEA9993304HG1\x87www\x97x\x87\x88\x99\x99\xa9\x99x\x99\xa7\x89w\x88\x97x\x86_\xf7\xffwwO\xffl#\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS1R\x7f\x90\n', + b'\xf1\x87LDLUEA6061564HG1\xa9\x99\x89\x98\x87wwwx\x88\x97\x88x\x99\xa7\x89x\x99\xa7\x89sO\xf9\xffvU_\xff<\xde\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS50\xcb\xc3\xed', b'\xf1\x87LDLUEA6159884HG1\x88\x87hv\x99\x99y\x97\x89\xaa\xb8\x9ax\x99\x87\x89y\x99\xb7\x99\xa7?\xf7\xff\x97wo\xff\xf3\x05\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00', + b'\xf1\x87LDLUEA6852664HG1\x97wWu\x97www\x89\xaa\xc8\x9ax\x99\x97\x89x\x99\xa7\x89SO\xf7\xff\xa8\x88\x7f\xff\x03z\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS50\xcb\xc3\xed', + b'\xf1\x87LDLUEA6898374HG1fevW\x87wwwx\x88\x97\x88h\x88\x96\x88x\x88\xa7\x88ao\xf9\xff\x98\x99\x7f\xffD\xe2\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00', + b'\xf1\x87LDLUEA6898374HG1fevW\x87wwwx\x88\x97\x88h\x88\x96\x88x\x88\xa7\x88ao\xf9\xff\x98\x99\x7f\xffD\xe2\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS50\xcb\xc3\xed', + b'\xf1\x87SBJWAA5842214GG0\x88\x87\x88xww\x87x\x89\x99\xa8\x99\x88\x99\x98\x89w\x88\x87xw_\xfa\xfffU_\xff\xd1\x8d\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x98{|\xe3', + b'\xf1\x87SBJWAA5890864GG0\xa9\x99\x89\x98\x98\x87\x98y\x89\x99\xa8\x99w\x88\x87xww\x87wvo\xfb\xffuD_\xff\x9f\xb5\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x98{|\xe3', b'\xf1\x87SBJWAA6562474GG0ffvgeTeFx\x88\x97\x88ww\x87www\x87w\x84o\xfa\xff\x87fO\xff\xc2 \xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x00\x00\x00\x00', + b'\xf1\x87SBJWAA6562474GG0ffvgeTeFx\x88\x97\x88ww\x87www\x87w\x84o\xfa\xff\x87fO\xff\xc2 \xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x98{|\xe3', + b'\xf1\x87SBJWAA7780564GG0wvwgUUeVwwwwx\x88\x87\x88wwwwd_\xfc\xff\x86f\x7f\xff\xd7*\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS2F\x84<\xc0', + b'\xf1\x87SBJWAA8278284GG0ffvgUU\x85Xx\x88\x87\x88x\x88w\x88ww\x87w\x96o\xfd\xff\xa7U_\xff\xf2\xa0\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS2F\x84<\xc0', + b'\xf1\x87SBLWAA4363244GG0wvwgwv\x87hgw\x86ww\x88\x87xww\x87wdo\xfb\xff\x86f\x7f\xff3$\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM2G24NS6\x00\x00\x00\x00', + b'\xf1\x87SBLWAA6622844GG0wwwwff\x86hwwwwx\x88\x87\x88\x88\x88\x88\x88\x98?\xfd\xff\xa9\x88\x7f\xffn\xe5\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM2G24NS7u\x1e{\x1c', + b'\xf1\x87SDJXAA7656854GG1DEtWUU\x85X\x88\x88\x98\x88w\x88\x87xx\x88\x87\x88\x96o\xfb\xff\x86f\x7f\xff.\xca\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4G24NS2\x00\x00\x00\x00', + b'\xf1\x87SDKXAA2443414GG1vfvgwv\x87h\x88\x88\x88\x88ww\x87wwwww\x99_\xfc\xffvD?\xffl\xd2\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4G24NS6\x00\x00\x00\x00', ], }, CAR.KIA_STINGER: { - (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 \xf1\xa01.01'], - (Ecu.engine, 0x7e0, None): [ b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00',], - (Ecu.eps, 0x7d4, None): [b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104'], - (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822'], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 \xf1\xa01.01', + b'\xf1\x00CK__ SCC F_CUP 1.00 1.03 96400-J5100 \xf1\xa01.03', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81606DE051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00', + b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104', + b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5220 4C2VL104', + b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104', + b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5420 4C4VL106', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822', + b'\xf1\x00CK MFC AT USA LHD 1.00 1.04 95740-J5000 180504', + ], (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', + b'\xf1\x87VCJLE17622572DK0vd6D\x99\x98y\x97vwVffUfvfC%CuT&Dx\x87o\xff{\x1c\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', + b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x89E21\x00\x00\x00\x00\x00\x00\x00\xf1\x82SCK0T33NB0', + b'\xf1\x87VDHLG17034412DK2vD6DfVvVTD$D\x99w\x88\x98EDEDeT6DgfO\xff\xc3=\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', + b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', + b'\xf1\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2', + b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94', ], }, CAR.KIA_OPTIMA_H: { @@ -301,16 +385,22 @@ FW_VERSIONS = { }, CAR.PALISADE: { (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04', b'\xf1\000LX2_ SCC F-CUP 1.00 1.05 99110-S8100 \xf1\xa01.05', b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04', + b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04', + b'\xf1\x00LX2_ SCC FHCUP 1.00 1.05 99110-S8100 \xf1\xa01.05', ], (Ecu.esp, 0x7d1, None): [ b'\xf1\x00LX ESC \v 102\x19\x05\a 58910-S8330\xf1\xa01.02', b'\xf1\x00LX ESC \v 103\x19\t\x10 58910-S8360\xf1\xa01.03', b'\xf1\x00LX ESC \x01 103\x19\t\x10 58910-S8360\xf1\xa01.03', b'\xf1\x00LX ESC \x01 103\x31\t\020 58910-S8360\xf1\xa01.03', + b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330\xf1\xa01.01', b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330', + b'\xf1\x00LX ESC \x0b 103\x19\t\x10 58910-S8360', + b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360\xf1\xa01.04', + b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360\xf1\xa01.00', + b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360\xf1\xa01.01', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00', @@ -319,18 +409,39 @@ FW_VERSIONS = { (Ecu.eps, 0x7d4, None): [ b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103', # modified firmware b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103', + b'\xf1\x00ON MDPS C 1.00 1.00 56340-S9000 8B13', + b'\xf1\x00ON MDPS C 1.00 1.01 56340-S9000 9201', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.03 99211-S8100 190125', b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.05 99211-S8100 190909', + b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 200422', b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 200903', + b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 181105', + b'\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 200720', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28', + b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6', b'\xf1\x87LBLUFN650868KF36\xa9\x98\x89\x88\xa8\x88\x88\x88h\x99\xa6\x89fw\x86gw\x88\x97x\xaa\x7f\xf6\xff\xbb\xbb\x8f\xff+\x82\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', b'\xf1\x87LBLUFN655162KF36\x98\x88\x88\x88\x98\x88\x88\x88x\x99\xa7\x89x\x99\xa7\x89x\x99\x97\x89g\x7f\xf7\xffwU_\xff\xe9!\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', b'\xf1\x87LBLUFN731381KF36\xb9\x99\x89\x98\x98\x88\x88\x88\x89\x99\xa8\x99\x88\x99\xa8\x89\x88\x88\x98\x88V\177\xf6\xff\x99w\x8f\xff\xad\xd8\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\000bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', + b'\xf1\x87LDKVBN382172KF26\x98\x88\x88\x88\xa8\x88\x88\x88x\x99\xa7\x89\x87\x88\x98x\x98\x99\xa9\x89\xa5_\xf6\xffDDO\xff\xcd\x16\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7', b'\xf1\x87LDKVBN424201KF26\xba\xaa\x9a\xa9\x99\x99\x89\x98\x89\x99\xa8\x99\x88\x99\x98\x89\x88\x99\xa8\x89v\x7f\xf7\xffwf_\xffq\xa6\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7', + b'\xf1\x87LDKVBN540766KF37\x87wgv\x87w\x87xx\x99\x97\x89v\x88\x97h\x88\x88\x88\x88x\x7f\xf6\xffvUo\xff\xd3\x01\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7', b'\xf1\x87LDLVBN560098KF26\x86fff\x87vgfg\x88\x96xfw\x86gfw\x86g\x95\xf6\xffeU_\xff\x92c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7', + b'\xf1\x87LDLVBN645817KF37\x87www\x98\x87xwx\x99\x97\x89\x99\x99\x99\x99g\x88\x96x\xb6_\xf7\xff\x98fo\xff\xe2\x86\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN662115KF37\x98\x88\x88\x88\xa8\x88\x88\x88x\x99\x97\x89x\x99\xa7\x89\x88\x99\xa8\x89\x88\x7f\xf7\xfffD_\xff\xdc\x84\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN667933KF37\xb9\x99\x89\x98\xb9\x99\x99\x99x\x88\x87\x88w\x88\x87x\x88\x88\x98\x88\xcbo\xf7\xffe3/\xffQ!\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN673087KF37\x97www\x86fvgx\x99\x97\x89\x99\xaa\xa9\x9ag\x88\x86x\xe9_\xf8\xff\x98w\x7f\xff"\xad\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN681363KF37\x98\x88\x88\x88\x97x\x87\x88y\xaa\xa7\x9a\x88\x88\x98\x88\x88\x88\x88\x88vo\xf6\xffvD\x7f\xff%v\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN713890KF26\xb9\x99\x89\x98\xa9\x99\x99\x99x\x99\x97\x89\x88\x99\xa8\x89\x88\x99\xb8\x89Do\xf7\xff\xa9\x88o\xffs\r\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN750044KF37\xca\xa9\x8a\x98\xa7wwwy\xaa\xb7\x9ag\x88\x96x\x88\x99\xa8\x89\xb9\x7f\xf6\xff\xa8w\x7f\xff\xbe\xde\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN752612KF37\xba\xaa\x8a\xa8\x87w\x87xy\xaa\xa7\x9a\x88\x99\x98\x89x\x88\x97\x88\x96o\xf6\xffvU_\xffh\x1b\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDLVBN755553KF37\x87xw\x87\x97w\x87xy\x99\xa7\x99\x99\x99\xa9\x99Vw\x95gwo\xf6\xffwUO\xff\xb5T\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', + b'\xf1\x87LDMVBN778156KF37\x87vWe\xa9\x99\x99\x99y\x99\xb7\x99\x99\x99\x99\x99x\x99\x97\x89\xa8\x7f\xf8\xffwf\x7f\xff\x82_\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6', + b'\xf1\x87LDMVBN780576KF37\x98\x87hv\x97x\x97\x89x\x99\xa7\x89\x88\x99\x98\x89w\x88\x97x\x98\x7f\xf7\xff\xba\x88\x8f\xff\x1e0\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6', + b"\xf1\x87LBLUFN622950KF36\xa8\x88\x88\x88\x87w\x87xh\x99\x96\x89\x88\x99\x98\x89\x88\x99\x98\x89\x87o\xf6\xff\x98\x88o\xffx'\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8", ], }, CAR.VELOSTER: { @@ -367,33 +478,75 @@ FW_VERSIONS = { (Ecu.transmission, 0x7E1, None): [b'\xf1\x816U2V7051\000\000\xf1\0006U2V0_C2\000\0006U2V7051\000\000DCD0T14US1\000\000\000\000', ], (Ecu.esp, 0x7D1, None): [b'\xf1\000CD ESC \003 102\030\b\005 58920-J7350', ], }, + CAR.KIA_FORTE: { + (Ecu.eps, 0x7D4, None): [ + b'\xf1\x00BD MDPS C 1.00 1.08 56310M6300\x00 4BDDC108', + ], + (Ecu.fwdCamera, 0x7C4, None): [ + b'\xf1\x00BD LKAS AT USA LHD 1.00 1.04 95740-M6000 J33', + ], + (Ecu.fwdRadar, 0x7D0, None): [ + b'\xf1\x00BD__ SCC H-CUP 1.00 1.02 99110-M6000 \xf1\xa01.02', + ], + (Ecu.engine, 0x7e0, None): [ + b'\x01TBDM1NU06F200H01', + ], + (Ecu.esp, 0x7d1, None): [ + b'\xf1\x816VGRAH00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00\xf1\xa01.04', + ], + (Ecu.transmission, 0x7e1, None): [ + b"\xf1\x816U2VC051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DBD0T16SS0\xcf\x1e'\xc3", + ], + }, CAR.KONA_EV: { (Ecu.esp, 0x7D1, None): [ b'\xf1\x00OS IEB \r 105\x18\t\x18 58520-K4000\xf1\xa01.05', + b'\xf1\x00OS IEB \x01 212 \x11\x13 58520-K4000\xf1\xa02.12', + b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000\xf1\xa02.12', + b'\xf1\x00OS IEB \x03 210 \x02\x14 58520-K4000\xf1\xa02.10', b'\xf1\x00OS IEB \x03 212 \x11\x13 58520-K4000\xf1\xa02.12', ], - (Ecu.fwdCamera, 0x7C4, None): [b'\xf1\x00OSE LKAS AT EUR LHD 1.00 1.00 95740-K4100 W40', ], - (Ecu.eps, 0x7D4, None): [b'\xf1\x00OS MDPS C 1.00 1.04 56310K4050\x00 4OEDC104', ], - (Ecu.fwdRadar, 0x7D0, None): [b'\xf1\x00OSev SCC F-CUP 1.00 1.01 99110-K4000 \xf1\xa01.01', ], + (Ecu.fwdCamera, 0x7C4, None): [ + b'\xf1\x00OE2 LKAS AT EUR LHD 1.00 1.00 95740-K4200 200', + b'\xf1\x00OSE LKAS AT EUR LHD 1.00 1.00 95740-K4100 W40', + b'\xf1\x00OSE LKAS AT KOR LHD 1.00 1.00 95740-K4100 W40', + b'\xf1\x00OSE LKAS AT USA LHD 1.00 1.00 95740-K4300 W50', + ], + (Ecu.eps, 0x7D4, None): [ + b'\xf1\x00OS MDPS C 1.00 1.04 56310K4000\x00 4OEDC104', + b'\xf1\x00OS MDPS C 1.00 1.04 56310K4050\x00 4OEDC104', + ], + (Ecu.fwdRadar, 0x7D0, None): [ + b'\xf1\x00OSev SCC F-CUP 1.00 1.00 99110-K4100 \xf1\xa01.00', + b'\xf1\x00OSev SCC F-CUP 1.00 1.01 99110-K4000 \xf1\xa01.01', + b'\xf1\x00OSev SCC FNCUP 1.00 1.01 99110-K4000 \xf1\xa01.01', + ], }, CAR.KIA_NIRO_EV: { (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 ', b'\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 \xf1\xa01.00', + b'\xf1\x00DEev SCC F-CUP 1.00 1.03 96400-Q4100 \xf1\xa01.03', + b'\xf1\x00OSev SCC F-CUP 1.00 1.01 99110-K4000 \xf1\xa01.01', + b'\xf1\x8799110Q4000\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 \xf1\xa01.00', + b'\xf1\x8799110Q4100\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4100 \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', - b'\xf1\xa01.07', + b'\xf1\x00OS IEB \r 212 \x11\x13 58520-K4000\xf1\xa02.12', + b'\xf1\x00OS IEB \r 212 \x11\x13 58520-K4000', ], (Ecu.eps, 0x7D4, None): [ b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4000\x00 4DEEC105', b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4100\x00 4DEEC105', + b'\xf1\x00OS MDPS C 1.00 1.04 56310K4050\x00 4OEDC104', ], (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', + b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211', + b'\xf1\x00DEE MFC AT USA LHD 1.00 1.00 99211-Q4000 191211', + b'\xf1\x00DEE MFC AT USA LHD 1.00 1.03 95740-Q4000 180821', + b'\xf1\x00OSE LKAS AT EUR LHD 1.00 1.00 95740-K4100 W40', ], }, CAR.KIA_SELTOS: { @@ -416,11 +569,14 @@ FW_VERSIONS = { CAR.KIA_OPTIMA: { (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 '], (Ecu.esp, 0x7d1, None): [b'\xf1\x00JF ESC \v 11 \x18\x030 58920-D5180',], - (Ecu.engine, 0x7e0, None): [b'\x01TJFAJNU06F201H03'], + (Ecu.engine, 0x7e0, None): [ + b'\x01TJFAJNU06F201H03', + b'\xf1\x89F1JF600AISEIU702\xf1\x82F1JF600AISEIU702', + ], (Ecu.eps, 0x7d4, None): [b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409'], (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00JFA LKAS AT USA LHD 1.00 1.02 95895-D5000 h31'], (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJF0T16NL0\t\xd2GW'], - } + }, } CHECKSUM = { @@ -436,10 +592,6 @@ FEATURES = { # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 "use_fca": set([CAR.SONATA, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS]), - - "use_bsm": set([CAR.SONATA, CAR.PALISADE, CAR.HYUNDAI_GENESIS, CAR.GENESIS_G70, - CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.KONA, CAR.IONIQ_EV_2020, - CAR.SANTA_FE, CAR.KIA_NIRO_EV, CAR.KIA_SELTOS]), } EV_HYBRID = set([CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_NIRO_EV]) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 4d2de08e8..f049434bf 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -13,6 +13,9 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel GearShifter = car.CarState.GearShifter EventName = car.CarEvent.EventName + +# WARNING: this value was determined based on the model's training distribution, +# model predictions above this speed can be unpredictable MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS # 135 + 4 = 86 mph # generic car and radar interfaces @@ -119,7 +122,10 @@ class CarInterfaceBase(): if cs_out.steerError: events.add(EventName.steerUnavailable) elif cs_out.steerWarning: - events.add(EventName.steerTempUnavailable) + if cs_out.steeringPressed: + events.add(EventName.steerTempUnavailableUserOverride) + else: + events.add(EventName.steerTempUnavailable) # Disable on rising edge of gas or brake. Also disable on brake when speed > 0. # Optionally allow to press gas at zero speed to resume. diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 36a0495fd..5d9e9c9bb 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -23,9 +23,9 @@ class CarController(): CS.out.steeringTorque, CarControllerParams) self.steer_rate_limited = new_steer != apply_steer - if CS.out.standstill and frame % 20 == 0: + if CS.out.standstill and frame % 5 == 0: # Mazda Stop and Go requires a RES button (or gas) press if the car stops more than 3 seconds - # Send Resume button at 5hz if we're engaged at standstill to support full stop and go! + # Send Resume button at 20hz if we're engaged at standstill to support full stop and go! # TODO: improve the resume trigger logic by looking at actual radar data can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, Buttons.RESUME)) else: diff --git a/selfdrive/car/mazda/mazdacan.py b/selfdrive/car/mazda/mazdacan.py index dabbd2129..456f7f672 100644 --- a/selfdrive/car/mazda/mazdacan.py +++ b/selfdrive/car/mazda/mazdacan.py @@ -13,8 +13,10 @@ def create_steering_control(packer, car_fingerprint, frame, apply_steer, lkas): lnv = 0 er2 = int(lkas["ERR_BIT_2"]) - steering_angle = int(lkas["STEERING_ANGLE"]) - b2 = int(lkas["ANGLE_ENABLED"]) + # Some older models do have these, newer models don't. + # Either way, they all work just fine if set to zero. + steering_angle = 0 + b2 = 0 tmp = steering_angle + 2048 ahi = tmp >> 10 diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 3060cef5f..60b9a8b58 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -61,7 +61,7 @@ FINGERPRINTS = { CAR.Mazda3: [ # Mazda 3 2017 { - 19: 5, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 605: 8, 606: 8, 607: 8, 628: 8, 832: 8, 863: 8, 865: 8, 866: 8, 867: 8, 868: 8, 869: 8, 870: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1070: 8, 1078: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1169: 8, 1170: 8, 1173: 8, 1177: 8, 1180: 8, 1182: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1243: 8, 1244: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1270: 8, 1271: 8, 1272: 8, 1274: 8, 1275: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1456: 8, 1479: 8, 2015: 8, 2024: 8, 2025: 8 + 19: 5, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 138: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 522: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 605: 8, 606: 8, 607: 8, 628: 8, 832: 8, 863: 8, 865: 8, 866: 8, 867: 8, 868: 8, 869: 8, 870: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1070: 8, 1078: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1169: 8, 1170: 8, 1173: 8, 1177: 8, 1180: 8, 1182: 8, 1183: 8, 1232: 8, 1233: 8, 1234: 8, 1235: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8,1240: 8, 1241: 8, 1242: 8, 1243: 8, 1244: 8, 1246: 8, 1247: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1270: 8, 1271: 8, 1272: 8, 1274: 8, 1275: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1456: 8, 1479: 8, 2015: 8, 2024: 8, 2025: 8 }, # Mazda 6 2017 GT diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py index 67ee422bc..45a4e6935 100644 --- a/selfdrive/car/nissan/carstate.py +++ b/selfdrive/car/nissan/carstate.py @@ -146,10 +146,13 @@ class CarState(CarStateBase): checks = [ # sig_address, frequency + ("STEER_ANGLE_SENSOR", 100), ("WHEEL_SPEEDS_REAR", 50), ("WHEEL_SPEEDS_FRONT", 50), - ("STEER_ANGLE_SENSOR", 100), + ("ESP", 25), + ("GEARBOX", 25), ("DOORS_LIGHTS", 10), + ("LIGHTS", 10), ] if CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA]: @@ -201,6 +204,9 @@ class CarState(CarStateBase): checks += [ ("BRAKE_PEDAL", 100), ("CRUISE_THROTTLE", 50), + ("CANCEL_MSG", 50), + ("HUD_SETTINGS", 25), + ("SEATBELT", 10), ] if CP.carFingerprint == CAR.ALTIMA: @@ -241,6 +247,7 @@ class CarState(CarStateBase): ("CRUISE_ON", "PRO_PILOT", 0), ] checks = [ + ("LKAS", 100), ("PRO_PILOT", 100), ] else: @@ -327,7 +334,11 @@ class CarState(CarStateBase): ] checks = [ + ("PROPILOT_HUD_INFO_MSG", 2), + ("LKAS_SETTINGS", 10), ("CRUISE_STATE", 50), + ("PROPILOT_HUD", 50), + ("LKAS", 100), ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) @@ -341,7 +352,9 @@ class CarState(CarStateBase): signals += [ ("CRUISE_ON", "PRO_PILOT", 0), ] - + checks += [ + ("PRO_PILOT", 100), + ] elif CP.carFingerprint == CAR.ALTIMA: signals += [ ("STEER_TORQUE_DRIVER", "STEER_TORQUE_SENSOR", 0), diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 39ce707d5..1bd8d8d80 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -39,9 +39,6 @@ FINGERPRINTS = { }, ], CAR.LEAF_IC: [ - { - 2: 5, 42: 6, 264: 3, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 643: 5, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 724: 6, 758: 3, 761: 2, 783: 3, 852: 8, 853: 8, 856: 8, 861: 8, 943: 8, 944: 1, 976: 6, 1001: 6, 1008: 7, 1011: 7, 1057: 3, 1227: 8, 1228: 8, 1229: 8, 1261: 5, 1342: 1, 1354: 8, 1361: 8, 1402: 8, 1459: 8, 1477: 8, 1497: 3, 1514: 6, 1549: 8, 1573: 6 - }, { 2: 5, 42: 6, 264: 3, 282: 8, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 643: 5, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 756: 5, 758: 3, 761: 2, 783: 3, 830: 2, 852: 8, 853: 8, 856: 8, 861: 8, 943: 8, 944: 1, 1001: 6, 1057: 3, 1227: 8, 1228: 8, 1229: 8, 1342: 1, 1354: 8, 1361: 8, 1459: 8, 1477: 8, 1497: 3, 1514: 6, 1549: 8, 1573: 6, 1792: 8, 1821: 8, 1822: 8, 1837: 8, 1838: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2015: 8, 2016: 8, 2017: 8 }, diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index 1ad6bc75f..1eb7699f7 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -37,8 +37,9 @@ class CarState(CarStateBase): ret.leftBlinker, ret.rightBlinker = self.update_blinker(50, cp.vl["Dashlights"]['LEFT_BLINKER'], cp.vl["Dashlights"]['RIGHT_BLINKER']) - ret.leftBlindspot = (cp.vl["BSD_RCTA"]['L_ADJACENT'] == 1) or (cp.vl["BSD_RCTA"]['L_APPROACHING'] == 1) - ret.rightBlindspot = (cp.vl["BSD_RCTA"]['R_ADJACENT'] == 1) or (cp.vl["BSD_RCTA"]['R_APPROACHING'] == 1) + if self.CP.enableBsm: + ret.leftBlindspot = (cp.vl["BSD_RCTA"]['L_ADJACENT'] == 1) or (cp.vl["BSD_RCTA"]['L_APPROACHING'] == 1) + ret.rightBlindspot = (cp.vl["BSD_RCTA"]['R_ADJACENT'] == 1) or (cp.vl["BSD_RCTA"]['R_APPROACHING'] == 1) can_gear = int(cp.vl["Transmission"]['Gear']) ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) @@ -102,10 +103,6 @@ class CarState(CarStateBase): ("DOOR_OPEN_RL", "BodyInfo", 1), ("Units", "Dash_State", 1), ("Gear", "Transmission", 0), - ("L_ADJACENT", "BSD_RCTA", 0), - ("R_ADJACENT", "BSD_RCTA", 0), - ("L_APPROACHING", "BSD_RCTA", 0), - ("R_APPROACHING", "BSD_RCTA", 0), ] checks = [ @@ -116,8 +113,21 @@ class CarState(CarStateBase): ("Wheel_Speeds", 50), ("Transmission", 100), ("Steering_Torque", 50), + ("Dash_State", 1), + ("BodyInfo", 1), ] + if CP.enableBsm: + signals += [ + ("L_ADJACENT", "BSD_RCTA", 0), + ("R_ADJACENT", "BSD_RCTA", 0), + ("L_APPROACHING", "BSD_RCTA", 0), + ("R_APPROACHING", "BSD_RCTA", 0), + ] + checks += [ + ("BSD_RCTA", 17), + ] + if CP.carFingerprint in PREGLOBAL_CARS: signals += [ ("LKA_Lockout", "Steering_Torque", 0), diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 0cfb6fb49..bc5502f48 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -27,6 +27,7 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = candidate in PREGLOBAL_CARS ret.enableCamera = True + ret.enableBsm = 0x228 in fingerprint[0] ret.steerRateCost = 0.7 ret.steerLimitTimer = 0.4 diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 60d5f5ed7..7f603cb42 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -1,70 +1,69 @@ #!/usr/bin/env python3 import unittest import importlib +from parameterized import parameterized + +from cereal import car from selfdrive.car.fingerprints import all_known_cars from selfdrive.car.car_helpers import interfaces from selfdrive.car.fingerprints import _FINGERPRINTS as FINGERPRINTS -from cereal import car - - class TestCarInterfaces(unittest.TestCase): - def test_car_interfaces(self): - all_cars = all_known_cars() - for car_name in all_cars: - print(car_name) - fingerprint = FINGERPRINTS[car_name][0] + @parameterized.expand([(car,) for car in all_known_cars()]) + def test_car_interfaces(self, car_name): + print(car_name) + fingerprint = FINGERPRINTS[car_name][0] - CarInterface, CarController, CarState = interfaces[car_name] - fingerprints = { - 0: fingerprint, - 1: fingerprint, - 2: fingerprint, - } + CarInterface, CarController, CarState = interfaces[car_name] + fingerprints = { + 0: fingerprint, + 1: fingerprint, + 2: fingerprint, + } - car_fw = [] + car_fw = [] - car_params = CarInterface.get_params(car_name, fingerprints, car_fw) - car_interface = CarInterface(car_params, CarController, CarState) - assert car_params - assert car_interface + car_params = CarInterface.get_params(car_name, fingerprints, car_fw) + car_interface = CarInterface(car_params, CarController, CarState) + assert car_params + assert car_interface - self.assertGreater(car_params.mass, 1) - self.assertGreater(car_params.steerRateCost, 1e-3) + self.assertGreater(car_params.mass, 1) + self.assertGreater(car_params.steerRateCost, 1e-3) - if car_params.steerControlType != car.CarParams.SteerControlType.angle: - tuning = car_params.lateralTuning.which() - if tuning == 'pid': - self.assertTrue(len(car_params.lateralTuning.pid.kpV)) - elif tuning == 'lqr': - self.assertTrue(len(car_params.lateralTuning.lqr.a)) - elif tuning == 'indi': - self.assertTrue(len(car_params.lateralTuning.indi.outerLoopGainV)) + if car_params.steerControlType != car.CarParams.SteerControlType.angle: + tuning = car_params.lateralTuning.which() + if tuning == 'pid': + self.assertTrue(len(car_params.lateralTuning.pid.kpV)) + elif tuning == 'lqr': + self.assertTrue(len(car_params.lateralTuning.lqr.a)) + elif tuning == 'indi': + self.assertTrue(len(car_params.lateralTuning.indi.outerLoopGainV)) - # Run car interface - CC = car.CarControl.new_message() - for _ in range(10): - car_interface.update(CC, []) - car_interface.apply(CC) - car_interface.apply(CC) + # Run car interface + CC = car.CarControl.new_message() + for _ in range(10): + car_interface.update(CC, []) + car_interface.apply(CC) + car_interface.apply(CC) - CC = car.CarControl.new_message() - CC.enabled = True - for _ in range(10): - car_interface.update(CC, []) - car_interface.apply(CC) - car_interface.apply(CC) + CC = car.CarControl.new_message() + CC.enabled = True + for _ in range(10): + car_interface.update(CC, []) + car_interface.apply(CC) + car_interface.apply(CC) - # Test radar interface - RadarInterface = importlib.import_module('selfdrive.car.%s.radar_interface' % car_params.carName).RadarInterface - radar_interface = RadarInterface(car_params) - assert radar_interface + # Test radar interface + RadarInterface = importlib.import_module('selfdrive.car.%s.radar_interface' % car_params.carName).RadarInterface + radar_interface = RadarInterface(car_params) + assert radar_interface - # Run radar interface once - radar_interface.update([]) - if not car_params.radarOffCan and hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): - radar_interface._update([radar_interface.trigger_msg]) + # Run radar interface once + radar_interface.update([]) + if not car_params.radarOffCan and hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): + radar_interface._update([radar_interface.trigger_msg]) if __name__ == "__main__": unittest.main() diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 7152aa73a..c961288aa 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -3,8 +3,8 @@ from common.numpy_fast import clip from selfdrive.car import apply_toyota_steer_torque_limits, create_gas_command, make_can_msg from selfdrive.car.toyota.toyotacan import create_steer_command, create_ui_command, \ create_accel_command, create_acc_cancel_command, \ - create_fcw_command -from selfdrive.car.toyota.values import Ecu, CAR, STATIC_MSGS, NO_STOP_TIMER_CAR, CarControllerParams + create_fcw_command, create_lta_steer_command +from selfdrive.car.toyota.values import Ecu, CAR, STATIC_MSGS, NO_STOP_TIMER_CAR, TSS2_CAR, CarControllerParams from opendbc.can.packer import CANPacker VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -99,6 +99,8 @@ class CarController(): # on consecutive messages if Ecu.fwdCamera in self.fake_ecus: can_sends.append(create_steer_command(self.packer, apply_steer, apply_steer_req, frame)) + if frame % 2 == 0 and CS.CP.carFingerprint in TSS2_CAR: + can_sends.append(create_lta_steer_command(self.packer, 0, 0, frame // 2)) # LTA mode. Set ret.steerControlType = car.CarParams.SteerControlType.angle and whitelist 0x191 in the panda # if frame % 2 == 0: diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 42bce1c48..ca2a2bcf8 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine from selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser from selfdrive.config import Conversions as CV -from selfdrive.car.toyota.values import CAR, DBC, STEER_THRESHOLD, TSS2_CAR, NO_STOP_TIMER_CAR +from selfdrive.car.toyota.values import CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR class CarState(CarStateBase): @@ -90,17 +90,14 @@ class CarState(CarStateBase): ret.cruiseState.enabled = bool(cp.vl["PCM_CRUISE"]['CRUISE_ACTIVE']) ret.cruiseState.nonAdaptive = cp.vl["PCM_CRUISE"]['CRUISE_STATE'] in [1, 2, 3, 4, 5, 6] - if self.CP.carFingerprint == CAR.PRIUS: - ret.genericToggle = cp.vl["AUTOPARK_STATUS"]['STATE'] != 0 - else: - ret.genericToggle = bool(cp.vl["LIGHT_STALK"]['AUTO_HIGH_BEAM']) + ret.genericToggle = bool(cp.vl["LIGHT_STALK"]['AUTO_HIGH_BEAM']) ret.stockAeb = bool(cp_cam.vl["PRE_COLLISION"]["PRECOLLISION_ACTIVE"] and cp_cam.vl["PRE_COLLISION"]["FORCE"] < -1e-5) ret.espDisabled = cp.vl["ESP_CONTROL"]['TC_DISABLED'] != 0 # 2 is standby, 10 is active. TODO: check that everything else is really a faulty state self.steer_state = cp.vl["EPS_STATUS"]['LKA_STATE'] - if self.CP.carFingerprint in TSS2_CAR: + if self.CP.enableBsm: ret.leftBlindspot = (cp.vl["BSM"]['L_ADJACENT'] == 1) or (cp.vl["BSM"]['L_APPROACHING'] == 1) ret.rightBlindspot = (cp.vl["BSM"]['R_ADJACENT'] == 1) or (cp.vl["BSM"]['R_APPROACHING'] == 1) @@ -140,13 +137,18 @@ class CarState(CarStateBase): ] checks = [ + ("GEAR_PACKET", 1), + ("LIGHT_STALK", 1), + ("STEERING_LEVERS", 0.15), + ("SEATS_DOORS", 3), + ("ESP_CONTROL", 3), + ("EPS_STATUS", 25), ("BRAKE_MODULE", 40), ("GAS_PEDAL", 33), ("WHEEL_SPEEDS", 80), ("STEER_ANGLE_SENSOR", 80), ("PCM_CRUISE", 33), ("STEER_TORQUE_SENSOR", 50), - ("EPS_STATUS", 25), ] if CP.carFingerprint == CAR.LEXUS_IS: @@ -159,20 +161,22 @@ class CarState(CarStateBase): signals.append(("LOW_SPEED_LOCKOUT", "PCM_CRUISE_2", 0)) checks.append(("PCM_CRUISE_2", 33)) - if CP.carFingerprint == CAR.PRIUS: - signals += [("STATE", "AUTOPARK_STATUS", 0)] - # add gas interceptor reading if we are using it if CP.enableGasInterceptor: signals.append(("INTERCEPTOR_GAS", "GAS_SENSOR", 0)) signals.append(("INTERCEPTOR_GAS2", "GAS_SENSOR", 0)) checks.append(("GAS_SENSOR", 50)) - if CP.carFingerprint in TSS2_CAR: - signals += [("L_ADJACENT", "BSM", 0)] - signals += [("L_APPROACHING", "BSM", 0)] - signals += [("R_ADJACENT", "BSM", 0)] - signals += [("R_APPROACHING", "BSM", 0)] + if CP.enableBsm: + signals += [ + ("L_ADJACENT", "BSM", 0), + ("L_APPROACHING", "BSM", 0), + ("R_ADJACENT", "BSM", 0), + ("R_APPROACHING", "BSM", 0), + ] + checks += [ + ("BSM", 1) + ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) @@ -186,7 +190,8 @@ class CarState(CarStateBase): # use steering message to check if panda is connected to frc checks = [ - ("STEERING_LKA", 42) + ("STEERING_LKA", 42), + ("PRE_COLLISION", 0), # TODO: figure out why freq is inconsistent ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 082284a44..6a7201def 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 from cereal import car from selfdrive.config import Conversions as CV -from selfdrive.car.toyota.values import Ecu, ECU_FINGERPRINT, CAR, TSS2_CAR, NO_DSU_CAR, FINGERPRINTS, CarControllerParams -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint +from selfdrive.car.toyota.values import Ecu, CAR, TSS2_CAR, NO_DSU_CAR, CarControllerParams +from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.swaglog import cloudlog from selfdrive.car.interfaces import CarInterfaceBase @@ -25,7 +25,7 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 # Improved longitudinal tune - if candidate in [CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.RAV4_TSS2, CAR.RAV4H_TSS2]: + if candidate in [CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.RAV4_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_NX_TSS2]: ret.longitudinalTuning.deadzoneBP = [0., 8.05] ret.longitudinalTuning.deadzoneV = [.0, .14] ret.longitudinalTuning.kpBP = [0., 5., 20.] @@ -278,7 +278,7 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]] ret.lateralTuning.pid.kf = 0.00007 - elif candidate in [CAR.LEXUS_NXH, CAR.LEXUS_NX]: + elif candidate in [CAR.LEXUS_NXH, CAR.LEXUS_NX, CAR.LEXUS_NX_TSS2]: stop_and_go = True ret.safetyParam = 73 ret.wheelbase = 2.66 @@ -298,6 +298,16 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.35], [0.15]] ret.lateralTuning.pid.kf = 0.00007818594 + elif candidate == CAR.MIRAI: + stop_and_go = True + ret.safetyParam = 73 + ret.wheelbase = 2.91 + ret.steerRatio = 14.8 + tire_stiffness_factor = 0.8 + ret.mass = 4300. * CV.LB_TO_KG + STD_CARGO_KG + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] + ret.lateralTuning.pid.kf = 0.00006 + ret.steerRateCost = 1. ret.centerToFront = ret.wheelbase * 0.44 @@ -311,15 +321,15 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor=tire_stiffness_factor) ret.enableCamera = True + ret.enableBsm = 0x3F6 in fingerprint[0] and candidate in TSS2_CAR # Detect smartDSU, which intercepts ACC_CMD from the DSU allowing openpilot to send it smartDsu = 0x2FF in fingerprint[0] - # TODO: use FW query for the enableDsu flag # In TSS2 cars the camera does long control - ret.enableDsu = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.dsu) and candidate not in NO_DSU_CAR + found_ecus = [fw.ecu for fw in car_fw] + ret.enableDsu = (len(found_ecus) > 0) and (Ecu.dsu not in found_ecus) and (candidate not in NO_DSU_CAR) ret.enableGasInterceptor = 0x201 in fingerprint[0] # if the smartDSU is detected, openpilot can send ACC_CMD (and the smartDSU will block it from the DSU) or not (the DSU is "connected") ret.openpilotLongitudinalControl = ret.enableCamera and (smartDsu or ret.enableDsu or candidate in TSS2_CAR) - cloudlog.warning("ECU Camera Simulated: %r", ret.enableCamera) cloudlog.warning("ECU DSU Simulated: %r", ret.enableDsu) cloudlog.warning("ECU Gas Interceptor: %r", ret.enableGasInterceptor) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 9c857f965..2e3d767ff 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -21,10 +21,10 @@ class CAR: RAV4H = "TOYOTA RAV4 HYBRID 2017" RAV4 = "TOYOTA RAV4 2017" COROLLA = "TOYOTA COROLLA 2017" - LEXUS_RX = "LEXUS RX 350 2016" + LEXUS_RX = "LEXUS RX 2016" LEXUS_RXH = "LEXUS RX HYBRID 2017" - LEXUS_RX_TSS2 = "LEXUS RX350 2020" - LEXUS_RXH_TSS2 = "LEXUS RX450 HYBRID 2020" + LEXUS_RX_TSS2 = "LEXUS RX 2020" + LEXUS_RXH_TSS2 = "LEXUS RX HYBRID 2020" CHR = "TOYOTA C-HR 2018" CHRH = "TOYOTA C-HR HYBRID 2018" CAMRY = "TOYOTA CAMRY 2018" @@ -40,14 +40,16 @@ class CAR: COROLLA_TSS2 = "TOYOTA COROLLA TSS2 2019" COROLLAH_TSS2 = "TOYOTA COROLLA HYBRID TSS2 2019" LEXUS_ES_TSS2 = "LEXUS ES 2019" - LEXUS_ESH_TSS2 = "LEXUS ES 300H 2019" - LEXUS_ESH = "LEXUS ES 300H 2018" - SIENNA = "TOYOTA SIENNA XLE 2018" - LEXUS_IS = "LEXUS IS300 2018" - LEXUS_CTH = "LEXUS CT 200H 2018" + LEXUS_ESH_TSS2 = "LEXUS ES HYBRID 2019" + LEXUS_ESH = "LEXUS ES HYBRID 2018" + SIENNA = "TOYOTA SIENNA 2018" + LEXUS_IS = "LEXUS IS 2018" + LEXUS_CTH = "LEXUS CT HYBRID 2018" RAV4H_TSS2 = "TOYOTA RAV4 HYBRID 2019" - LEXUS_NXH = "LEXUS NX300H 2018" - LEXUS_NX = "LEXUS NX300 2018" + LEXUS_NXH = "LEXUS NX HYBRID 2018" + LEXUS_NX = "LEXUS NX 2018" + LEXUS_NX_TSS2 = "LEXUS NX 2020" + MIRAI = "TOYOTA MIRAI 2021" # TSS 2.5 # addr: (ecu, cars, bus, 1/freq*100, vl) STATIC_MSGS = [ @@ -71,11 +73,6 @@ STATIC_MSGS = [ (0x4CB, Ecu.dsu, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.LEXUS_NXH, CAR.LEXUS_NX, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.AVALON, CAR.SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_ESH, CAR.LEXUS_RX), 0, 100, b'\x0c\x00\x00\x00\x00\x00\x00\x00'), ] -ECU_FINGERPRINT = { - Ecu.fwdCamera: [0x2e4], # steer torque cmd - Ecu.dsu: [0x283], # accel cmd -} - FINGERPRINTS = { CAR.RAV4: [{ @@ -287,28 +284,38 @@ FINGERPRINTS = { CAR.LEXUS_NX: [{ 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 658: 8, 705: 8, 725: 2, 740: 5, 764: 8, 800: 8, 810: 2, 812: 3, 818: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1006: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1195: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], + CAR.LEXUS_NX_TSS2: [{ + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 725: 2, 740: 5, 742: 8, 743: 8, 764: 8, 765: 8, 800: 8, 810: 2, 812: 3, 818: 8, 822: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 877: 8, 889: 8, 891: 8, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 987: 8, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1006: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1172: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1195: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1208: 8, 1212: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1585: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1775: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + }], CAR.PRIUS_TSS2: [{ 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 765: 8, 800: 8, 810: 2, 814: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1175: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1593: 8, 1595: 8, 1649: 8, 1653: 8, 1654: 8, 1655: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + }], + CAR.MIRAI: [{ + 15: 8, 36: 8, 37: 8, 164: 8, 166: 8, 170: 8, 180: 8, 203: 8, 295: 8, 401: 8, 426: 6, 466: 8, 467: 8, 494: 8, 495: 8, 550: 8, 552: 4, 560: 7, 562: 8, 581: 5, 608: 8, 610: 8, 643: 7, 664: 8, 665: 8, 666: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 789: 8, 791: 8, 800: 8, 810: 2, 812: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 870: 7, 871: 2, 877: 8, 881: 8, 889: 8, 891: 8, 892: 8, 893: 8, 894: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 955: 8, 956: 8, 971: 7, 983: 8, 984: 8, 987: 8, 998: 5, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1081: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1593: 8, 1595: 8, 1649: 8, 1653: 8, 1654: 8, 1655: 8, 1677: 8, 1745: 8, 1769: 8, 1770: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1792: 8, 1872: 8, 1880: 8, 1937: 8, 1945: 8, 1953: 8, 1961: 8, 1968: 8, 1976: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2008: 8, 2009: 8, 2015: 8, 2016: 8, 2017: 8 }] } # Don't use theses fingerprints for fingerprinting, they are still needed for ECU detection IGNORED_FINGERPRINTS = [CAR.RAV4H_TSS2, CAR.HIGHLANDERH_TSS2, CAR.LEXUS_RXH_TSS2, CAR.PRIUS_TSS2, - CAR.LEXUS_NX, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, CAR.LEXUS_ESH] + CAR.LEXUS_NX, CAR.LEXUS_NX_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, CAR.LEXUS_ESH, CAR.MIRAI] FW_VERSIONS = { CAR.AVALON: { (Ecu.esp, 0x7b0, None): [ + b'F152607060\x00\x00\x00\x00\x00\x00', b'F152607110\x00\x00\x00\x00\x00\x00', + b'F152607140\x00\x00\x00\x00\x00\x00', b'F152607171\x00\x00\x00\x00\x00\x00', b'F152607180\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'881510701300\x00\x00\x00\x00', b'881510703200\x00\x00\x00\x00', + b'881510705100\x00\x00\x00\x00', b'881510705200\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ + b'8965B41051\x00\x00\x00\x00\x00\x00', b'8965B41080\x00\x00\x00\x00\x00\x00', b'8965B41090\x00\x00\x00\x00\x00\x00', ], @@ -370,6 +377,7 @@ FW_VERSIONS = { b'F152606230\x00\x00\x00\x00\x00\x00', b'F152606270\x00\x00\x00\x00\x00\x00', b'F152606290\x00\x00\x00\x00\x00\x00', + b'F152606410\x00\x00\x00\x00\x00\x00', b'F152633540\x00\x00\x00\x00\x00\x00', b'F152633A10\x00\x00\x00\x00\x00\x00', b'F152633A20\x00\x00\x00\x00\x00\x00', @@ -395,8 +403,8 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F0601200 ', b'8646F0601300 ', + b'8646F0601400 ', b'8646F0603400 ', - b'8821F0604100 ', b'8646F0605000 ', b'8646F0606000 ', b'8646F0606100 ', @@ -405,8 +413,11 @@ FW_VERSIONS = { }, CAR.CAMRYH: { (Ecu.engine, 0x700, None): [ + b'\x018966333N1100\x00\x00\x00\x00', b'\x018966333N4300\x00\x00\x00\x00', b'\x018966333X0000\x00\x00\x00\x00', + b'\x018966333X4000\x00\x00\x00\x00', + b'\x01896633T16000\x00\x00\x00\x00', b'\x028966306B2100\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', b'\x028966306B2300\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', b'\x028966306N8100\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', @@ -433,10 +444,13 @@ FW_VERSIONS = { b'8821F0601200 ', b'8821F0601300 ', b'8821F0603400 ', + b'8821F0604000 ', b'8821F0604200 ', + b'8821F0605200 ', b'8821F0606200 ', b'8821F0607200 ', b'8821F0608000 ', + b'8821F0608200 ', b'8821F0609000 ', b'8821F0609100 ', ], @@ -454,10 +468,13 @@ FW_VERSIONS = { b'8821F0601200 ', b'8821F0601300 ', b'8821F0603400 ', + b'8821F0604000 ', b'8821F0604200 ', + b'8821F0605200 ', b'8821F0606200 ', b'8821F0607200 ', b'8821F0608000 ', + b'8821F0608200 ', b'8821F0609000 ', b'8821F0609100 ', ], @@ -465,6 +482,7 @@ FW_VERSIONS = { b'8646F0601200 ', b'8646F0601300 ', b'8646F0601400 ', + b'8646F0603400 ', b'8646F0603500 ', b'8646F0604100 ', b'8646F0605000 ', @@ -504,12 +522,14 @@ FW_VERSIONS = { ], (Ecu.engine, 0x700, None): [ b'\x018966306Q6000\x00\x00\x00\x00', + b'\x018966306Q7000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 15): [ b'\x018821F6201200\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 109): [ b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', + b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', ], }, CAR.CHR: { @@ -570,48 +590,57 @@ FW_VERSIONS = { }, CAR.CHRH: { (Ecu.engine, 0x700, None): [ - b'\x0289663F431000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', - b'\x0289663F423000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x0289663F405000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x0289663F418000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x0289663F423000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x0289663F431000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x0189663F438000\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ + b'F152610013\x00\x00\x00\x00\x00\x00', b'F152610040\x00\x00\x00\x00\x00\x00', b'F152610190\x00\x00\x00\x00\x00\x00', - b'F152610013\x00\x00\x00\x00\x00\x00', + b'F152610200\x00\x00\x00\x00\x00\x00', + b'F152610230\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ + b'8821FF402300 ', + b'8821FF402400 ', b'8821FF404000 ', b'8821FF406000 ', b'8821FF407100 ', ], (Ecu.eps, 0x7a1, None): [ b'8965B10011\x00\x00\x00\x00\x00\x00', + b'8965B10020\x00\x00\x00\x00\x00\x00', b'8965B10040\x00\x00\x00\x00\x00\x00', b'8965B10050\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821FF402300 ', + b'8821FF402400 ', b'8821FF404000 ', b'8821FF406000 ', b'8821FF407100 ', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646FF402100 ', b'8646FF404000 ', - b'8821FF406000 ', + b'8646FF406000 ', b'8646FF407000 ', ], }, CAR.COROLLA: { (Ecu.engine, 0x7e0, None): [ - b'\x01896630E88000\x00\x00\x00\x00', - b'\x0330ZC1200\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x0230ZC2000\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230ZC2100\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230ZC2200\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230ZC2300\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230ZC3000\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0230ZC3100\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230ZC3200\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230ZC3300\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0330ZC1200\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'881510201100\x00\x00\x00\x00', @@ -633,11 +662,11 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F0201101\x00\x00\x00\x00', b'8646F0201200\x00\x00\x00\x00', - b'8646F0E01300\x00\x00\x00\x00', ], }, CAR.COROLLA_TSS2: { (Ecu.engine, 0x700, None): [ + b'\x01896630ZG2000\x00\x00\x00\x00', b'\x01896630ZG5000\x00\x00\x00\x00', b'\x01896630ZG5100\x00\x00\x00\x00', b'\x01896630ZG5200\x00\x00\x00\x00', @@ -645,35 +674,39 @@ FW_VERSIONS = { b'\x01896630ZP2000\x00\x00\x00\x00', b'\x01896630ZQ5000\x00\x00\x00\x00', b'\x018966312L8000\x00\x00\x00\x00', + b'\x018966312M9000\x00\x00\x00\x00', b'\x018966312P9000\x00\x00\x00\x00', b'\x018966312P9100\x00\x00\x00\x00', b'\x018966312P9200\x00\x00\x00\x00', + b'\x018966312Q2300\x00\x00\x00\x00', b'\x018966312R0100\x00\x00\x00\x00', b'\x018966312R1000\x00\x00\x00\x00', b'\x018966312R1100\x00\x00\x00\x00', b'\x018966312R3100\x00\x00\x00\x00', + b'\x018966312S5000\x00\x00\x00\x00', b'\x018966312S7000\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'\x0230ZN4000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0235883000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x03312M3000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', b'\x03312N6000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x03312N6000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', - b'\x03312M3000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ - b'\x018965B1255000\x00\x00\x00\x00', - b'8965B12361\x00\x00\x00\x00\x00\x00', b'\x018965B12350\x00\x00\x00\x00\x00\x00', b'\x018965B12470\x00\x00\x00\x00\x00\x00', b'\x018965B12490\x00\x00\x00\x00\x00\x00', b'\x018965B12500\x00\x00\x00\x00\x00\x00', b'\x018965B12520\x00\x00\x00\x00\x00\x00', b'\x018965B12530\x00\x00\x00\x00\x00\x00', + b'\x018965B1255000\x00\x00\x00\x00', + b'8965B12361\x00\x00\x00\x00\x00\x00', + b'8965B58040\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ - b'F152602191\x00\x00\x00\x00\x00\x00', b'\x01F152602280\x00\x00\x00\x00\x00\x00', b'\x01F152602560\x00\x00\x00\x00\x00\x00', b'\x01F152602590\x00\x00\x00\x00\x00\x00', @@ -685,6 +718,9 @@ FW_VERSIONS = { b'\x01F152612B60\x00\x00\x00\x00\x00\x00', b'\x01F152612B61\x00\x00\x00\x00\x00\x00', b'\x01F152612B90\x00\x00\x00\x00\x00\x00', + b'\x01F152612C00\x00\x00\x00\x00\x00\x00', + b'F152602191\x00\x00\x00\x00\x00\x00', + b'F152658320\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301100\x00\x00\x00\x00', @@ -701,13 +737,16 @@ FW_VERSIONS = { b'\x028646F1202000\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1202200\x00\x00\x00\x008646G2601500\x00\x00\x00\x00', + b'\x028646F5803200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.COROLLAH_TSS2: { (Ecu.engine, 0x700, None): [ b'\x01896630ZJ1000\x00\x00\x00\x00', b'\x01896630ZU8000\x00\x00\x00\x00', - b'\x018966342M5000\x00\x00\x00\x00', + b'\x01896637624000\x00\x00\x00\x00', + b'\x01896637626000\x00\x00\x00\x00', + b'\x02896630ZN8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZQ3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZR2000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZT8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', @@ -718,8 +757,10 @@ FW_VERSIONS = { (Ecu.eps, 0x7a1, None): [ b'8965B12361\x00\x00\x00\x00\x00\x00', b'8965B12451\x00\x00\x00\x00\x00\x00', + b'8965B76012\x00\x00\x00\x00\x00\x00', b'\x018965B12350\x00\x00\x00\x00\x00\x00', b'\x018965B12470\x00\x00\x00\x00\x00\x00', + b'\x018965B12490\x00\x00\x00\x00\x00\x00', b'\x018965B12500\x00\x00\x00\x00\x00\x00', b'\x018965B12520\x00\x00\x00\x00\x00\x00', b'\x018965B12530\x00\x00\x00\x00\x00\x00', @@ -731,10 +772,13 @@ FW_VERSIONS = { b'F152612700\x00\x00\x00\x00\x00\x00', b'F152612790\x00\x00\x00\x00\x00\x00', b'F152612800\x00\x00\x00\x00\x00\x00', + b'F152612820\x00\x00\x00\x00\x00\x00', b'F152612840\x00\x00\x00\x00\x00\x00', + b'F152612A00\x00\x00\x00\x00\x00\x00', b'F152612A10\x00\x00\x00\x00\x00\x00', b'F152642540\x00\x00\x00\x00\x00\x00', - b'F152612A00\x00\x00\x00\x00\x00\x00', + b'F152676293\x00\x00\x00\x00\x00\x00', + b'F152676303\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301100\x00\x00\x00\x00', @@ -743,28 +787,35 @@ FW_VERSIONS = { b'\x018821F3301400\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F12010D0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F1201100\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F1201300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1201400\x00\x00\x00\x008646G2601500\x00\x00\x00\x00', b'\x028646F1202000\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F7603100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', ], }, CAR.HIGHLANDER: { (Ecu.engine, 0x700, None): [ b'\x01896630E09000\x00\x00\x00\x00', + b'\x01896630E43000\x00\x00\x00\x00', b'\x01896630E43100\x00\x00\x00\x00', b'\x01896630E43200\x00\x00\x00\x00', b'\x01896630E44200\x00\x00\x00\x00', b'\x01896630E45000\x00\x00\x00\x00', b'\x01896630E45100\x00\x00\x00\x00', b'\x01896630E45200\x00\x00\x00\x00', + b'\x01896630E46200\x00\x00\x00\x00', b'\x01896630E74000\x00\x00\x00\x00', + b'\x01896630E75000\x00\x00\x00\x00', b'\x01896630E76000\x00\x00\x00\x00', + b'\x01896630E77000\x00\x00\x00\x00', b'\x01896630E83000\x00\x00\x00\x00', b'\x01896630E84000\x00\x00\x00\x00', b'\x01896630E85000\x00\x00\x00\x00', + b'\x01896630E86000\x00\x00\x00\x00', b'\x01896630E88000\x00\x00\x00\x00', b'\x01896630EA0000\x00\x00\x00\x00', ], @@ -797,6 +848,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7e0, None): [ b'\x0230E40000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0230E40100\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230EA2000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0230EA2100\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', ], @@ -819,13 +871,15 @@ FW_VERSIONS = { b'\x01F15260E110\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ + b'\x01896630E62100\x00\x00\x00\x00', b'\x01896630E62200\x00\x00\x00\x00', b'\x01896630E64100\x00\x00\x00\x00', b'\x01896630E64200\x00\x00\x00\x00', + b'\x01896630EB1000\x00\x00\x00\x00', + b'\x01896630EB1100\x00\x00\x00\x00', b'\x01896630EB2000\x00\x00\x00\x00', b'\x01896630EB2100\x00\x00\x00\x00', - b'\x01896630EB1100\x00\x00\x00\x00', - b'\x01896630EB1000\x00\x00\x00\x00', + b'\x01896630EB2200\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301400\x00\x00\x00\x00', @@ -863,29 +917,35 @@ FW_VERSIONS = { CAR.LEXUS_IS: { (Ecu.engine, 0x700, None): [ b'\x018966353M7100\x00\x00\x00\x00', + b'\x018966353Q2000\x00\x00\x00\x00', b'\x018966353Q2300\x00\x00\x00\x00', b'\x018966353R1100\x00\x00\x00\x00', b'\x018966353R7100\x00\x00\x00\x00', b'\x018966353R8100\x00\x00\x00\x00', + b'\x018966353Q4000\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ + b'\x0232480000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02353P7000\x00\x00\x00\x00\x00\x00\x00\x00530J5000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02353P9000\x00\x00\x00\x00\x00\x00\x00\x00553C1000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ - b'F152653330\x00\x00\x00\x00\x00\x00', b'F152653301\x00\x00\x00\x00\x00\x00', + b'F152653310\x00\x00\x00\x00\x00\x00', + b'F152653330\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ + b'881515306200\x00\x00\x00\x00', b'881515306400\x00\x00\x00\x00', b'881515306500\x00\x00\x00\x00', - b'881515306200\x00\x00\x00\x00', + b'881515307400\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B53270\x00\x00\x00\x00\x00\x00', b'8965B53271\x00\x00\x00\x00\x00\x00', b'8965B53280\x00\x00\x00\x00\x00\x00', b'8965B53281\x00\x00\x00\x00\x00\x00', + b'8965B53311\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4702300\x00\x00\x00\x00', @@ -902,23 +962,30 @@ FW_VERSIONS = { b'\x02896634761000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634761100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634761200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634762000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634763000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634763100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634765000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634765100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634769100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634769200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634770000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634774000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634774100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634774200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634782000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634784000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x028966347A0000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966347A5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966347A8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', - b'\x02896634765100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x028966347B0000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x03896634759100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634759200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634759200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', b'\x03896634759300\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', b'\x03896634760000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701002\x00\x00\x00\x00', b'\x03896634760000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', + b'\x03896634760000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', b'\x03896634760100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634760200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634760200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', @@ -927,9 +994,11 @@ FW_VERSIONS = { b'\x03896634768000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703002\x00\x00\x00\x00', b'\x03896634768100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703002\x00\x00\x00\x00', b'\x03896634785000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4705001\x00\x00\x00\x00', + b'\x03896634785000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', b'\x03896634786000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4705001\x00\x00\x00\x00', b'\x03896634786000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', b'\x03896634789000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703002\x00\x00\x00\x00', + b'\x038966347A3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x038966347A3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707001\x00\x00\x00\x00', b'\x038966347B6000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', b'\x038966347B7000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', @@ -951,6 +1020,7 @@ FW_VERSIONS = { b'F152647417\x00\x00\x00\x00\x00\x00', b'F152647470\x00\x00\x00\x00\x00\x00', b'F152647490\x00\x00\x00\x00\x00\x00', + b'F152647683\x00\x00\x00\x00\x00\x00', b'F152647684\x00\x00\x00\x00\x00\x00', b'F152647862\x00\x00\x00\x00\x00\x00', b'F152647863\x00\x00\x00\x00\x00\x00', @@ -970,7 +1040,6 @@ FW_VERSIONS = { b'8821F4702300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ - b'8646F4201200\x00\x00\x00\x00', b'8646F4701300\x00\x00\x00\x00', b'8646F4702001\x00\x00\x00\x00', b'8646F4702100\x00\x00\x00\x00', @@ -991,9 +1060,10 @@ FW_VERSIONS = { b'\x02342Q4000\x00\x00\x00\x00\x00\x00\x00\x0054215000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ + b'8965B42063\x00\x00\x00\x00\x00\x00', + b'8965B42073\x00\x00\x00\x00\x00\x00', b'8965B42082\x00\x00\x00\x00\x00\x00', b'8965B42083\x00\x00\x00\x00\x00\x00', - b'8965B42063\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'F15260R102\x00\x00\x00\x00\x00\x00', @@ -1015,6 +1085,7 @@ FW_VERSIONS = { b'8646F4201200\x00\x00\x00\x00', b'8646F4202001\x00\x00\x00\x00', b'8646F4202100\x00\x00\x00\x00', + b'8646F4204000\x00\x00\x00\x00', ], }, CAR.RAV4H: { @@ -1022,15 +1093,17 @@ 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'8965B42102\x00\x00\x00\x00\x00\x00', b'8965B42103\x00\x00\x00\x00\x00\x00', + b'8965B42112\x00\x00\x00\x00\x00\x00', b'8965B42162\x00\x00\x00\x00\x00\x00', b'8965B42163\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'F152642090\x00\x00\x00\x00\x00\x00', + b'F152642110\x00\x00\x00\x00\x00\x00', b'F152642120\x00\x00\x00\x00\x00\x00', b'F152642400\x00\x00\x00\x00\x00\x00', ], @@ -1055,28 +1128,35 @@ FW_VERSIONS = { CAR.RAV4_TSS2: { (Ecu.engine, 0x700, None): [ b'\x01896630R58000\x00\x00\x00\x00', + b'\x01896630R58100\x00\x00\x00\x00', b'\x018966342E2000\x00\x00\x00\x00', b'\x018966342M8000\x00\x00\x00\x00', + b'\x018966342S9000\x00\x00\x00\x00', b'\x018966342T1000\x00\x00\x00\x00', b'\x018966342T6000\x00\x00\x00\x00', b'\x018966342T9000\x00\x00\x00\x00', b'\x018966342U4000\x00\x00\x00\x00', b'\x018966342U4100\x00\x00\x00\x00', + b'\x018966342V3000\x00\x00\x00\x00', b'\x018966342V3100\x00\x00\x00\x00', b'\x018966342V3200\x00\x00\x00\x00', - b'\x018966342X5000\x00\x00\x00\x00', b'\x01896634A05000\x00\x00\x00\x00', b'\x01896634A19000\x00\x00\x00\x00', b'\x01896634A19100\x00\x00\x00\x00', b'\x01896634A20000\x00\x00\x00\x00', + b'\x01896634A20100\x00\x00\x00\x00', b'\x01896634A22000\x00\x00\x00\x00', + b'\x01896634A22100\x00\x00\x00\x00', + b'\x01896634A30000\x00\x00\x00\x00', b'\x01896634A44000\x00\x00\x00\x00', b'\x01896634A45000\x00\x00\x00\x00', b'\x01896634A46000\x00\x00\x00\x00', + b'\x028966342M7000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x028966342T0000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x028966342V1000\x00\x00\x00\x00897CF1202001\x00\x00\x00\x00', b'\x028966342Y8000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x02896634A18000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', + b'\x02896634A18100\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x02896634A43000\x00\x00\x00\x00897CF4201001\x00\x00\x00\x00', b'\x02896634A47000\x00\x00\x00\x00897CF4201001\x00\x00\x00\x00', ], @@ -1088,9 +1168,11 @@ FW_VERSIONS = { b'\x01F152642551\x00\x00\x00\x00\x00\x00', b'\x01F152642561\x00\x00\x00\x00\x00\x00', b'\x01F152642700\x00\x00\x00\x00\x00\x00', + b'\x01F152642701\x00\x00\x00\x00\x00\x00', b'\x01F152642710\x00\x00\x00\x00\x00\x00', b'\x01F152642711\x00\x00\x00\x00\x00\x00', b'\x01F152642750\x00\x00\x00\x00\x00\x00', + b'\x01F152642751\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B42170\x00\x00\x00\x00\x00\x00', @@ -1172,23 +1254,37 @@ FW_VERSIONS = { }, CAR.LEXUS_ES_TSS2: { (Ecu.engine, 0x700, None): [ - b'\x018966333T5100\x00\x00\x00\x00', + b'\x01896630EC9100\x00\x00\x00\x00', b'\x018966333T5000\x00\x00\x00\x00', + b'\x018966333T5100\x00\x00\x00\x00', + b'\x018966333X6000\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'\x01F152606281\x00\x00\x00\x00\x00\x00', + b'\x01F152606340\x00\x00\x00\x00\x00\x00', + b'\x01F15260E031\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B33252\x00\x00\x00\x00\x00\x00', + b'8965B33590\x00\x00\x00\x00\x00\x00', + b'8965B48271\x00\x00\x00\x00\x00\x00', ], - (Ecu.esp, 0x7b0, None): [b'\x01F152606281\x00\x00\x00\x00\x00\x00'], - (Ecu.eps, 0x7a1, None): [b'8965B33252\x00\x00\x00\x00\x00\x00'], (Ecu.fwdRadar, 0x750, 0xf): [ - b'\x018821F3301200\x00\x00\x00\x00', b'\x018821F3301100\x00\x00\x00\x00', + b'\x018821F3301200\x00\x00\x00\x00', + b'\x018821F3301400\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ - b'\x028646F3303200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F33030D0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', + b'\x028646F3303200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', + b'\x028646F3304100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F4810200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.SIENNA: { (Ecu.engine, 0x700, None): [ b'\x01896630832100\x00\x00\x00\x00', + b'\x01896630832200\x00\x00\x00\x00', b'\x01896630838000\x00\x00\x00\x00', b'\x01896630838100\x00\x00\x00\x00', b'\x01896630842000\x00\x00\x00\x00', @@ -1201,6 +1297,7 @@ FW_VERSIONS = { ], (Ecu.eps, 0x7a1, None): [ b'8965B45070\x00\x00\x00\x00\x00\x00', + b'8965B45080\x00\x00\x00\x00\x00\x00', b'8965B45082\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ @@ -1218,27 +1315,51 @@ FW_VERSIONS = { b'8646F0801100\x00\x00\x00\x00', ], }, + CAR.LEXUS_CTH: { + (Ecu.dsu, 0x791, None): [ + b'881517601100\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152676144\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x7e0, None): [ + b'\x0237635000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4702300\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F7601100\x00\x00\x00\x00', + ], + }, CAR.LEXUS_ESH_TSS2: { (Ecu.engine, 0x700, None): [ b'\x028966333S8000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966333T0100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966333V4000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', + b'\x02896633T09000\x00\x00\x00\x00897CF3307001\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'F152633423\x00\x00\x00\x00\x00\x00', b'F152633680\x00\x00\x00\x00\x00\x00', + b'F152633681\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B33252\x00\x00\x00\x00\x00\x00', b'8965B33590\x00\x00\x00\x00\x00\x00', + b'8965B33690\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301100\x00\x00\x00\x00', + b'\x018821F3301200\x00\x00\x00\x00', b'\x018821F3301300\x00\x00\x00\x00', + b'\x018821F3301400\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F33030D0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F3303100\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F3304100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F3304200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.LEXUS_ESH: { @@ -1248,13 +1369,18 @@ FW_VERSIONS = { (Ecu.esp, 0x7b0, None): [ b'F152633171\x00\x00\x00\x00\x00\x00', ], + (Ecu.dsu, 0x791, None): [ + b'881513310400\x00\x00\x00\x00', + ], (Ecu.eps, 0x7a1, None): [ b'8965B33512\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4701100\x00\x00\x00\x00', b'8821F4701300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F3302001\x00\x00\x00\x00', b'8646F3302200\x00\x00\x00\x00', ], }, @@ -1262,8 +1388,10 @@ FW_VERSIONS = { (Ecu.engine, 0x700, None): [ b'\x01896637851000\x00\x00\x00\x00', b'\x01896637852000\x00\x00\x00\x00', + b'\x01896637854000\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ + b'F152678130\x00\x00\x00\x00\x00\x00', b'F152678140\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ @@ -1274,12 +1402,30 @@ FW_VERSIONS = { b'8965B78080\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4702100\x00\x00\x00\x00', b'8821F4702300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F7801100\x00\x00\x00\x00', ], }, + CAR.LEXUS_NX_TSS2: { + (Ecu.engine, 0x700, None): [ + b'\x018966378B2100\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'\x01F152678221\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B78120\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b"\x018821F3301400\x00\x00\x00\x00", + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F78030A0\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + ], + }, CAR.LEXUS_NXH: { (Ecu.engine, 0x7e0, None): [ b'\x0237882000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', @@ -1310,17 +1456,19 @@ FW_VERSIONS = { }, CAR.LEXUS_RX: { (Ecu.engine, 0x700, None): [ + b'\x01896630E36200\x00\x00\x00\x00', + b'\x01896630E36300\x00\x00\x00\x00', b'\x01896630E37200\x00\x00\x00\x00', + b'\x01896630E37300\x00\x00\x00\x00', b'\x01896630E41000\x00\x00\x00\x00', b'\x01896630E41100\x00\x00\x00\x00', b'\x01896630E41200\x00\x00\x00\x00', - b'\x01896630E37300\x00\x00\x00\x00', - b'\x01896630E36300\x00\x00\x00\x00', - b'\x018966348R8500\x00\x00\x00\x00', - b'\x018966348W1300\x00\x00\x00\x00', + b'\x01896630EA4100\x00\x00\x00\x00', b'\x01896630EA4300\x00\x00\x00\x00', b'\x01896630EA6300\x00\x00\x00\x00', - b'\x01896630EA4100\x00\x00\x00\x00', + b'\x018966348R1300\x00\x00\x00\x00', + b'\x018966348R8500\x00\x00\x00\x00', + b'\x018966348W1300\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'F152648472\x00\x00\x00\x00\x00\x00', @@ -1359,9 +1507,12 @@ FW_VERSIONS = { }, CAR.LEXUS_RXH: { (Ecu.engine, 0x7e0, None): [ + b'\x02348J7000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348N0000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348Q4000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02348Q4100\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348T1100\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02348T3000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348V6000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348Z3000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', ], @@ -1370,6 +1521,7 @@ FW_VERSIONS = { b'F152648501\x00\x00\x00\x00\x00\x00', b'F152648502\x00\x00\x00\x00\x00\x00', b'F152648504\x00\x00\x00\x00\x00\x00', + b'F152648740\x00\x00\x00\x00\x00\x00', b'F152648A30\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ @@ -1380,6 +1532,7 @@ FW_VERSIONS = { (Ecu.eps, 0x7a1, None): [ b'8965B0E011\x00\x00\x00\x00\x00\x00', b'8965B0E012\x00\x00\x00\x00\x00\x00', + b'8965B48111\x00\x00\x00\x00\x00\x00', b'8965B48112\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ @@ -1390,6 +1543,7 @@ FW_VERSIONS = { ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F4801200\x00\x00\x00\x00', + b'8646F4802001\x00\x00\x00\x00', b'8646F4802100\x00\x00\x00\x00', b'8646F4802200\x00\x00\x00\x00', b'8646F4809000\x00\x00\x00\x00', @@ -1403,6 +1557,7 @@ FW_VERSIONS = { b'\x01896630EA9000\x00\x00\x00\x00', b'\x01896630ED0000\x00\x00\x00\x00', b'\x018966348W9000\x00\x00\x00\x00', + b'\x01896634D12100\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'\x01F152648801\x00\x00\x00\x00\x00\x00', @@ -1445,11 +1600,13 @@ FW_VERSIONS = { }, CAR.PRIUS_TSS2: { (Ecu.engine, 0x700, None): [ + b'\x028966347C8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x038966347C1000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710101\x00\x00\x00\x00', b'\x038966347C5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707101\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'F152647500\x00\x00\x00\x00\x00\x00', + b'F152647510\x00\x00\x00\x00\x00\x00', b'F152647520\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ @@ -1462,6 +1619,13 @@ FW_VERSIONS = { b'\x028646F4707000\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, + CAR.MIRAI: { + (Ecu.esp, 0x7D1, None): [b'\x01898A36203000\x00\x00\x00\x00',], + (Ecu.esp, 0x7B0, None): [b'\x01F15266203200\x00\x00\x00\x00',], # a second ESP ECU + (Ecu.eps, 0x7A1, None): [b'\x028965B6204100\x00\x00\x00\x008965B6203100\x00\x00\x00\x00',], + (Ecu.fwdRadar, 0x750, 0xf): [b'\x018821F6201200\x00\x00\x00\x00',], + (Ecu.fwdCamera, 0x750, 0x6d): [b'\x028646F6201400\x00\x00\x00\x008646G5301200\x00\x00\x00\x00',], + }, } STEER_THRESHOLD = 100 @@ -1498,13 +1662,16 @@ DBC = { CAR.RAV4H_TSS2: dbc_dict('toyota_nodsu_hybrid_pt_generated', 'toyota_tss2_adas'), CAR.LEXUS_NXH: dbc_dict('lexus_nx300h_2018_pt_generated', 'toyota_adas'), CAR.LEXUS_NX: dbc_dict('lexus_nx300_2018_pt_generated', 'toyota_adas'), + CAR.LEXUS_NX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.PRIUS_TSS2: dbc_dict('toyota_nodsu_hybrid_pt_generated', 'toyota_tss2_adas'), + CAR.MIRAI: dbc_dict('toyota_nodsu_hybrid_pt_generated', 'toyota_tss2_adas'), } # Toyota/Lexus Safety Sense 2.0 and 2.5 TSS2_CAR = set([CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, - CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2]) + CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, + CAR.MIRAI, CAR.LEXUS_NX_TSS2]) NO_DSU_CAR = TSS2_CAR | set([CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH]) diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 5bb5dcc10..1317ee769 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -20,7 +20,7 @@ class CarController(): self.steer_rate_limited = False - def update(self, enabled, CS, frame, actuators, visual_alert, audible_alert, leftLaneVisible, rightLaneVisible): + def update(self, enabled, CS, frame, actuators, visual_alert, left_lane_visible, right_lane_visible, left_lane_depart, right_lane_depart): """ Controls thread """ P = CarControllerParams @@ -110,16 +110,18 @@ class CarController(): # filters LDW_02 from the factory camera and OP emits LDW_02 at 10Hz. if frame % P.LDW_STEP == 0: - hcaEnabled = True if enabled and not CS.out.standstill else False - if visual_alert == car.CarControl.HUDControl.VisualAlert.steerRequired: hud_alert = MQB_LDW_MESSAGES["laneAssistTakeOverSilent"] else: hud_alert = MQB_LDW_MESSAGES["none"] - can_sends.append(volkswagencan.create_mqb_hud_control(self.packer_pt, CANBUS.pt, hcaEnabled, - CS.out.steeringPressed, hud_alert, leftLaneVisible, - rightLaneVisible)) + + can_sends.append(volkswagencan.create_mqb_hud_control(self.packer_pt, CANBUS.pt, enabled, + CS.out.steeringPressed, hud_alert, left_lane_visible, + right_lane_visible, CS.ldw_lane_warning_left, + CS.ldw_lane_warning_right, CS.ldw_side_dlc_tlc, + CS.ldw_dlc, CS.ldw_tlc, CS.out.standstill, + left_lane_depart, right_lane_depart)) #-------------------------------------------------------------------------- # # diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 0010c11e6..3897588f6 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -16,7 +16,7 @@ class CarState(CarStateBase): self.shifter_values = can_define.dv["EV_Gearshift"]['GearPosition'] self.buttonStates = BUTTON_STATES.copy() - def update(self, pt_cp, trans_type): + def update(self, pt_cp, cam_cp, trans_type): ret = car.CarState.new_message() # Update vehicle speed and acceleration from ABS wheel speeds. ret.wheelSpeeds.fl = pt_cp.vl["ESP_19"]['ESP_VL_Radgeschw_02'] * CV.KPH_TO_MS @@ -80,8 +80,17 @@ class CarState(CarStateBase): # detection box is dynamic based on speed and road curvature. # Refer to VW Self Study Program 890253: Volkswagen Driver Assist Systems, # pages 32-35. - ret.leftBlindspot = bool(pt_cp.vl["SWA_01"]["SWA_Infostufe_SWA_li"]) or bool(pt_cp.vl["SWA_01"]["SWA_Warnung_SWA_li"]) - ret.rightBlindspot = bool(pt_cp.vl["SWA_01"]["SWA_Infostufe_SWA_re"]) or bool(pt_cp.vl["SWA_01"]["SWA_Warnung_SWA_re"]) + if self.CP.enableBsm: + ret.leftBlindspot = bool(pt_cp.vl["SWA_01"]["SWA_Infostufe_SWA_li"]) or bool(pt_cp.vl["SWA_01"]["SWA_Warnung_SWA_li"]) + ret.rightBlindspot = bool(pt_cp.vl["SWA_01"]["SWA_Infostufe_SWA_re"]) or bool(pt_cp.vl["SWA_01"]["SWA_Warnung_SWA_re"]) + + # Consume factory LDW data relevant for factory SWA (Lane Change Assist) + # and capture it for forwarding to the blind spot radar controller + self.ldw_lane_warning_left = bool(cam_cp.vl["LDW_02"]["LDW_SW_Warnung_links"]) + self.ldw_lane_warning_right = bool(cam_cp.vl["LDW_02"]["LDW_SW_Warnung_rechts"]) + self.ldw_side_dlc_tlc = bool(cam_cp.vl["LDW_02"]["LDW_Seite_DLCTLC"]) + self.ldw_dlc = cam_cp.vl["LDW_02"]["LDW_DLC"] + self.ldw_tlc = cam_cp.vl["LDW_02"]["LDW_TLC"] # Stock FCW is considered active if the release bit for brake-jerk warning # is set. Stock AEB considered active if the partial braking or target @@ -180,8 +189,6 @@ class CarState(CarStateBase): ("KBI_Handbremse", "Kombi_01", 0), # Manual handbrake applied ("TSK_Status", "TSK_06", 0), # ACC engagement status from drivetrain coordinator ("TSK_Fahrzeugmasse_02", "Motor_16", 0), # Estimated vehicle mass from drivetrain coordinator - ("ACC_Status_ACC", "ACC_06", 0), # ACC engagement status - ("ACC_Typ", "ACC_06", 0), # ACC type (follow to stop, stop&go) ("ACC_Wunschgeschw", "ACC_02", 0), # ACC set speed ("AWV2_Freigabe", "ACC_10", 0), # FCW brake jerk release ("ANB_Teilbremsung_Freigabe", "ACC_10", 0), # AEB partial braking release @@ -197,10 +204,6 @@ class CarState(CarStateBase): ("GRA_Tip_Stufe_2", "GRA_ACC_01", 0), # unknown related to stalk type ("GRA_ButtonTypeInfo", "GRA_ACC_01", 0), # unknown related to stalk type ("COUNTER", "GRA_ACC_01", 0), # GRA_ACC_01 CAN message counter - ("SWA_Infostufe_SWA_li", "SWA_01", 0), # Blind spot object info, left - ("SWA_Warnung_SWA_li", "SWA_01", 0), # Blind spot object warning, left - ("SWA_Infostufe_SWA_re", "SWA_01", 0), # Blind spot object info, right - ("SWA_Warnung_SWA_re", "SWA_01", 0), # Blind spot object warning, right ] checks = [ @@ -210,10 +213,10 @@ class CarState(CarStateBase): ("ESP_19", 100), # From J104 ABS/ESP controller ("ESP_05", 50), # From J104 ABS/ESP controller ("ESP_21", 50), # From J104 ABS/ESP controller - ("ACC_06", 50), # From J428 ACC radar control module ("ACC_10", 50), # From J428 ACC radar control module ("Motor_20", 50), # From J623 Engine control module ("TSK_06", 50), # From J623 Engine control module + ("ESP_02", 50), ("GRA_ACC_01", 33), # From J??? steering wheel control buttons ("ACC_02", 17), # From J428 ACC radar control module ("Gateway_72", 10), # From J533 CAN gateway (aggregated data) @@ -224,6 +227,17 @@ class CarState(CarStateBase): ("Einheiten_01", 1), # From J??? not known if gateway, cluster, or BCM ] + if CP.enableBsm: + signals += [ + ("SWA_Infostufe_SWA_li", "SWA_01", 0), # Blind spot object info, left + ("SWA_Warnung_SWA_li", "SWA_01", 0), # Blind spot object warning, left + ("SWA_Infostufe_SWA_re", "SWA_01", 0), # Blind spot object info, right + ("SWA_Warnung_SWA_re", "SWA_01", 0), # Blind spot object warning, right + ] + checks += [ + ("SWA_01", 20), + ] + if CP.transmissionType == TransmissionType.automatic: signals += [("GE_Fahrstufe", "Getriebe_11", 0)] # Auto trans gear selector position checks += [("Getriebe_11", 20)] # From J743 Auto transmission control module @@ -237,15 +251,16 @@ class CarState(CarStateBase): return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, CANBUS.pt) - # A single signal is monitored from the camera CAN bus, and then ignored, - # so the presence of CAN traffic can be verified with cam_cp.valid. - @staticmethod def get_cam_can_parser(CP): signals = [ # sig_name, sig_address, default - ("LDW_Status_LED_gruen", "LDW_02", 0), # Lane Assist status LED + ("LDW_SW_Warnung_links", "LDW_02", 0), # Blind spot in warning mode on left side due to lane departure + ("LDW_SW_Warnung_rechts", "LDW_02", 0), # Blind spot in warning mode on right side due to lane departure + ("LDW_Seite_DLCTLC", "LDW_02", 0), # Direction of most likely lane departure (left or right) + ("LDW_DLC", "LDW_02", 0), # Lane departure, distance to line crossing + ("LDW_TLC", "LDW_02", 0), # Lane departure, time to line crossing ] checks = [ diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 21721a0c0..787899359 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -57,7 +57,12 @@ class CarInterface(CarInterfaceBase): # Per-chassis tuning values, override tuning defaults here if desired - if candidate == CAR.GOLF_MK7: + if candidate == CAR.ATLAS_MK1: + # Averages of all CA Atlas variants + ret.mass = 2011 + STD_CARGO_KG + ret.wheelbase = 2.98 + + elif candidate == CAR.GOLF_MK7: # Averages of all AU Golf variants ret.mass = 1397 + STD_CARGO_KG ret.wheelbase = 2.62 @@ -77,10 +82,10 @@ class CarInterface(CarInterfaceBase): ret.mass = 1715 + STD_CARGO_KG ret.wheelbase = 2.74 - elif candidate == CAR.AUDI_A3: - # Temporarily carry forward old tuning values while we test vehicle identification - ret.mass = 1500 + STD_CARGO_KG - ret.wheelbase = 2.64 + elif candidate == CAR.AUDI_A3_MK3: + # Averages of all 8V A3 variants + ret.mass = 1335 + STD_CARGO_KG + ret.wheelbase = 2.61 elif candidate == CAR.SEAT_ATECA_MK1: # Averages of all 5F Ateca variants @@ -104,7 +109,8 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.45 - ret.enableCamera = True # Stock camera detection doesn't apply to VW + ret.enableCamera = True + ret.enableBsm = 0x30F in fingerprint[0] # TODO: get actual value, for now starting with reasonable value for # civic and scaling by mass and wheelbase @@ -127,7 +133,7 @@ class CarInterface(CarInterfaceBase): self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) - ret = self.CS.update(self.cp, self.CP.transmissionType) + ret = self.CS.update(self.cp, self.cp_cam, self.CP.transmissionType) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False @@ -167,8 +173,9 @@ class CarInterface(CarInterfaceBase): def apply(self, c): can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, c.hudControl.visualAlert, - c.hudControl.audibleAlert, c.hudControl.leftLaneVisible, - c.hudControl.rightLaneVisible) + c.hudControl.rightLaneVisible, + c.hudControl.leftLaneDepart, + c.hudControl.rightLaneDepart) self.frame += 1 return can_sends diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 8d85cb47a..ec2d879fa 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -55,17 +55,21 @@ MQB_LDW_MESSAGES = { # FW_VERSIONS for that existing CAR. class CAR: + ATLAS_MK1 = "VOLKSWAGEN ATLAS 1ST GEN" # Chassis CA, Mk1 VW Atlas and Atlas Cross Sport 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 + AUDI_A3_MK3 = "AUDI A3 3RD GEN" # Chassis 8V/FF, Mk3 Audi A3 and variants SEAT_ATECA_MK1 = "SEAT ATECA 1ST GEN" # Chassis 5F, Mk1 SEAT Ateca and CUPRA Ateca SKODA_KODIAQ_MK1 = "SKODA KODIAQ 1ST GEN" # Chassis NS, Mk1 Skoda Kodiaq SKODA_SCALA_MK1 = "SKODA SCALA 1ST GEN" # Chassis NW, Mk1 Skoda Scala and Skoda Kamiq SKODA_SUPERB_MK3 = "SKODA SUPERB 3RD GEN" # Chassis 3V/NP, Mk3 Skoda Superb and variants - AUDI_A3 = "AUDI A3" # Chassis 8V/FF, Mk3 Audi A3 and variants FINGERPRINTS = { + CAR.ATLAS_MK1: [{ + 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 418: 8, 427: 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, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1156: 8, 1157: 8, 1158: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1440: 5, 1471: 4, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1635: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8, 1792: 8, 1872: 8, 1879: 8, 1976: 8, 1977: 8, 1985: 8, 2015: 8 + }], 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 }], @@ -78,7 +82,7 @@ FINGERPRINTS = { CAR.TIGUAN_MK2: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 376: 8, 418: 8, 427: 8, 573: 8, 679: 8, 681: 8, 684: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 795: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 828: 8, 870: 8, 879: 8, 884: 8, 888: 8, 891: 8, 896: 8, 897: 8, 898: 8, 901: 8, 913: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1156: 8, 1157: 8, 1158: 8, 1162: 8, 1175: 8, 1312: 8, 1343: 8, 1385: 8, 1413: 8, 1440: 5, 1471: 4, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1635: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8 }], - CAR.AUDI_A3: [{ + CAR.AUDI_A3_MK3: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 285: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 295: 8, 299: 8, 302: 8, 346: 8, 418: 8, 427: 8, 506: 8, 679: 8, 681: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 802: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 846: 8, 847: 8, 870: 8, 896: 8, 897: 8, 898: 8, 901: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 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, 1600: 8, 1601: 8, 1603: 8, 1624: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8, 1792: 8, 1872: 8, 1976: 8, 1977: 8, 1982: 8, 1985: 8 }], CAR.SEAT_ATECA_MK1: [{ @@ -95,24 +99,27 @@ 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] +# All VW should be here +IGNORED_FINGERPRINTS = [CAR.ATLAS_MK1, CAR.GOLF_MK7, CAR.JETTA_MK7, CAR.PASSAT_MK8, + CAR.TIGUAN_MK2, CAR.AUDI_A3_MK3, CAR.SEAT_ATECA_MK1, + CAR.SKODA_KODIAQ_MK1, CAR.SKODA_SCALA_MK1, CAR.SKODA_SUPERB_MK3 ] FW_VERSIONS = { - CAR.AUDI_A3: { + CAR.ATLAS_MK1: { (Ecu.engine, 0x7e0, None): [ - b'\xf1\x875G0906259L \xf1\x890002', + b'\xf1\x8703H906026AA\xf1\x899970', ], (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x870D9300013B \xf1\x894931', + b'\xf1\x8709G927158DR\xf1\x893536', ], (Ecu.srs, 0x715, None): [ - b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023121111111211--261117141112231291163221', + b'\xf1\x873Q0959655BN\xf1\x890713\xf1\x82\0162214152212001105141122052900', ], (Ecu.eps, 0x712, None): [ - b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521G00807A1', + b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\00571B60924A1', ], (Ecu.fwdRadar, 0x757, None): [ - b'\xf1\x875Q0907572G \xf1\x890571', + b'\xf1\x875Q0907572P \xf1\x890682', ], }, CAR.GOLF_MK7: { @@ -123,57 +130,83 @@ FW_VERSIONS = { b'\xf1\x8704E906023BN\xf1\x894518', b'\xf1\x8704E906027GR\xf1\x892394', b'\xf1\x8704L906026NF\xf1\x899528', + b'\xf1\x8704L906056CR\xf1\x895813', b'\xf1\x8704L906056HE\xf1\x893758', b'\xf1\x870EA906016A \xf1\x898343', + b'\xf1\x870EA906016F \xf1\x895002', b'\xf1\x870EA906016S \xf1\x897207', b'\xf1\x875G0906259 \xf1\x890007', b'\xf1\x875G0906259J \xf1\x890002', b'\xf1\x875G0906259L \xf1\x890002', + b'\xf1\x875G0906259N \xf1\x890003', b'\xf1\x875G0906259Q \xf1\x890002', + b'\xf1\x875G0906259Q \xf1\x892313', + b'\xf1\x878V0906259J \xf1\x890003', b'\xf1\x878V0906259P \xf1\x890001', b'\xf1\x878V0906259Q \xf1\x890002', + b'\xf1\x878V0906264F \xf1\x890003', + b'\xf1\x878V0906264L \xf1\x890002', + b'\xf1\x878V0906264M \xf1\x890001', ], (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\x8709G927749AP\xf1\x892943', b'\xf1\x870CW300042F \xf1\x891604', - b'\xf1\x870DD300046F \xf1\x891601', + b'\xf1\x870CW300045 \xf1\x894531', + b'\xf1\x870CW300047D \xf1\x895261', + b'\xf1\x870CW300048J \xf1\x890611', + b'\xf1\x870D9300012 \xf1\x894913', + b'\xf1\x870D9300014M \xf1\x895004', 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\x870D9300040S \xf1\x894311', b'\xf1\x870DD300045K \xf1\x891120', + b'\xf1\x870DD300046F \xf1\x891601', + b'\xf1\x870GC300012A \xf1\x891403', + b'\xf1\x870GC300014B \xf1\x892401', + b'\xf1\x870GC300014B \xf1\x892405', + b'\xf1\x870GC300020G \xf1\x892401', + b'\xf1\x870GC300020G \xf1\x892403', + b'\xf1\x870GC300020G \xf1\x892404', + b'\xf1\x870GC300043T \xf1\x899999', ], (Ecu.srs, 0x715, None): [ + b'\xf1\x875Q0959655AA\xf1\x890386\xf1\x82\0211413001113120043114317121C111C9113', + b'\xf1\x875Q0959655AA\xf1\x890386\xf1\x82\0211413001113120053114317121C111C9113', + b'\xf1\x875Q0959655AA\xf1\x890388\xf1\x82\0211413001113120043114317121C111C9113', + b'\xf1\x875Q0959655AA\xf1\x890388\xf1\x82\0211413001113120043114417121411149113', + b'\xf1\x875Q0959655AA\xf1\x890388\xf1\x82\0211413001113120053114317121C111C9113', + b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02314160011123300314211012230229333463100', + b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\023141600111233003142405A2252229333463100', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023271112111312--071104171825102591131211', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023271212111312--071104171838103891131211', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023341512112212--071104172328102891131211', 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', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02324230011211200621143171724112491132111', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\x1315120011211200061104171717101791132111', + b'\xf1\x875Q0959655T \xf1\x890830\xf1\x82\x13271100111312--071104171826102691131211', ], (Ecu.eps, 0x712, None): [ b'\xf1\x873Q0909144F \xf1\x895043\xf1\x82\00561A01612A0', b'\xf1\x873Q0909144H \xf1\x895061\xf1\x82\00566A0J612A1', + b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\00566A00514A1', + b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\00571A0J714A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571A0JA15A1', + b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\00571A01A18A1', 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\x875Q0909144L \xf1\x891021\xf1\x82\00522A00402A0', + b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00511A00403A0', + b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\00516A00604A1', + b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\00516A07A02A1', + b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521A20B03A1', + b'\xf1\x875QM909144A \xf1\x891072\xf1\x82\x0521A20B03A1', + b'\xf1\x875QN909144A \xf1\x895081\xf1\x82\00571A01A18A1', b'\xf1\x875QN909144A \xf1\x895081\xf1\x82\x0571A01A17A1', ], (Ecu.fwdRadar, 0x757, None): [ @@ -182,6 +215,7 @@ FW_VERSIONS = { 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\x875Q0907572G \xf1\x890571', b'\xf1\x875Q0907572H \xf1\x890620', b'\xf1\x875Q0907572J \xf1\x890654', b'\xf1\x875Q0907572P \xf1\x890682', @@ -189,20 +223,23 @@ FW_VERSIONS = { }, CAR.JETTA_MK7: { (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704E906024AK\xf1\x899937', + b'\xf1\x8704E906024AS\xf1\x899912', b'\xf1\x8704E906024B \xf1\x895594', b'\xf1\x8704E906024L \xf1\x895595', - b'\xf1\x8704E906024AK\xf1\x899937', b'\xf1\x875G0906259T \xf1\x890003', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x8709S927158BS\xf1\x893642', b'\xf1\x8709S927158R \xf1\x893552', b'\xf1\x8709S927158R \xf1\x893587', b'\xf1\x870GC300020N \xf1\x892803', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AG\xf1\x890336\xf1\x82\02314171231313500314611011630169333463100', - b'\xf1\x875Q0959655BR\xf1\x890403\xf1\x82\02311170031313300314240011150119333433100', b'\xf1\x875Q0959655BM\xf1\x890403\xf1\x82\02314171231313500314643011650169333463100', + b'\xf1\x875Q0959655BM\xf1\x890403\xf1\x82\02314171231313500314642011650169333463100', + b'\xf1\x875Q0959655BR\xf1\x890403\xf1\x82\02311170031313300314240011150119333433100', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\00521A10A01A1', @@ -221,20 +258,20 @@ FW_VERSIONS = { b'\xf1\x8704L906026GA\xf1\x892013', ], (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x870DD300045T \xf1\x891601', b'\xf1\x870D9300014L \xf1\x895002', + b'\xf1\x870DD300045T \xf1\x891601', ], (Ecu.srs, 0x715, None): [ - b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02315120011111200631145171716121691132111', b'\xf1\x873Q0959655AN\xf1\x890306\xf1\x82\r58160058140013036914110311', + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02315120011111200631145171716121691132111', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521B00703A1', ], (Ecu.fwdRadar, 0x757, None): [ - b'\xf1\x875Q0907572R \xf1\x890771', b'\xf1\x873Q0907572C \xf1\x890195', + b'\xf1\x875Q0907572R \xf1\x890771', ], }, CAR.TIGUAN_MK2: { @@ -254,6 +291,40 @@ FW_VERSIONS = { b'\xf1\x872Q0907572R \xf1\x890372', ], }, + CAR.AUDI_A3_MK3: { + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704E906023AN\xf1\x893695', + b'\xf1\x8704E906023AR\xf1\x893440', + b'\xf1\x8704E906023BL\xf1\x895190', + b'\xf1\x8704L997022N \xf1\x899459', + b'\xf1\x875G0906259L \xf1\x890002', + b'\xf1\x878V0906264B \xf1\x890003', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870CW300048 \xf1\x895201', + b'\xf1\x870D9300013B \xf1\x894931', + b'\xf1\x870D9300041N \xf1\x894512', + b'\xf1\x870DD300046A \xf1\x891602', + b'\xf1\x870DD300046F \xf1\x891602', + b'\xf1\x870DD300046G \xf1\x891601', + ], + (Ecu.srs, 0x715, None): [ + b'\xf1\x875Q0959655AM\xf1\x890315\xf1\x82\x1311111111111111311411011231129321212100', + b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\023111112111111--171115141112221291163221', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023121111111211--261117141112231291163221', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13121111111111--341117141212231291163221', + b'\xf1\x875Q0959655N \xf1\x890361\xf1\x82\0211212001112111104110411111521159114', + ], + (Ecu.eps, 0x712, None): [ + b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00803A0', + b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\00516G00804A1', + b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521G00807A1', + ], + (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x875Q0907572D \xf1\x890304\xf1\x82\00101', + b'\xf1\x875Q0907572G \xf1\x890571', + ], + }, CAR.SEAT_ATECA_MK1: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027KA\xf1\x893749', @@ -275,20 +346,25 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027DD\xf1\x893123', b'\xf1\x875NA907115E \xf1\x890003', + b'\xf1\x8704L906026DE\xf1\x895418', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870D9300043 \xf1\x895202', b'\xf1\x870DL300012M \xf1\x892107', + b'\xf1\x870DL300012N \xf1\x892110', ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655BJ\xf1\x890703\xf1\x82\0161213001211001205212111052100', + b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6050405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6060405', + b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G600', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572R \xf1\x890372', + b'\xf1\x872Q0907572Q \xf1\x890342', ], }, CAR.SKODA_SCALA_MK1: { @@ -311,26 +387,38 @@ FW_VERSIONS = { CAR.SKODA_SUPERB_MK3: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704L906026KB\xf1\x894071', + b'\xf1\x873G0906259B \xf1\x890002', + b'\xf1\x8704L906026FP\xf1\x891196', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870D9300012 \xf1\x894940', + b'\xf1\x870D9300011T \xf1\x894801', ], - # Only onboarded Superb so far is a manual (Ecu.transmission, 0x7e1, None): [], (Ecu.srs, 0x715, None): [ + b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\022111200111121001121118112231292221111', b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02331310031313100313131013141319331413100', + b'\xf1\x875Q0959655AK\xf1\x890130\xf1\x82\022111200111121001121110012211292221111', ], (Ecu.eps, 0x712, None): [ + b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522UZ070303', b'\xf1\x875Q0910143B \xf1\x892201\xf1\x82\00563UZ060700', + b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820514UZ070203', ], (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x873Q0907572B \xf1\x890194', b'\xf1\x873Q0907572C \xf1\x890195', + b'\xf1\x873Q0907572B \xf1\x890192', ], }, } DBC = { + CAR.ATLAS_MK1: 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), - CAR.AUDI_A3: dbc_dict('vw_mqb_2010', None), + CAR.AUDI_A3_MK3: dbc_dict('vw_mqb_2010', None), CAR.SEAT_ATECA_MK1: dbc_dict('vw_mqb_2010', None), CAR.SKODA_KODIAQ_MK1: dbc_dict('vw_mqb_2010', None), CAR.SKODA_SCALA_MK1: dbc_dict('vw_mqb_2010', None), diff --git a/selfdrive/car/volkswagen/volkswagencan.py b/selfdrive/car/volkswagen/volkswagencan.py index 4d0eaec62..0e35d21d6 100644 --- a/selfdrive/car/volkswagen/volkswagencan.py +++ b/selfdrive/car/volkswagen/volkswagencan.py @@ -15,23 +15,26 @@ def create_mqb_steering_control(packer, bus, apply_steer, idx, lkas_enabled): } return packer.make_can_msg("HCA_01", bus, values, idx) -def create_mqb_hud_control(packer, bus, hca_enabled, steering_pressed, hud_alert, leftLaneVisible, rightLaneVisible): - - if hca_enabled: - leftlanehud = 3 if leftLaneVisible else 1 - rightlanehud = 3 if rightLaneVisible else 1 - else: - leftlanehud = 2 if leftLaneVisible else 1 - rightlanehud = 2 if rightLaneVisible else 1 +def create_mqb_hud_control(packer, bus, enabled, steering_pressed, hud_alert, left_lane_visible, right_lane_visible, + ldw_lane_warning_left, ldw_lane_warning_right, ldw_side_dlc_tlc, ldw_dlc, ldw_tlc, + standstill, left_lane_depart, right_lane_depart): + # Lane color reference: + # 0 (LKAS disabled) - off + # 1 (LKAS enabled, no lane detected) - dark gray + # 2 (LKAS enabled, lane detected) - light gray on VW, green or white on Audi depending on year or virtual cockpit. On a color MFD on a 2015 A3 TDI it is white, virtual cockpit on a 2018 A3 e-Tron its green. + # 3 (LKAS enabled, lane departure detected) - white on VW, red on Audi values = { - "LDW_SW_Warnung_links": 0, # FIXME: to be store-and-forwarded from the stock camera - "LDW_SW_Warnung_rechts": 1, # FIXME: to be store-and-forwarded from the stock camera - "LDW_Status_LED_gelb": 1 if hca_enabled and steering_pressed else 0, - "LDW_Status_LED_gruen": 1 if hca_enabled and not steering_pressed else 0, - "LDW_Lernmodus_links": leftlanehud, - "LDW_Lernmodus_rechts": rightlanehud, + "LDW_Status_LED_gelb": 1 if enabled and steering_pressed else 0, + "LDW_Status_LED_gruen": 1 if enabled and not steering_pressed else 0, + "LDW_Lernmodus_links": 3 if left_lane_depart else 1 + left_lane_visible, + "LDW_Lernmodus_rechts": 3 if right_lane_depart else 1 + right_lane_visible, "LDW_Texte": hud_alert, + "LDW_SW_Warnung_links": ldw_lane_warning_left, + "LDW_SW_Warnung_rechts": ldw_lane_warning_right, + "LDW_Seite_DLCTLC": ldw_side_dlc_tlc, + "LDW_DLC": ldw_dlc, + "LDW_TLC": ldw_tlc } return packer.make_can_msg("LDW_02", bus, values) diff --git a/selfdrive/clocksd/clocksd.cc b/selfdrive/clocksd/clocksd.cc index 32d8c508c..c6ad4061a 100644 --- a/selfdrive/clocksd/clocksd.cc +++ b/selfdrive/clocksd/clocksd.cc @@ -1,8 +1,8 @@ -#include #include -#include +#include #include #include +#include // Apple doesn't have timerfd #ifdef __APPLE__ @@ -14,9 +14,9 @@ #include #include -#include "messaging.hpp" -#include "common/timing.h" -#include "common/util.h" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" ExitHandler do_exit; diff --git a/selfdrive/common/SConscript b/selfdrive/common/SConscript index fb36e2b9f..5d5900500 100644 --- a/selfdrive/common/SConscript +++ b/selfdrive/common/SConscript @@ -28,6 +28,8 @@ if arch == "aarch64": 'touch.c', ] _gpu_libs = ['gui', 'adreno_utils'] +elif arch == "larch64": + _gpu_libs = ["GLESv2"] else: _gpu_libs = ["GL"] diff --git a/selfdrive/common/clutil.cc b/selfdrive/common/clutil.cc index c6a2b49dc..526c66b22 100644 --- a/selfdrive/common/clutil.cc +++ b/selfdrive/common/clutil.cc @@ -1,12 +1,15 @@ -#include "clutil.h" +#include "selfdrive/common/clutil.h" + #include #include #include #include -#include + #include +#include #include -#include "util.h" + +#include "selfdrive/common/util.h" namespace { // helper functions diff --git a/selfdrive/common/framebuffer.cc b/selfdrive/common/framebuffer.cc index 62ac7053e..79051f7e8 100644 --- a/selfdrive/common/framebuffer.cc +++ b/selfdrive/common/framebuffer.cc @@ -1,15 +1,15 @@ -#include "framebuffer.h" -#include "util.h" +#include "selfdrive/common/framebuffer.h" + #include #include +#include "selfdrive/common/util.h" + #include #include #include #include - - #include #include @@ -40,7 +40,7 @@ void FrameBuffer::swap() { bool set_brightness(int brightness) { char bright[64]; snprintf(bright, sizeof(bright), "%d", brightness); - return 0 == write_file("/sys/class/leds/lcd-backlight/brightness", bright, strlen(bright)); + return 0 == util::write_file("/sys/class/leds/lcd-backlight/brightness", bright, strlen(bright)); } void FrameBuffer::set_power(int mode) { diff --git a/selfdrive/common/framebuffer.h b/selfdrive/common/framebuffer.h index d60424d6a..d7054374c 100644 --- a/selfdrive/common/framebuffer.h +++ b/selfdrive/common/framebuffer.h @@ -1,5 +1,7 @@ #pragma once + #include + #include "hardware/hwcomposer_defs.h" bool set_brightness(int brightness); diff --git a/selfdrive/common/glutil.cc b/selfdrive/common/glutil.cc index 77cb82627..7e53975e1 100644 --- a/selfdrive/common/glutil.cc +++ b/selfdrive/common/glutil.cc @@ -1,9 +1,10 @@ -#include -#include -#include -#include +#include "selfdrive/common/glutil.h" -#include "glutil.h" +#include +#include +#include + +#include static GLuint load_shader(GLenum shaderType, const char *src) { GLint status = 0, len = 0; diff --git a/selfdrive/common/glutil.h b/selfdrive/common/glutil.h index dff87821f..7180f855c 100644 --- a/selfdrive/common/glutil.h +++ b/selfdrive/common/glutil.h @@ -1,12 +1,13 @@ #pragma once -#ifdef __APPLE__ - #include -#else - #include -#endif #include +#ifdef __APPLE__ +#include +#else +#include +#endif + class GLShader { public: GLShader(const char *vert_src, const char *frag_src); diff --git a/selfdrive/common/gpio.cc b/selfdrive/common/gpio.cc index 8a72388d4..8a2885316 100644 --- a/selfdrive/common/gpio.cc +++ b/selfdrive/common/gpio.cc @@ -1,8 +1,10 @@ -#include "gpio.h" -#include "util.h" +#include "selfdrive/common/gpio.h" + #include -#include #include +#include + +#include "selfdrive/common/util.h" // We assume that all pins have already been exported on boot, // and that we have permission to write to them. @@ -15,7 +17,7 @@ int gpio_init(int pin_nr, bool output){ return -1; } const char *value = output ? "out" : "in"; - return write_file(pin_dir_path, (void*)value, strlen(value)); + return util::write_file(pin_dir_path, (void*)value, strlen(value)); } int gpio_set(int pin_nr, bool high){ @@ -25,5 +27,5 @@ int gpio_set(int pin_nr, bool high){ if(pin_val_path_len <= 0){ return -1; } - return write_file(pin_val_path, (void*)(high ? "1" : "0"), 1); + return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1); } diff --git a/selfdrive/common/i2c.cc b/selfdrive/common/i2c.cc index 95d0aedd5..c2842948b 100644 --- a/selfdrive/common/i2c.cc +++ b/selfdrive/common/i2c.cc @@ -1,12 +1,14 @@ -#include "i2c.h" +#include "selfdrive/common/i2c.h" + +#include +#include +#include +#include #include -#include #include -#include -#include -#include -#include "common/swaglog.h" + +#include "selfdrive/common/swaglog.h" #define UNUSED(x) (void)(x) diff --git a/selfdrive/common/modeldata.h b/selfdrive/common/modeldata.h index fbbd9ce46..b6282000e 100644 --- a/selfdrive/common/modeldata.h +++ b/selfdrive/common/modeldata.h @@ -19,27 +19,27 @@ const double X_IDXS[TRAJECTORY_SIZE] = { 0. , 0.1875, 0.75 , 1.6875, #ifdef __cplusplus -#include "common/mat.h" -#ifdef QCOM2 -const mat3 fcam_intrinsic_matrix = (mat3){{ - 2648.0, 0.0, 1928.0/2, - 0.0, 2648.0, 1208.0/2, - 0.0, 0.0, 1.0 -}}; -#else -const mat3 fcam_intrinsic_matrix = (mat3){{ - 910., 0., 1164.0/2, - 0., 910., 874.0/2, - 0., 0., 1. -}}; -#endif +#include "selfdrive/common/mat.h" +#include "selfdrive/hardware/hw.h" +const mat3 fcam_intrinsic_matrix = + Hardware::TICI() ? (mat3){{2648.0, 0.0, 1928.0 / 2, + 0.0, 2648.0, 1208.0 / 2, + 0.0, 0.0, 1.0}} + : (mat3){{910., 0., 1164.0 / 2, + 0., 910., 874.0 / 2, + 0., 0., 1.}}; + +// without unwarp, focal length is for center portion only +const mat3 ecam_intrinsic_matrix = + Hardware::TICI() ? (mat3){{620.0, 0.0, 1928.0 / 2, + 0.0, 620.0, 1208.0 / 2, + 0.0, 0.0, 1.0}} + : (mat3){{0., 0., 0., + 0., 0., 0., + 0., 0., 0.}}; static inline mat3 get_model_yuv_transform(bool bayer = true) { -#ifndef QCOM2 - float db_s = 0.5; // debayering does a 2x downscale -#else - float db_s = 1.0; -#endif + float db_s = Hardware::TICI() ? 1.0 : 0.5; // debayering does a 2x downscale on EON const mat3 transform = (mat3){{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, @@ -49,4 +49,3 @@ static inline mat3 get_model_yuv_transform(bool bayer = true) { } #endif - diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc index 930f3f0df..87d338ed7 100644 --- a/selfdrive/common/params.cc +++ b/selfdrive/common/params.cc @@ -1,45 +1,49 @@ -#include "common/params.h" +#include "selfdrive/common/params.h" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif // _GNU_SOURCE +#include #include #include -#include -#include +#include #include #include +#include -#include -#include -#include #include -#include +#include +#include -#include "common/util.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" +// keep trying if x gets interrupted by a signal +#define HANDLE_EINTR(x) \ + ({ \ + decltype(x) ret; \ + int try_cnt = 0; \ + do { \ + ret = (x); \ + } while (ret == -1 && errno == EINTR && try_cnt++ < 100); \ + ret; \ + }) -#if defined(QCOM) || defined(QCOM2) -const std::string default_params_path = "/data/params"; -#else -const std::string default_params_path = util::getenv_default("HOME", "/.comma/params", "/data/params"); -#endif - -#if defined(QCOM) || defined(QCOM2) -const std::string persistent_params_path = "/persist/comma/params"; -#else -const std::string persistent_params_path = default_params_path; -#endif +namespace { +const std::string default_params_path = Hardware::PC() ? util::getenv_default("HOME", "/.comma/params", "/data/params") + : "/data/params"; +const std::string persistent_params_path = Hardware::PC() ? default_params_path : "/persist/comma/params"; volatile sig_atomic_t params_do_exit = 0; void params_sig_handler(int signal) { params_do_exit = 1; } -static int fsync_dir(const char* path){ - int fd = open(path, O_RDONLY, 0755); +int fsync_dir(const char* path){ + int fd = HANDLE_EINTR(open(path, O_RDONLY, 0755)); if (fd < 0){ return -1; } @@ -52,7 +56,8 @@ static int fsync_dir(const char* path){ return result; } -static int mkdir_p(std::string path) { +// TODO: replace by std::filesystem::create_directories +int mkdir_p(std::string path) { char * _path = (char *)path.c_str(); mode_t prev_mask = umask(0); @@ -73,281 +78,250 @@ static int mkdir_p(std::string path) { return 0; } -static int ensure_dir_exists(std::string path) { - // TODO: replace by std::filesystem::create_directories - return mkdir_p(path.c_str()); +bool ensure_params_path(const std::string ¶m_path, const std::string &key_path) { + // Make sure params path exists + if (!util::file_exists(param_path) && mkdir_p(param_path) != 0) { + return false; + } + + // See if the symlink exists, otherwise create it + if (!util::file_exists(key_path)) { + // 1) Create temp folder + // 2) Set permissions + // 3) Symlink it to temp link + // 4) Move symlink to /d + + std::string tmp_path = param_path + "/.tmp_XXXXXX"; + // this should be OK since mkdtemp just replaces characters in place + char *tmp_dir = mkdtemp((char *)tmp_path.c_str()); + if (tmp_dir == NULL) { + return false; + } + + if (chmod(tmp_dir, 0777) != 0) { + return false; + } + + std::string link_path = std::string(tmp_dir) + ".link"; + if (symlink(tmp_dir, link_path.c_str()) != 0) { + return false; + } + + // don't return false if it has been created by other + if (rename(link_path.c_str(), key_path.c_str()) != 0 && errno != EEXIST) { + return false; + } + } + + // Ensure permissions are correct in case we didn't create the symlink + return chmod(key_path.c_str(), 0777) == 0; } +class FileLock { + public: + FileLock(const std::string& file_name, int op) : fn_(file_name), op_(op) {} -Params::Params(bool persistent_param){ - params_path = persistent_param ? persistent_params_path : default_params_path; + void lock() { + fd_ = HANDLE_EINTR(open(fn_.c_str(), O_CREAT, 0775)); + if (fd_ < 0) { + LOGE("Failed to open lock file %s, errno=%d", fn_.c_str(), errno); + return; + } + if (HANDLE_EINTR(flock(fd_, op_)) < 0) { + close(fd_); + LOGE("Failed to lock file %s, errno=%d", fn_.c_str(), errno); + } + } + + void unlock() { close(fd_); } + +private: + int fd_ = -1, op_; + std::string fn_; +}; + +std::unordered_map keys = { + {"AccessToken", CLEAR_ON_MANAGER_START}, + {"ApiCache_DriveStats", PERSISTENT}, + {"ApiCache_Device", PERSISTENT}, + {"ApiCache_Owner", PERSISTENT}, + {"AthenadPid", PERSISTENT}, + {"CalibrationParams", PERSISTENT}, + {"CarBatteryCapacity", PERSISTENT}, + {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION}, + {"CarParamsCache", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT}, + {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION}, + {"CommunityFeaturesToggle", PERSISTENT}, + {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT | CLEAR_ON_IGNITION}, + {"EnableLteOnroad", PERSISTENT}, + {"EndToEndToggle", PERSISTENT}, + {"CompletedTrainingVersion", PERSISTENT}, + {"DisablePowerDown", PERSISTENT}, + {"DisableUpdates", PERSISTENT}, + {"EnableWideCamera", PERSISTENT}, + {"DoUninstall", CLEAR_ON_MANAGER_START}, + {"DongleId", PERSISTENT}, + {"GitDiff", PERSISTENT}, + {"GitBranch", PERSISTENT}, + {"GitCommit", PERSISTENT}, + {"GitRemote", PERSISTENT}, + {"GithubSshKeys", PERSISTENT}, + {"GithubUsername", PERSISTENT}, + {"HardwareSerial", PERSISTENT}, + {"HasAcceptedTerms", PERSISTENT}, + {"IsDriverViewEnabled", CLEAR_ON_MANAGER_START}, + {"IMEI", PERSISTENT}, + {"IsLdwEnabled", PERSISTENT}, + {"IsMetric", PERSISTENT}, + {"IsOffroad", CLEAR_ON_MANAGER_START}, + {"IsRHD", PERSISTENT}, + {"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, + {"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, + {"IsUploadRawEnabled", PERSISTENT}, + {"LastAthenaPingTime", PERSISTENT}, + {"LastGPSPosition", PERSISTENT}, + {"LastUpdateException", PERSISTENT}, + {"LastUpdateTime", PERSISTENT}, + {"LiveParameters", PERSISTENT}, + {"OpenpilotEnabledToggle", PERSISTENT}, + {"PandaFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT}, + {"PandaFirmwareHex", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT}, + {"PandaDongleId", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT}, + {"Passive", PERSISTENT}, + {"RecordFront", PERSISTENT}, + {"RecordFrontLock", PERSISTENT}, // for the internal fleet + {"ReleaseNotes", PERSISTENT}, + {"ShouldDoUpdate", CLEAR_ON_MANAGER_START}, + {"SubscriberInfo", PERSISTENT}, + {"SshEnabled", PERSISTENT}, + {"TermsVersion", PERSISTENT}, + {"Timezone", PERSISTENT}, + {"TrainingVersion", PERSISTENT}, + {"UpdateAvailable", CLEAR_ON_MANAGER_START}, + {"UpdateFailedCount", CLEAR_ON_MANAGER_START}, + {"Version", PERSISTENT}, + {"VisionRadarToggle", PERSISTENT}, + {"Offroad_ChargeDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT}, + {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START}, + {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START}, + {"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START}, + {"Offroad_PandaFirmwareMismatch", CLEAR_ON_MANAGER_START | CLEAR_ON_PANDA_DISCONNECT}, + {"Offroad_InvalidTime", CLEAR_ON_MANAGER_START}, + {"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START}, + {"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START}, + {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START}, + {"Offroad_HardwareUnsupported", CLEAR_ON_MANAGER_START}, + {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START}, + {"ForcePowerDown", CLEAR_ON_MANAGER_START}, +}; + +} // namespace + +Params::Params(bool persistent_param) : Params(persistent_param ? persistent_params_path : default_params_path) {} + +Params::Params(const std::string &path) : params_path(path) { + if (!ensure_params_path(params_path, params_path + "/d")) { + throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno)); + } } -Params::Params(std::string path) { - params_path = path; +bool Params::checkKey(const std::string &key) { + return keys.find(key) != keys.end(); } -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 // 3) fsync() the temp file // 4) rename the temp file to the real name // 5) fsync() the containing directory + std::string tmp_path = params_path + "/.tmp_value_XXXXXX"; + int tmp_fd = mkstemp((char*)tmp_path.c_str()); + if (tmp_fd < 0) return -1; - int lock_fd = -1; - int tmp_fd = -1; - int result; - std::string path; - std::string tmp_path; - ssize_t bytes_written; - - // Make sure params path exists - result = ensure_dir_exists(params_path); - if (result < 0) { - goto cleanup; - } - - // See if the symlink exists, otherwise create it - path = params_path + "/d"; - struct stat st; - if (stat(path.c_str(), &st) == -1) { - // Create temp folder - path = params_path + "/.tmp_XXXXXX"; - - char *t = mkdtemp((char*)path.c_str()); - if (t == NULL){ - goto cleanup; - } - std::string tmp_dir(t); - - // Set permissions - result = chmod(tmp_dir.c_str(), 0777); - if (result < 0) { - goto cleanup; + int result = -1; + do { + // Write value to temp. + ssize_t bytes_written = HANDLE_EINTR(write(tmp_fd, value, value_size)); + if (bytes_written < 0 || (size_t)bytes_written != value_size) { + result = -20; + break; } - // Symlink it to temp link - tmp_path = tmp_dir + ".link"; - result = symlink(tmp_dir.c_str(), tmp_path.c_str()); - if (result < 0) { - goto cleanup; - } + // change permissions to 0666 for apks + if ((result = fchmod(tmp_fd, 0666)) < 0) break; + // fsync to force persist the changes. + if ((result = fsync(tmp_fd)) < 0) break; - // Move symlink to /d + FileLock file_lock(params_path + "/.lock", LOCK_EX); + std::lock_guard lk(file_lock); + + // Move temp into place. + std::string path = params_path + "/d/" + std::string(key); + if ((result = rename(tmp_path.c_str(), path.c_str())) < 0) break; + + // fsync parent directory path = params_path + "/d"; - result = rename(tmp_path.c_str(), path.c_str()); - if (result < 0) { - goto cleanup; - } - } else { - // Ensure permissions are correct in case we didn't create the symlink - result = chmod(path.c_str(), 0777); - if (result < 0) { - goto cleanup; - } - } + result = fsync_dir(path.c_str()); + } while(0); - // Write value to temp. - tmp_path = params_path + "/.tmp_value_XXXXXX"; - tmp_fd = mkstemp((char*)tmp_path.c_str()); - bytes_written = write(tmp_fd, value, value_size); - if (bytes_written < 0 || (size_t)bytes_written != value_size) { - result = -20; - goto cleanup; - } - - // Build lock path - path = params_path + "/.lock"; - lock_fd = open(path.c_str(), O_CREAT, 0775); - - // Build key path - path = params_path + "/d/" + std::string(key); - - // Take lock. - result = flock(lock_fd, LOCK_EX); - if (result < 0) { - goto cleanup; - } - - // change permissions to 0666 for apks - result = fchmod(tmp_fd, 0666); - if (result < 0) { - goto cleanup; - } - - // fsync to force persist the changes. - result = fsync(tmp_fd); - if (result < 0) { - goto cleanup; - } - - // Move temp into place. - result = rename(tmp_path.c_str(), path.c_str()); - if (result < 0) { - goto cleanup; - } - - // fsync parent directory - path = params_path + "/d"; - result = fsync_dir(path.c_str()); - if (result < 0) { - goto cleanup; - } - -cleanup: - // Release lock. - if (lock_fd >= 0) { - close(lock_fd); - } - if (tmp_fd >= 0) { - if (result < 0) { - remove(tmp_path.c_str()); - } - close(tmp_fd); - } + close(tmp_fd); + remove(tmp_path.c_str()); return result; } -int Params::delete_db_value(std::string key) { - int lock_fd = -1; - int result; - std::string path; - - // Build lock path, and open lockfile - path = params_path + "/.lock"; - lock_fd = open(path.c_str(), O_CREAT, 0775); - - // Take lock. - result = flock(lock_fd, LOCK_EX); - if (result < 0) { - goto cleanup; - } - +int Params::remove(const char *key) { + FileLock file_lock(params_path + "/.lock", LOCK_EX); + std::lock_guard lk(file_lock); // Delete value. - path = params_path + "/d/" + key; - result = remove(path.c_str()); + std::string path = params_path + "/d/" + key; + int result = ::remove(path.c_str()); if (result != 0) { result = ERR_NO_VALUE; - goto cleanup; + return result; } - // fsync parent directory path = params_path + "/d"; - result = fsync_dir(path.c_str()); - if (result < 0) { - goto cleanup; - } - -cleanup: - // Release lock. - if (lock_fd >= 0) { - close(lock_fd); - } - return result; + return fsync_dir(path.c_str()); } -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); +std::string Params::get(const char *key, bool block) { + std::string path = params_path + "/d/" + key; + if (!block) { + return util::read_file(path); } else { - r = read_db_value((const char*)key.c_str(), &value, &size); - } + // 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); - if (r == 0){ - std::string s(value, size); - free(value); - return s; - } 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 + 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) { - int err = 0; - - std::string lock_path = params_path + "/.lock"; - - int lock_fd = open(lock_path.c_str(), 0); - if (lock_fd < 0) return -1; - - err = flock(lock_fd, LOCK_SH); - if (err < 0) { - close(lock_fd); - return err; - } +int Params::readAll(std::map *params) { + FileLock file_lock(params_path + "/.lock", LOCK_SH); + std::lock_guard lk(file_lock); std::string key_path = params_path + "/d"; - DIR *d = opendir(key_path.c_str()); - if (!d) { - close(lock_fd); - return -1; - } - - struct dirent *de = NULL; - while ((de = readdir(d))) { - if (!isalnum(de->d_name[0])) continue; - std::string key = std::string(de->d_name); - std::string value = util::read_file(key_path + "/" + key); - - (*params)[key] = value; - } - - closedir(d); - - close(lock_fd); - return 0; + return util::read_files_in_dir(key_path, params); } -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); +void Params::clearAll(ParamKeyType key_type) { + for (auto &[key, type] : keys) { + if (type & key_type) { + remove(key); + } } - 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 8da077cfd..589775c3c 100644 --- a/selfdrive/common/params.h +++ b/selfdrive/common/params.h @@ -1,46 +1,76 @@ #pragma once + #include + #include +#include #include -#include #define ERR_NO_VALUE -33 +enum ParamKeyType { + PERSISTENT = 0x02, + CLEAR_ON_MANAGER_START = 0x04, + CLEAR_ON_PANDA_DISCONNECT = 0x08, + CLEAR_ON_IGNITION = 0x10, + ALL = 0x02 | 0x04 | 0x08 | 0x10 +}; + class Params { private: std::string params_path; public: Params(bool persistent_param = false); - Params(std::string path); + Params(const 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); + bool checkKey(const std::string &key); - // 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 + int remove(const char *key); + inline int remove(const std::string &key) { + return remove (key.c_str()); + } + void clearAll(ParamKeyType type); - // 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); + // read all values + int readAll(std::map *params); - // 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); + // helpers for reading values + std::string get(const char *key, bool block = false); - int read_db_all(std::map *params); - std::vector read_db_bytes(const char* param_name); - bool read_db_bool(const char* param_name); + inline std::string get(const std::string &key, bool block = false) { + return get(key.c_str(), block); + } - std::string get(std::string key, bool block=false); + 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 std::string &key) { + return getBool(key.c_str()); + } + + inline bool getBool(const char *key) { + return get(key) == "1"; + } + + // helpers for writing values + 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); + } + + inline int putBool(const std::string &key, bool val) { + return putBool(key.c_str(), val); + } }; diff --git a/selfdrive/common/swaglog.cc b/selfdrive/common/swaglog.cc index 5c69c0a94..80d2379d9 100644 --- a/selfdrive/common/swaglog.cc +++ b/selfdrive/common/swaglog.cc @@ -2,22 +2,22 @@ #define _GNU_SOURCE #endif -#include -#include -#include - -#include -#include - -#include "json11.hpp" - -#include "common/util.h" -#include "common/version.h" - #include "swaglog.h" +#include +#include +#include +#include + +#include +#include "json11.hpp" + +#include "selfdrive/common/util.h" +#include "selfdrive/common/version.h" +#include "selfdrive/hardware/hw.h" + class LogState { -public: + public: LogState() = default; ~LogState(); std::mutex lock; @@ -71,9 +71,9 @@ static void cloudlog_init() { s.ctx_j["dirty"] = !getenv("CLEAN"); // device type - if (util::file_exists("/EON")) { + if (Hardware::EON()) { cloudlog_bind_locked("device", "eon"); - } else if (util::file_exists("/TICI")) { + } else if (Hardware::TICI()) { cloudlog_bind_locked("device", "tici"); } else { cloudlog_bind_locked("device", "pc"); @@ -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/timing.h b/selfdrive/common/timing.h index 48d031e51..b940cc924 100644 --- a/selfdrive/common/timing.h +++ b/selfdrive/common/timing.h @@ -1,5 +1,4 @@ -#ifndef COMMON_TIMING_H -#define COMMON_TIMING_H +#pragma once #include #include @@ -50,5 +49,3 @@ static inline uint64_t nanos_monotonic_raw() { clock_gettime(CLOCK_MONOTONIC_RAW, &t); return t.tv_sec * 1000000000ULL + t.tv_nsec; } - -#endif diff --git a/selfdrive/common/touch.c b/selfdrive/common/touch.c index 0ab1e38c0..eef83d8f2 100644 --- a/selfdrive/common/touch.c +++ b/selfdrive/common/touch.c @@ -1,14 +1,14 @@ +#include "selfdrive/common/touch.h" + +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include #include -#include - -#include "touch.h" +#include /* this macro is used to tell if "bit" is set in "array" * it selects a byte from the array, and does a boolean AND diff --git a/selfdrive/common/util.cc b/selfdrive/common/util.cc index a9db1a156..4d366a039 100644 --- a/selfdrive/common/util.cc +++ b/selfdrive/common/util.cc @@ -1,6 +1,8 @@ +#include "selfdrive/common/util.h" + #include -#include "common/util.h" +#include #ifdef __linux__ #include @@ -9,47 +11,7 @@ #define __USE_GNU #endif #include -#endif // __linux__ - -void* read_file(const char* path, size_t* out_len) { - FILE* f = fopen(path, "r"); - if (!f) { - return NULL; - } - fseek(f, 0, SEEK_END); - long f_len = ftell(f); - rewind(f); - - // malloc one extra byte so the file will always be NULL terminated - // cl_cached_program_from_file relies on this - char* buf = (char*)malloc(f_len+1); - assert(buf); - - size_t num_read = fread(buf, f_len, 1, f); - fclose(f); - - if (num_read != 1) { - free(buf); - return NULL; - } - - buf[f_len] = '\0'; - if (out_len) { - *out_len = f_len; - } - - return buf; -} - -int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) { - int fd = open(path, flags, mode); - if (fd == -1) { - return -1; - } - ssize_t n = write(fd, data, size); - close(fd); - return (n >= 0 && (size_t)n == size) ? 0 : -1; -} +#endif // __linux__ void set_thread_name(const char* name) { #ifdef __linux__ @@ -84,3 +46,56 @@ int set_core_affinity(int core) { return -1; #endif } + +namespace util { + +std::string read_file(const std::string& fn) { + std::ifstream ifs(fn, std::ios::binary | std::ios::ate); + if (ifs) { + std::ifstream::pos_type pos = ifs.tellg(); + if (pos != std::ios::beg) { + std::string result; + result.resize(pos); + ifs.seekg(0, std::ios::beg); + ifs.read(result.data(), pos); + if (ifs) { + return result; + } + } + } + ifs.close(); + + // fallback for files created on read, e.g. procfs + std::ifstream f(fn); + std::stringstream buffer; + buffer << f.rdbuf(); + return buffer.str(); +} + +int read_files_in_dir(std::string path, std::map *contents) { + DIR *d = opendir(path.c_str()); + if (!d) return -1; + + struct dirent *de = NULL; + while ((de = readdir(d))) { + if (isalnum(de->d_name[0])) { + (*contents)[de->d_name] = util::read_file(path + "/" + de->d_name); + } + } + + closedir(d); + return 0; +} + +int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) { + int fd = open(path, flags, mode); + if (fd == -1) { + return -1; + } + ssize_t n = write(fd, data, size); + close(fd); + return (n >= 0 && (size_t)n == size) ? 0 : -1; +} + + +} // namespace util diff --git a/selfdrive/common/util.h b/selfdrive/common/util.h index b75c2f434..d4d27fb90 100644 --- a/selfdrive/common/util.h +++ b/selfdrive/common/util.h @@ -1,37 +1,26 @@ #pragma once -#include -#include -#include -#include -#include #include +#include +#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifndef sighandler_t typedef void (*sighandler_t)(int sig); #endif -#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) - -#undef ALIGN -#define ALIGN(x, align) (((x) + (align)-1) & ~((align)-1)) - -// Reads a file into a newly allocated buffer. -// -// Returns NULL on failure, otherwise the NULL-terminated file contents. -// The result must be freed by the caller. -void* read_file(const char* path, size_t* out_len); -int write_file(const char* path, const void* data, size_t size, int flags=O_WRONLY, mode_t mode=0777); - void set_thread_name(const char* name); int set_realtime_priority(int level); @@ -64,12 +53,11 @@ inline std::string string_format(const std::string& format, Args... args) { return std::string(buf.get(), buf.get() + size - 1); } -inline std::string read_file(const std::string &fn) { - std::ifstream t(fn); - std::stringstream buffer; - buffer << t.rdbuf(); - return buffer.str(); -} +std::string read_file(const std::string &fn); + +int read_files_in_dir(std::string path, std::map *contents); + +int write_file(const char* path, const void* data, size_t size, int flags = O_WRONLY, mode_t mode = 0777); inline std::string tohex(const uint8_t* buf, size_t buf_size) { std::unique_ptr hexbuf(new char[buf_size*2+1]); @@ -161,3 +149,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/common/version.h b/selfdrive/common/version.h index 6646026bc..10379fb4d 100644 --- a/selfdrive/common/version.h +++ b/selfdrive/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.8.3-9896438d-2021-03-29T23:54:19" +#define COMMA_VERSION "0.8.4-a7b3df5df-2021-05-15T01:20:46" diff --git a/selfdrive/common/visionimg.cc b/selfdrive/common/visionimg.cc index fdd7d07c7..770e18a10 100644 --- a/selfdrive/common/visionimg.cc +++ b/selfdrive/common/visionimg.cc @@ -1,11 +1,12 @@ +#include "selfdrive/common/visionimg.h" + #include -#include "common/visionimg.h" #ifdef QCOM +#include #include #include #include -#include #define GL_GLEXT_PROTOTYPES #include using namespace android; diff --git a/selfdrive/common/visionimg.h b/selfdrive/common/visionimg.h index 20a476c1a..cf3b36b79 100644 --- a/selfdrive/common/visionimg.h +++ b/selfdrive/common/visionimg.h @@ -3,9 +3,9 @@ #include "visionbuf.h" #ifdef __APPLE__ - #include +#include #else - #include +#include #endif #ifdef QCOM diff --git a/selfdrive/common/watchdog.cc b/selfdrive/common/watchdog.cc index 2e8afb391..fe95e23fd 100644 --- a/selfdrive/common/watchdog.cc +++ b/selfdrive/common/watchdog.cc @@ -1,10 +1,12 @@ -#include -#include +#include "selfdrive/common/watchdog.h" + #include -#include "common/timing.h" -#include "common/util.h" -#include "common/watchdog.h" +#include +#include + +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" const std::string watchdog_fn_prefix = "/dev/shm/wd_"; // + @@ -12,6 +14,6 @@ bool watchdog_kick(){ std::string fn = watchdog_fn_prefix + std::to_string(getpid()); std::string cur_t = std::to_string(nanos_since_boot()); - int r = write_file(fn.c_str(), cur_t.data(), cur_t.length(), O_WRONLY | O_CREAT); + int r = util::write_file(fn.c_str(), cur_t.data(), cur_t.length(), O_WRONLY | O_CREAT); return r == 0; } diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index b575d6eb9..661d87536 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -45,7 +45,7 @@ EventName = car.CarEvent.EventName class Controls: def __init__(self, sm=None, pm=None, can_sock=None): - config_realtime_process(3, Priority.CTRL_HIGH) + config_realtime_process(4 if TICI else 3, Priority.CTRL_HIGH) # Setup sockets self.pm = pm @@ -58,7 +58,8 @@ class Controls: ignore = ['driverCameraState', 'managerState'] if SIMULATION else None self.sm = messaging.SubMaster(['deviceState', 'pandaState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', - 'roadCameraState', 'driverCameraState', 'managerState', 'liveParameters', 'radarState'], ignore_alive=ignore) + 'roadCameraState', 'driverCameraState', 'managerState', 'liveParameters', 'radarState'], + ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan']) self.can_sock = can_sock if can_sock is None: @@ -73,25 +74,29 @@ class Controls: # read params params = Params() - self.is_metric = params.get("IsMetric", encoding='utf8') == "1" - self.is_ldw_enabled = params.get("IsLdwEnabled", encoding='utf8') == "1" - community_feature_toggle = params.get("CommunityFeaturesToggle", encoding='utf8') == "1" - openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle", encoding='utf8') == "1" - passive = params.get("Passive", encoding='utf8') == "1" or not openpilot_enabled_toggle + self.is_metric = params.get_bool("IsMetric") + self.is_ldw_enabled = params.get_bool("IsLdwEnabled") + self.enable_lte_onroad = params.get_bool("EnableLteOnroad") + community_feature_toggle = params.get_bool("CommunityFeaturesToggle") + openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle") + passive = params.get_bool("Passive") or not openpilot_enabled_toggle # detect sound card presence and ensure successful init sounds_available = HARDWARE.get_sound_card_online() car_recognized = self.CP.carName != 'mock' + fuzzy_fingerprint = self.CP.fuzzyFingerprint + # If stock camera is disconnected, we loaded car controls and it's not dashcam mode controller_available = self.CP.enableCamera and self.CI.CC is not None and not passive and not self.CP.dashcamOnly - community_feature_disallowed = self.CP.communityFeature and not community_feature_toggle + community_feature = self.CP.communityFeature or fuzzy_fingerprint + community_feature_disallowed = community_feature and (not community_feature_toggle) self.read_only = not car_recognized or not controller_available or \ self.CP.dashcamOnly or community_feature_disallowed if self.read_only: self.CP.safetyModel = car.CarParams.SafetyModel.noOutput - # Write CarParams for radard and boardd safety mode + # Write CarParams for radard cp_bytes = self.CP.to_bytes() params.put("CarParams", cp_bytes) put_nonblocking("CarParamsCache", cp_bytes) @@ -112,6 +117,7 @@ class Controls: elif self.CP.lateralTuning.which() == 'lqr': self.LaC = LatControlLQR(self.CP) + self.initialized = False self.state = State.disabled self.enabled = False self.active = False @@ -129,14 +135,10 @@ class Controls: self.current_alert_types = [ET.PERMANENT] self.logged_comm_issue = False - self.sm['liveCalibration'].calStatus = Calibration.CALIBRATED - self.sm['deviceState'].freeSpacePercent = 100 - self.sm['driverMonitoringState'].events = [] - self.sm['driverMonitoringState'].awarenessStatus = 1. - self.sm['driverMonitoringState'].faceDetected = False + # TODO: no longer necessary, aside from process replay self.sm['liveParameters'].valid = True - self.startup_event = get_startup_event(car_recognized, controller_available) + self.startup_event = get_startup_event(car_recognized, controller_available, fuzzy_fingerprint) if not sounds_available: self.events.add(EventName.soundsUnavailable, static=True) @@ -163,6 +165,11 @@ class Controls: self.events.add(self.startup_event) self.startup_event = None + # Don't add any more events if not initialized + if not self.initialized: + self.events.add(EventName.controlsInitializing) + return + # Create events for battery, temperature, disk space, and memory if self.sm['deviceState'].batteryPercent < 1 and self.sm['deviceState'].chargingError: # at zero percent battery, while discharging, OP should not allowed @@ -206,12 +213,11 @@ class Controls: LaneChangeState.laneChangeFinishing]: self.events.add(EventName.laneChange) - if self.can_rcv_error or (not CS.canValid and self.sm.frame > 5 / DT_CTRL): + if self.can_rcv_error or not CS.canValid: self.events.add(EventName.canError) - safety_mismatch = self.sm['pandaState'].safetyModel != self.CP.safetyModel - safety_mismatch = safety_mismatch or self.sm['pandaState'].safetyParam != self.CP.safetyParam - if (safety_mismatch and self.sm.frame > 2 / DT_CTRL) or self.mismatch_counter >= 200: + safety_mismatch = self.sm['pandaState'].safetyModel != self.CP.safetyModel or self.sm['pandaState'].safetyParam != self.CP.safetyParam + if safety_mismatch or self.mismatch_counter >= 200: self.events.add(EventName.controlsMismatch) if not self.sm['liveParameters'].valid: @@ -244,10 +250,11 @@ class Controls: # TODO: fix simulator if not SIMULATION: if not NOSENSOR: - if not self.sm['liveLocationKalman'].gpsOK and (self.distance_traveled > 1000) and not TICI: + if not self.sm['liveLocationKalman'].gpsOK and (self.distance_traveled > 1000) and \ + (not TICI or self.enable_lte_onroad): # Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes self.events.add(EventName.noGps) - if not self.sm.all_alive(['roadCameraState', 'driverCameraState']) and (self.sm.frame > 5 / DT_CTRL): + if not self.sm.all_alive(['roadCameraState', 'driverCameraState']): self.events.add(EventName.cameraMalfunction) if self.sm['modelV2'].frameDropPerc > 20: self.events.add(EventName.modeldLagging) @@ -271,6 +278,11 @@ class Controls: self.sm.update(0) + all_valid = CS.canValid and self.sm.all_alive_and_valid() + if not self.initialized and (all_valid or self.sm.frame * DT_CTRL > 2.0): + self.initialized = True + Params().put_bool("ControlsReady", True) + # Check for CAN timeout if not can_strs: self.can_error_counter += 1 @@ -478,7 +490,7 @@ class Controls: self.AM.process_alerts(self.sm.frame, clear_event) CC.hudControl.visualAlert = self.AM.visual_alert - if not self.read_only: + if not self.read_only and self.initialized: # send car controls over can can_sends = self.CI.apply(CC) self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) @@ -578,7 +590,7 @@ class Controls: self.update_events(CS) - if not self.read_only: + if not self.read_only and self.initialized: # Update control state self.state_transition(CS) self.prof.checkpoint("State transition") diff --git a/selfdrive/controls/lib/alerts_offroad.json b/selfdrive/controls/lib/alerts_offroad.json index 79642ccef..f8aaab74e 100644 --- a/selfdrive/controls/lib/alerts_offroad.json +++ b/selfdrive/controls/lib/alerts_offroad.json @@ -40,5 +40,9 @@ "Offroad_HardwareUnsupported": { "text": "White and grey panda are unsupported. Upgrade to comma two or black panda.", "severity": 0 + }, + "Offroad_UnofficialHardware": { + "text": "Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, contact support@comma.ai.", + "severity": 1 } } diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 12fd6519b..87ea3d6fa 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -171,7 +171,7 @@ class EngagementAlert(Alert): class NormalPermanentAlert(Alert): def __init__(self, alert_text_1, alert_text_2): super().__init__(alert_text_1, alert_text_2, - AlertStatus.normal, AlertSize.mid, + AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small, Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), # ********** alert callback functions ********** @@ -208,6 +208,13 @@ def wrong_car_mode_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: boo text = "Main Switch Off" return NoEntryAlert(text, duration_hud_alert=0.) +def startup_fuzzy_fingerprint_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert: + return Alert( + "WARNING: No Exact Match on Car Model", + f"Closest Match: {CP.carFingerprint.title()[:40]}", + AlertStatus.userPrompt, AlertSize.mid, + Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.) + EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, bool], Alert]]]] = { # ********** events with no alerts ********** @@ -221,6 +228,10 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, .1, .1), }, + EventName.controlsInitializing: { + ET.NO_ENTRY: NoEntryAlert("Controls Initializing"), + }, + EventName.startup: { ET.PERMANENT: Alert( "Be ready to take over at any time", @@ -253,6 +264,10 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), }, + EventName.startupFuzzyFingerprint: { + ET.PERMANENT: startup_fuzzy_fingerprint_alert, + }, + EventName.dashcamMode: { ET.PERMANENT: Alert( "Dashcam Mode", @@ -272,8 +287,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.communityFeatureDisallowed: { # LOW priority to overcome Cruise Error ET.PERMANENT: Alert( - "Community Feature Detected", - "Enable Community Features in Developer Settings", + "openpilot Not Available", + "Enable Community Features in Settings to Engage", AlertStatus.normal, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, @@ -292,6 +307,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo "Stock AEB: Risk of Collision", AlertStatus.critical, AlertSize.full, Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), + ET.NO_ENTRY: NoEntryAlert("Stock AEB: Risk of Collision"), }, EventName.stockFcw: { @@ -300,6 +316,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo "Stock FCW: Risk of Collision", AlertStatus.critical, AlertSize.full, Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), + ET.NO_ENTRY: NoEntryAlert("Stock FCW: Risk of Collision"), }, EventName.fcw: { @@ -330,6 +347,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo EventName.vehicleModelInvalid: { ET.NO_ENTRY: NoEntryAlert("Vehicle Parameter Identification Failed"), + ET.SOFT_DISABLE: SoftDisableAlert("Vehicle Parameter Identification Failed"), ET.WARNING: Alert( "Vehicle Parameter Identification Failed", "", @@ -337,12 +355,12 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo Priority.LOWEST, VisualAlert.steerRequired, AudibleAlert.none, .0, .0, .1), }, - EventName.steerTempUnavailableMute: { + EventName.steerTempUnavailableUserOverride: { ET.WARNING: Alert( - "TAKE CONTROL", "Steering Temporarily Unavailable", - AlertStatus.userPrompt, AlertSize.mid, - Priority.LOW, VisualAlert.none, AudibleAlert.none, .2, .2, .2), + "", + AlertStatus.userPrompt, AlertSize.small, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 1., 1.), }, EventName.preDriverDistracted: { @@ -518,11 +536,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo }, EventName.steerTempUnavailable: { - ET.WARNING: Alert( - "TAKE CONTROL", - "Steering Temporarily Unavailable", - AlertStatus.userPrompt, AlertSize.mid, - Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 1.), + ET.SOFT_DISABLE: SoftDisableAlert("Steering Temporarily Unavailable"), ET.NO_ENTRY: NoEntryAlert("Steering Temporarily Unavailable", duration_hud_alert=0.), }, @@ -648,9 +662,10 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo audible_alert=AudibleAlert.chimeDisengage), }, - EventName.controlsFailed: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Failed"), - ET.NO_ENTRY: NoEntryAlert("Controls Failed"), + EventName.accFaulted: { + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Faulted"), + ET.PERMANENT: NormalPermanentAlert("Cruise Faulted", ""), + ET.NO_ENTRY: NoEntryAlert("Cruise Faulted"), }, EventName.controlsMismatch: { @@ -734,7 +749,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo "Speed Too High", "Model uncertain at this speed", AlertStatus.normal, AlertSize.mid, - Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.none, 2.2, 3., 4.), + Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), ET.NO_ENTRY: Alert( "Speed Too High", "Slow down to engage", diff --git a/selfdrive/controls/lib/lane_planner.py b/selfdrive/controls/lib/lane_planner.py index 200ab5d3a..79f23294b 100644 --- a/selfdrive/controls/lib/lane_planner.py +++ b/selfdrive/controls/lib/lane_planner.py @@ -17,9 +17,8 @@ else: PATH_OFFSET = 0.0 - class LanePlanner: - def __init__(self): + def __init__(self, wide_camera=False): self.ll_t = np.zeros((TRAJECTORY_SIZE,)) self.ll_x = np.zeros((TRAJECTORY_SIZE,)) self.lll_y = np.zeros((TRAJECTORY_SIZE,)) @@ -38,6 +37,8 @@ class LanePlanner: self.l_lane_change_prob = 0. self.r_lane_change_prob = 0. + self.camera_offset = -CAMERA_OFFSET if wide_camera else CAMERA_OFFSET + self.path_offset = -PATH_OFFSET if wide_camera else PATH_OFFSET def parse_model(self, md): if len(md.laneLines) == 4 and len(md.laneLines[0].t) == TRAJECTORY_SIZE: @@ -45,8 +46,8 @@ class LanePlanner: # left and right ll x is the same self.ll_x = md.laneLines[1].x # only offset left and right lane lines; offsetting path does not make sense - self.lll_y = np.array(md.laneLines[1].y) - CAMERA_OFFSET - self.rll_y = np.array(md.laneLines[2].y) - CAMERA_OFFSET + self.lll_y = np.array(md.laneLines[1].y) - self.camera_offset + self.rll_y = np.array(md.laneLines[2].y) - self.camera_offset self.lll_prob = md.laneLineProbs[1] self.rll_prob = md.laneLineProbs[2] self.lll_std = md.laneLineStds[1] @@ -59,7 +60,7 @@ class LanePlanner: def get_d_path(self, v_ego, path_t, path_xyz): # Reduce reliance on lanelines that are too far apart or # will be in a few seconds - path_xyz[:,1] -= PATH_OFFSET + path_xyz[:, 1] -= self.path_offset l_prob, r_prob = self.lll_prob, self.rll_prob width_pts = self.rll_y - self.lll_y prob_mods = [] diff --git a/selfdrive/controls/lib/lateral_mpc/generator.cpp b/selfdrive/controls/lib/lateral_mpc/generator.cpp index ca4be4c25..171e7231c 100644 --- a/selfdrive/controls/lib/lateral_mpc/generator.cpp +++ b/selfdrive/controls/lib/lateral_mpc/generator.cpp @@ -1,6 +1,6 @@ #include #include -#include "common/modeldata.h" +#include "selfdrive/common/modeldata.h" #define deg2rad(d) (d/180.0*M_PI) diff --git a/selfdrive/controls/lib/lateral_mpc/lateral_mpc.c b/selfdrive/controls/lib/lateral_mpc/lateral_mpc.c index 8da44f4f1..6765fe57b 100644 --- a/selfdrive/controls/lib/lateral_mpc/lateral_mpc.c +++ b/selfdrive/controls/lib/lateral_mpc/lateral_mpc.c @@ -29,7 +29,7 @@ typedef struct { double cost; } log_t; -void init_weights(double pathCost, double headingCost, double steerRateCost){ +void set_weights(double pathCost, double headingCost, double steerRateCost){ int i; const int STEP_MULTIPLIER = 3.0; @@ -44,7 +44,7 @@ void init_weights(double pathCost, double headingCost, double steerRateCost){ acadoVariables.WN[(NYN+1)*1] = headingCost * STEP_MULTIPLIER; } -void init(double pathCost, double headingCost, double steerRateCost){ +void init(){ acado_initializeSolver(); int i; @@ -58,8 +58,6 @@ void init(double pathCost, double headingCost, double steerRateCost){ /* MPC: initialize the current state feedback. */ for (i = 0; i < NX; ++i) acadoVariables.x0[ i ] = 0.0; - - init_weights(pathCost, headingCost, steerRateCost); } int run_mpc(state_t * x0, log_t * solution, double v_ego, diff --git a/selfdrive/controls/lib/lateral_mpc/libmpc_py.py b/selfdrive/controls/lib/lateral_mpc/libmpc_py.py index 7ef94fc59..2ca3db3a2 100644 --- a/selfdrive/controls/lib/lateral_mpc/libmpc_py.py +++ b/selfdrive/controls/lib/lateral_mpc/libmpc_py.py @@ -22,8 +22,8 @@ typedef struct { double cost; } log_t; -void init(double pathCost, double headingCost, double steerRateCost); -void init_weights(double pathCost, double headingCost, double steerRateCost); +void init(); +void set_weights(double pathCost, double headingCost, double steerRateCost); int run_mpc(state_t * x0, log_t * solution, double v_ego, double rotation_radius, double target_y[N+1], double target_psi[N+1]); diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index 3b7772df0..71913636e 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -1,7 +1,6 @@ import os import math import numpy as np -from common.params import Params from common.realtime import sec_since_boot, DT_MDL from common.numpy_fast import interp, clip from selfdrive.swaglog import cloudlog @@ -17,7 +16,7 @@ LaneChangeDirection = log.LateralPlan.LaneChangeDirection LOG_MPC = os.environ.get('LOG_MPC', False) -LANE_CHANGE_SPEED_MIN = 45 * CV.MPH_TO_MS +LANE_CHANGE_SPEED_MIN = 30 * CV.MPH_TO_MS LANE_CHANGE_TIME_MAX = 10. # this corresponds to 80deg/s and 20deg/s steering angle in a toyota corolla MAX_CURVATURE_RATES = [0.03762194918267951, 0.003441203371932992] @@ -46,15 +45,15 @@ DESIRES = { class LateralPlanner(): - def __init__(self, CP): - self.LP = LanePlanner() + def __init__(self, CP, use_lanelines=True, wide_camera=False): + self.use_lanelines = use_lanelines + self.LP = LanePlanner(wide_camera) self.last_cloudlog_t = 0 self.steer_rate_cost = CP.steerRateCost self.setup_mpc() self.solution_invalid_cnt = 0 - self.use_lanelines = Params().get('EndToEndToggle') != b'1' self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none self.lane_change_timer = 0.0 @@ -63,13 +62,14 @@ class LateralPlanner(): self.desire = log.LateralPlan.Desire.none self.path_xyz = np.zeros((TRAJECTORY_SIZE,3)) + self.path_xyz_stds = np.ones((TRAJECTORY_SIZE,3)) self.plan_yaw = np.zeros((TRAJECTORY_SIZE,)) self.t_idxs = np.arange(TRAJECTORY_SIZE) self.y_pts = np.zeros(TRAJECTORY_SIZE) def setup_mpc(self): self.libmpc = libmpc_py.libmpc - self.libmpc.init(MPC_COST_LAT.PATH, MPC_COST_LAT.HEADING, self.steer_rate_cost) + self.libmpc.init() self.mpc_solution = libmpc_py.ffi.new("log_t *") self.cur_state = libmpc_py.ffi.new("state_t *") @@ -94,16 +94,13 @@ class LateralPlanner(): self.path_xyz = np.column_stack([md.position.x, md.position.y, md.position.z]) self.t_idxs = np.array(md.position.t) self.plan_yaw = list(md.orientation.z) + if len(md.orientation.xStd) == TRAJECTORY_SIZE: + self.path_xyz_stds = np.column_stack([md.position.xStd, md.position.yStd, md.position.zStd]) # Lane change logic one_blinker = sm['carState'].leftBlinker != sm['carState'].rightBlinker below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN - if sm['carState'].leftBlinker: - self.lane_change_direction = LaneChangeDirection.left - elif sm['carState'].rightBlinker: - self.lane_change_direction = LaneChangeDirection.right - if (not active) or (self.lane_change_timer > LANE_CHANGE_TIME_MAX): self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none @@ -120,6 +117,11 @@ class LateralPlanner(): # State transitions # off if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed: + if sm['carState'].leftBlinker: + self.lane_change_direction = LaneChangeDirection.left + elif sm['carState'].rightBlinker: + self.lane_change_direction = LaneChangeDirection.right + self.lane_change_state = LaneChangeState.preLaneChange self.lane_change_ll_prob = 1.0 @@ -162,8 +164,13 @@ class LateralPlanner(): self.LP.rll_prob *= self.lane_change_ll_prob if self.use_lanelines: d_path_xyz = self.LP.get_d_path(v_ego, self.t_idxs, self.path_xyz) + self.libmpc.set_weights(MPC_COST_LAT.PATH, MPC_COST_LAT.HEADING, CP.steerRateCost) else: d_path_xyz = self.path_xyz + path_cost = np.clip(abs(self.path_xyz[0,1]/self.path_xyz_stds[0,1]), 0.5, 5.0) * MPC_COST_LAT.PATH + # Heading cost is useful at low speed, otherwise end of plan can be off-heading + heading_cost = interp(v_ego, [5.0, 10.0], [MPC_COST_LAT.HEADING, 0.0]) + self.libmpc.set_weights(path_cost, heading_cost, CP.steerRateCost) y_pts = np.interp(v_ego * self.t_idxs[:MPC_N + 1], np.linalg.norm(d_path_xyz, axis=1), d_path_xyz[:,1]) heading_pts = np.interp(v_ego * self.t_idxs[:MPC_N + 1], np.linalg.norm(self.path_xyz, axis=1), self.plan_yaw) self.y_pts = y_pts @@ -207,7 +214,7 @@ class LateralPlanner(): mpc_nans = any(math.isnan(x) for x in self.mpc_solution.curvature) t = sec_since_boot() if mpc_nans: - self.libmpc.init(MPC_COST_LAT.PATH, MPC_COST_LAT.HEADING, CP.steerRateCost) + self.libmpc.init() self.cur_state.curvature = measured_curvature if t > self.last_cloudlog_t + 5.0: diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index ceed00c73..a2c650fa1 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -5,23 +5,27 @@ from common.realtime import Priority, config_realtime_process from selfdrive.swaglog import cloudlog from selfdrive.controls.lib.longitudinal_planner import Planner from selfdrive.controls.lib.lateral_planner import LateralPlanner +from selfdrive.hardware import TICI import cereal.messaging as messaging def plannerd_thread(sm=None, pm=None): - - config_realtime_process(2, Priority.CTRL_LOW) + config_realtime_process(5 if TICI else 2, Priority.CTRL_LOW) cloudlog.info("plannerd is waiting for CarParams") - CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) + params = Params() + CP = car.CarParams.from_bytes(params.get("CarParams", block=True)) cloudlog.info("plannerd got CarParams: %s", CP.carName) + use_lanelines = not params.get_bool('EndToEndToggle') + wide_camera = params.get_bool('EnableWideCamera') if TICI else False + longitudinal_planner = Planner(CP) - lateral_planner = LateralPlanner(CP) + lateral_planner = LateralPlanner(CP, use_lanelines=use_lanelines, wide_camera=wide_camera) if sm is None: sm = messaging.SubMaster(['carState', 'controlsState', 'radarState', 'modelV2'], - poll=['radarState', 'modelV2']) + poll=['radarState', 'modelV2'], ignore_avg_freq=['radarState']) if pm is None: pm = messaging.PubMaster(['longitudinalPlan', 'liveLongitudinalMpc', 'lateralPlan', 'liveMpc']) diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 8f23d9d73..244d02d23 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -12,6 +12,7 @@ from selfdrive.config import RADAR_TO_CAMERA from selfdrive.controls.lib.cluster.fastcluster_py import cluster_points_centroid from selfdrive.controls.lib.radar_helpers import Cluster, Track from selfdrive.swaglog import cloudlog +from selfdrive.hardware import TICI class KalmanParams(): @@ -173,7 +174,7 @@ class RadarD(): # fuses camera and radar data for best lead detection def radard_thread(sm=None, pm=None, can_sock=None): - config_realtime_process(2, Priority.CTRL_LOW) + config_realtime_process(5 if TICI else 2, Priority.CTRL_LOW) # wait for stats about the car to come in from controls cloudlog.info("radard is waiting for CarParams") @@ -188,7 +189,7 @@ def radard_thread(sm=None, pm=None, can_sock=None): if can_sock is None: can_sock = messaging.sub_sock('can') if sm is None: - sm = messaging.SubMaster(['modelV2', 'carState']) + sm = messaging.SubMaster(['modelV2', 'carState'], ignore_avg_freq=['modelV2', 'carState']) # Can't check average frequency, since radar determines timing if pm is None: pm = messaging.PubMaster(['radarState', 'liveTracks']) diff --git a/selfdrive/crash.py b/selfdrive/crash.py index 3bc000d2e..b6faa23af 100644 --- a/selfdrive/crash.py +++ b/selfdrive/crash.py @@ -1,77 +1,27 @@ """Install exception handler for process crash.""" -import os -import sys -import threading -import capnp -from selfdrive.version import version, dirty, origin, branch - -from selfdrive.hardware import PC from selfdrive.swaglog import cloudlog +from selfdrive.version import version -if os.getenv("NOLOG") or os.getenv("NOCRASH") or PC: - def capture_exception(*args, **kwargs): - pass +import sentry_sdk +from sentry_sdk.integrations.threading import ThreadingIntegration - def bind_user(**kwargs): - pass +def capture_exception(*args, **kwargs): + cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1)) - def bind_extra(**kwargs): - pass + try: + sentry_sdk.capture_exception(*args, **kwargs) + sentry_sdk.flush() # https://github.com/getsentry/sentry-python/issues/291 + except Exception: + cloudlog.exception("sentry exception") - def install(): - pass -else: - from raven import Client - from raven.transport.http import HTTPTransport +def bind_user(**kwargs): + sentry_sdk.set_user(kwargs) - tags = { - 'dirty': dirty, - 'origin': origin, - 'branch': branch - } - client = Client('https://1994756b5e6f41cf939a4c65de45f4f2:cefebaf3a8aa40d182609785f7189bd7@app.getsentry.com/77924', - install_sys_hook=False, transport=HTTPTransport, release=version, tags=tags) +def bind_extra(**kwargs): + for k, v in kwargs.items(): + sentry_sdk.set_tag(k, v) - def capture_exception(*args, **kwargs): - exc_info = sys.exc_info() - if not exc_info[0] is capnp.lib.capnp.KjException: - client.captureException(*args, **kwargs) - cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1)) - - def bind_user(**kwargs): - client.user_context(kwargs) - - def bind_extra(**kwargs): - client.extra_context(kwargs) - - def install(): - """ - Workaround for `sys.excepthook` thread bug from: - http://bugs.python.org/issue1230540 - Call once from the main thread before creating any threads. - Source: https://stackoverflow.com/a/31622038 - """ - # installs a sys.excepthook - __excepthook__ = sys.excepthook - - def handle_exception(*exc_info): - if exc_info[0] not in (KeyboardInterrupt, SystemExit): - capture_exception() - __excepthook__(*exc_info) - sys.excepthook = handle_exception - - init_original = threading.Thread.__init__ - - def init(self, *args, **kwargs): - init_original(self, *args, **kwargs) - run_original = self.run - - def run_with_except_hook(*args2, **kwargs2): - try: - run_original(*args2, **kwargs2) - except Exception: - sys.excepthook(*sys.exc_info()) - - self.run = run_with_except_hook - - threading.Thread.__init__ = init +def init(): + sentry_sdk.init("https://a8dc76b5bfb34908a601d67e2aa8bcf9@o33823.ingest.sentry.io/77924", + default_integrations=False, integrations=[ThreadingIntegration(propagate_hub=True)], + release=version) diff --git a/selfdrive/debug/count_events.py b/selfdrive/debug/count_events.py new file mode 100755 index 000000000..732c1af1c --- /dev/null +++ b/selfdrive/debug/count_events.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +import sys +from collections import Counter +from pprint import pprint +from tqdm import tqdm + +from tools.lib.route import Route +from tools.lib.logreader import LogReader + +if __name__ == "__main__": + r = Route(sys.argv[1]) + + cnt: Counter = Counter() + for q in tqdm(r.qlog_paths()): + lr = LogReader(q) + car_events = [m for m in lr if m.which() == 'carEvents'] + for car_event in car_events: + for e in car_event.carEvents: + cnt[e.name] += 1 + pprint(cnt) diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py index fa7c266c3..ffff3d6ce 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -31,9 +31,6 @@ PRINT_INTERVAL = 5 SLEEP_INTERVAL = 0.2 monitored_proc_names = [ - # offroad APK - 'ai.comma.plus.offroad', - # android procs 'SurfaceFlinger', 'sensors.qcom' ] + list(managed_processes.keys()) diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index 9999d8657..98e7eafec 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -5,17 +5,22 @@ import time +from cereal import car import cereal.messaging as messaging from selfdrive.car.honda.interface import CarInterface from selfdrive.controls.lib.events import ET, EVENTS, Events from selfdrive.controls.lib.alertmanager import AlertManager +EventName = car.CarEvent.EventName -def cycle_alerts(duration=200, is_metric=False): +def cycle_alerts(duration=2000, is_metric=False): alerts = list(EVENTS.keys()) print(alerts) - CP = CarInterface.get_params("HONDA CIVIC 2016 TOURING") + #alerts = [EventName.preDriverDistracted, EventName.promptDriverDistracted, EventName.driverDistracted] + alerts = [EventName.preLaneChangeLeft, EventName.preLaneChangeRight] + + CP = CarInterface.get_params("HONDA CIVIC 2016") sm = messaging.SubMaster(['deviceState', 'pandaState', 'roadCameraState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman']) diff --git a/selfdrive/debug/dump.py b/selfdrive/debug/dump.py index 908b129c7..ce96b360f 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/debug/filter_log_message.py b/selfdrive/debug/filter_log_message.py index 4ca69f5e9..118a980ee 100755 --- a/selfdrive/debug/filter_log_message.py +++ b/selfdrive/debug/filter_log_message.py @@ -49,7 +49,7 @@ if __name__ == "__main__": logs = None if len(args.route): r = Route(args.route[0]) - logs = r.log_paths() # TODO: switch to qlogs when logs are in there + logs = r.qlog_paths() if len(args.route) == 2 and logs: n = int(args.route[1]) diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py index 1c7f0077e..5a3ccc957 100755 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -7,14 +7,25 @@ import os import traceback from tqdm import tqdm from tools.lib.logreader import LogReader -from selfdrive.car.fw_versions import match_fw_to_car +from tools.lib.route import Route +from selfdrive.car.fw_versions import match_fw_to_car_exact, match_fw_to_car_fuzzy, build_fw_dict from selfdrive.car.toyota.values import FW_VERSIONS as TOYOTA_FW_VERSIONS from selfdrive.car.honda.values import FW_VERSIONS as HONDA_FW_VERSIONS from selfdrive.car.hyundai.values import FW_VERSIONS as HYUNDAI_FW_VERSIONS +from selfdrive.car.volkswagen.values import FW_VERSIONS as VW_FW_VERSIONS from selfdrive.car.toyota.values import FINGERPRINTS as TOYOTA_FINGERPRINTS from selfdrive.car.honda.values import FINGERPRINTS as HONDA_FINGERPRINTS from selfdrive.car.hyundai.values import FINGERPRINTS as HYUNDAI_FINGERPRINTS +from selfdrive.car.volkswagen.values import FINGERPRINTS as VW_FINGERPRINTS + +NO_API = "NO_API" in os.environ +SUPPORTED_CARS = list(TOYOTA_FINGERPRINTS.keys()) + list(HONDA_FINGERPRINTS.keys()) + list(HYUNDAI_FINGERPRINTS.keys())+ list(VW_FINGERPRINTS.keys()) + +try: + from xx.pipeline.c.CarState import migration +except ImportError: + migration = {} if __name__ == "__main__": @@ -30,25 +41,37 @@ if __name__ == "__main__": mismatches = defaultdict(list) - wrong = 0 - good = 0 + not_fingerprinted = 0 + solved_by_fuzzy = 0 + + good_exact = 0 + wrong_fuzzy = 0 + good_fuzzy = 0 dongles = [] for route in tqdm(routes): route = route.rstrip() dongle_id, time = route.split('|') - qlog_path = f"cd:/{dongle_id}/{time}/0/qlog.bz2" if dongle_id in dongles: continue + if NO_API: + qlog_path = f"cd:/{dongle_id}/{time}/0/qlog.bz2" + else: + route = Route(route) + qlog_path = route.qlog_paths()[0] + + if qlog_path is None: + continue + try: lr = LogReader(qlog_path) + dongles.append(dongle_id) for msg in lr: if msg.which() == "pandaState": - if msg.pandaState.pandaType not in ['uno', 'blackPanda']: - dongles.append(dongle_id) + if msg.pandaState.pandaType not in ['uno', 'blackPanda', 'dos']: break elif msg.which() == "carParams": @@ -58,24 +81,37 @@ if __name__ == "__main__": if len(car_fw) == 0: break - dongles.append(dongle_id) live_fingerprint = msg.carParams.carFingerprint + live_fingerprint = migration.get(live_fingerprint, live_fingerprint) if args.car is not None: live_fingerprint = args.car - if live_fingerprint not in list(TOYOTA_FINGERPRINTS.keys()) + list(HONDA_FINGERPRINTS.keys()) + list(HYUNDAI_FINGERPRINTS.keys()): + if live_fingerprint not in SUPPORTED_CARS: break - candidates = match_fw_to_car(car_fw) - if (len(candidates) == 1) and (list(candidates)[0] == live_fingerprint): - good += 1 - print("Correct", live_fingerprint, dongle_id) + fw_versions_dict = build_fw_dict(car_fw) + exact_matches = match_fw_to_car_exact(fw_versions_dict) + fuzzy_matches = match_fw_to_car_fuzzy(fw_versions_dict) + + if (len(exact_matches) == 1) and (list(exact_matches)[0] == live_fingerprint): + good_exact += 1 + print(f"Correct! Live: {live_fingerprint} - Fuzzy: {fuzzy_matches}") + + # Check if fuzzy match was correct + if len(fuzzy_matches) == 1: + if list(fuzzy_matches)[0] != live_fingerprint: + wrong_fuzzy += 1 + print(f"{dongle_id}|{time}") + print("Fuzzy match wrong! Fuzzy:", fuzzy_matches, "Live:", live_fingerprint) + else: + good_fuzzy += 1 break print(f"{dongle_id}|{time}") print("Old style:", live_fingerprint, "Vin", msg.carParams.carVin) - print("New style:", candidates) + print("New style (exact):", exact_matches) + print("New style (fuzzy):", fuzzy_matches) for version in car_fw: subaddr = None if version.subAddress == 0 else hex(version.subAddress) @@ -83,7 +119,7 @@ if __name__ == "__main__": print("Mismatches") found = False - for car_fws in [TOYOTA_FW_VERSIONS, HONDA_FW_VERSIONS, HYUNDAI_FW_VERSIONS]: + for car_fws in [TOYOTA_FW_VERSIONS, HONDA_FW_VERSIONS, HYUNDAI_FW_VERSIONS, VW_FW_VERSIONS]: if live_fingerprint in car_fws: found = True expected = car_fws[live_fingerprint] @@ -111,19 +147,24 @@ if __name__ == "__main__": mismatches[live_fingerprint].append(mismatch) print() - wrong += 1 + not_fingerprinted += 1 + + if len(fuzzy_matches) == 1: + if list(fuzzy_matches)[0] == live_fingerprint: + solved_by_fuzzy += 1 + else: + wrong_fuzzy += 1 + print("Fuzzy match wrong! Fuzzy:", fuzzy_matches, "Live:", live_fingerprint) + break except Exception: traceback.print_exc() except KeyboardInterrupt: break - print(f"Fingerprinted: {good} - Not fingerprinted: {wrong}") - print(f"Number of dongle ids checked: {len(dongles)}") print() - # Print FW versions that need to be added seperated out by car and address - for car, m in mismatches.items(): + for car, m in sorted(mismatches.items()): print(car) addrs = defaultdict(list) for (addr, sub_addr, version) in m: @@ -135,3 +176,15 @@ if __name__ == "__main__": print(f" {v},") print(" ]") print() + + print() + print(f"Number of dongle ids checked: {len(dongles)}") + print(f"Fingerprinted: {good_exact}") + print(f"Not fingerprinted: {not_fingerprinted}") + print(f" of which had a fuzzy match: {solved_by_fuzzy}") + + print() + print(f"Correct fuzzy matches: {good_fuzzy}") + print(f"Wrong fuzzy matches: {wrong_fuzzy}") + print() + diff --git a/selfdrive/hardware/base.h b/selfdrive/hardware/base.h index c82610d93..d9ce5c48c 100644 --- a/selfdrive/hardware/base.h +++ b/selfdrive/hardware/base.h @@ -3,20 +3,23 @@ #include #include - // no-op base hw class class HardwareNone { public: static constexpr float MAX_VOLUME = 0; static constexpr float MIN_VOLUME = 0; - static std::string get_os_version() { return "openpilot for PC"; }; + static std::string get_os_version() { return ""; } - static void reboot() {}; - static void poweroff() {}; - static void set_brightness(int percent) {}; - static void set_display_power(bool on) {}; + static void reboot() {} + static void poweroff() {} + static void set_brightness(int percent) {} + static void set_display_power(bool on) {} - static bool get_ssh_enabled() { return false; }; - static void set_ssh_enabled(bool enabled) {}; + static bool get_ssh_enabled() { return false; } + static void set_ssh_enabled(bool enabled) {} + + static bool PC() { return false; } + static bool EON() { return false; } + static bool TICI() { return false; } }; diff --git a/selfdrive/hardware/base.py b/selfdrive/hardware/base.py index 14a1a6f81..edfd02aad 100644 --- a/selfdrive/hardware/base.py +++ b/selfdrive/hardware/base.py @@ -105,3 +105,7 @@ class HardwareBase: @abstractmethod def set_screen_brightness(self, percentage): pass + + @abstractmethod + def set_power_save(self, enabled): + pass diff --git a/selfdrive/hardware/eon/hardware.h b/selfdrive/hardware/eon/hardware.h index bcf99a628..afd1f77be 100644 --- a/selfdrive/hardware/eon/hardware.h +++ b/selfdrive/hardware/eon/hardware.h @@ -15,6 +15,7 @@ public: static constexpr float MAX_VOLUME = 1.0; static constexpr float MIN_VOLUME = 0.5; + static bool EON() { return true; } static std::string get_os_version() { return "NEOS " + util::read_file("/VERSION"); }; @@ -47,6 +48,13 @@ public: int ret = std::system("dumpsys SurfaceFlinger --list | grep -Fq 'com.android.settings'"); launched_activity = ret == 0; } + + static void close_activities() { + if(launched_activity){ + std::system("pm disable com.android.settings && pm enable com.android.settings"); + } + } + static void launch_activity(std::string activity, std::string opts = "") { if (!launched_activity) { std::string cmd = "am start -n " + activity + " " + opts + diff --git a/selfdrive/hardware/eon/hardware.py b/selfdrive/hardware/eon/hardware.py index 2ef2a8f47..4f9a260cd 100644 --- a/selfdrive/hardware/eon/hardware.py +++ b/selfdrive/hardware/eon/hardware.py @@ -81,7 +81,7 @@ class Android(HardwareBase): def get_serial(self): ret = getprop("ro.serialno") - if ret == "": + if len(ret) == 0: ret = "cccccccc" return ret @@ -352,3 +352,6 @@ class Android(HardwareBase): def set_screen_brightness(self, percentage): with open("/sys/class/leds/lcd-backlight/brightness", "w") as f: f.write(str(int(percentage * 2.55))) + + def set_power_save(self, enabled): + pass diff --git a/selfdrive/hardware/hw.h b/selfdrive/hardware/hw.h index 0e0980f15..8112ba1c6 100644 --- a/selfdrive/hardware/hw.h +++ b/selfdrive/hardware/hw.h @@ -9,5 +9,10 @@ #include "selfdrive/hardware/tici/hardware.h" #define Hardware HardwareTici #else -#define Hardware HardwareNone +class HardwarePC : public HardwareNone { +public: + static std::string get_os_version() { return "openpilot for PC"; } + static bool PC() { return true; } +}; +#define Hardware HardwarePC #endif diff --git a/selfdrive/hardware/pc/hardware.py b/selfdrive/hardware/pc/hardware.py index 7ee40bd6b..edbc4e07b 100644 --- a/selfdrive/hardware/pc/hardware.py +++ b/selfdrive/hardware/pc/hardware.py @@ -79,3 +79,6 @@ class Pc(HardwareBase): def set_screen_brightness(self, percentage): pass + + def set_power_save(self, enabled): + pass diff --git a/selfdrive/hardware/tici/agnos.json b/selfdrive/hardware/tici/agnos.json index 1fa725b97..216b3b661 100644 --- a/selfdrive/hardware/tici/agnos.json +++ b/selfdrive/hardware/tici/agnos.json @@ -1,18 +1,18 @@ [ { "name": "system", - "url": "https://commadist.azureedge.net/agnosupdate-staging/system-990a4362f863f860d70440016005b434bcd17130547deafed96c720d0fc8495e.img.xz", - "hash": "f30370eda7253029ec1e4322fbb060ab69f541e4d5176c41541df608183cee4b", - "hash_raw": "990a4362f863f860d70440016005b434bcd17130547deafed96c720d0fc8495e", + "url": "https://commadist.azureedge.net/agnosupdate-staging/system-53d8287459de23ee65d00f004abd4a13aabdec39ff8d692e33ef4fb274b18439.img.xz", + "hash": "2d31d71fc8571de26fcb75e7ddd270ac60200bd9ab321bf03bee47bf13822b08", + "hash_raw": "53d8287459de23ee65d00f004abd4a13aabdec39ff8d692e33ef4fb274b18439", "size": 10737418240, "sparse": true }, { "name": "boot", - "url": "https://commadist.azureedge.net/agnosupdate-staging/boot-b8aebb538f030bbd8e69c227bee33f78ac3be0affe55dc76ab7e87e3f030eceb.img.xz", - "hash": "b8aebb538f030bbd8e69c227bee33f78ac3be0affe55dc76ab7e87e3f030eceb", - "hash_raw": "b8aebb538f030bbd8e69c227bee33f78ac3be0affe55dc76ab7e87e3f030eceb", - "size": 14768128, + "url": "https://commadist.azureedge.net/agnosupdate-staging/boot-60440a9427db1f255281b78e47dff79bb6b039f4cb99f5600fd9d962f6b2b360.img.xz", + "hash": "60440a9427db1f255281b78e47dff79bb6b039f4cb99f5600fd9d962f6b2b360", + "hash_raw": "60440a9427db1f255281b78e47dff79bb6b039f4cb99f5600fd9d962f6b2b360", + "size": 14772224, "sparse": false } ] diff --git a/selfdrive/hardware/tici/hardware.h b/selfdrive/hardware/tici/hardware.h index 034e01a86..0ff73b840 100644 --- a/selfdrive/hardware/tici/hardware.h +++ b/selfdrive/hardware/tici/hardware.h @@ -3,15 +3,15 @@ #include #include -#include "selfdrive/common/util.h" #include "selfdrive/common/params.h" +#include "selfdrive/common/util.h" #include "selfdrive/hardware/base.h" class HardwareTici : public HardwareNone { public: static constexpr float MAX_VOLUME = 0.5; static constexpr float MIN_VOLUME = 0.4; - + static bool TICI() { return true; } static std::string get_os_version() { return "AGNOS " + util::read_file("/VERSION"); }; @@ -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/hardware/tici/hardware.py b/selfdrive/hardware/tici/hardware.py index bdf2170c2..f277944aa 100644 --- a/selfdrive/hardware/tici/hardware.py +++ b/selfdrive/hardware/tici/hardware.py @@ -1,6 +1,7 @@ import os import subprocess from pathlib import Path +from smbus2 import SMBus from cereal import log from selfdrive.hardware.base import HardwareBase, ThermalConfig @@ -27,6 +28,14 @@ NetworkStrength = log.DeviceState.NetworkStrength MM_MODEM_ACCESS_TECHNOLOGY_UMTS = 1 << 5 MM_MODEM_ACCESS_TECHNOLOGY_LTE = 1 << 14 +AMP_I2C_BUS = 0 +AMP_ADDRESS = 0x10 + +def write_amplifier_reg(reg, val, offset, mask): + with SMBus(AMP_I2C_BUS) as bus: + v = bus.read_byte_data(AMP_ADDRESS, reg, force=True) + v = (v & (~mask)) | ((val << offset) & mask) + bus.write_byte_data(AMP_ADDRESS, reg, v, force=True) class Tici(HardwareBase): def __init__(self): @@ -191,3 +200,17 @@ class Tici(HardwareBase): f.write(str(int(percentage * 10.23))) except Exception: pass + + def set_power_save(self, enabled): + # amplifier, 100mW at idle + write_amplifier_reg(0x51, 0b0 if enabled else 0b1, 7, 0b10000000) + + # offline big cluster, leave core 4 online for boardd + for i in range(5, 8): + # TODO: fix permissions with udev + val = "0" if enabled else "1" + os.system(f"sudo su -c 'echo {val} > /sys/devices/system/cpu/cpu{i}/online'") + +if __name__ == "__main__": + import sys + Tici().set_power_save(bool(int(sys.argv[1]))) diff --git a/selfdrive/locationd/.gitignore b/selfdrive/locationd/.gitignore index 6ea757462..526890278 100644 --- a/selfdrive/locationd/.gitignore +++ b/selfdrive/locationd/.gitignore @@ -1,4 +1,5 @@ ubloxd ubloxd_test params_learner -paramsd \ No newline at end of file +paramsd +locationd diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index 43e5d1fec..4b7fba19b 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -1,8 +1,22 @@ -Import('env', 'common', 'cereal', 'messaging') +Import('env', 'common', 'cereal', 'messaging', 'libkf', 'transformations') -loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'pthread'] +loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'kaitai', 'pthread'] -env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "ubloxd_main.cc"], LIBS=loc_libs) +if GetOption('kaitai'): + generated = Dir('generated').srcnode().abspath + cmd = f"kaitai-struct-compiler --target cpp_stl --outdir {generated} $SOURCES" + env.Command(['generated/ubx.cpp', 'generated/ubx.h'], 'ubx.ksy', cmd) + env.Command(['generated/gps.cpp', 'generated/gps.h'], 'gps.ksy', cmd) -if GetOption("test"): - env.Program("ubloxd_test", ["ubloxd_test.cc", "ublox_msg.cc", "ubloxd_main.cc"], LIBS=loc_libs) +env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "generated/ubx.cpp", "generated/gps.cpp"], LIBS=loc_libs) + +ekf_sym_cc = env.SharedObject("#rednose/helpers/ekf_sym.cc") +locationd_sources = ["locationd.cc", "models/live_kf.cc", ekf_sym_cc] +lenv = env.Clone() +lenv["_LIBFLAGS"] += f' {libkf[0].get_labspath()}' +locationd = lenv.Program("locationd", locationd_sources, LIBS=loc_libs + transformations) +lenv.Depends(locationd, libkf) + +if File("liblocationd.cc").exists(): + liblocationd = lenv.SharedLibrary("liblocationd", ["liblocationd.cc"] + locationd_sources, LIBS=loc_libs + transformations) + lenv.Depends(liblocationd, libkf) diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index f9b857fbc..e8e4f32df 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -13,6 +13,7 @@ import json import numpy as np import cereal.messaging as messaging from cereal import car, log +from selfdrive.hardware import TICI from common.params import Params, put_nonblocking from common.transformations.model import model_height from common.transformations.camera import get_view_frame_from_road_frame @@ -63,7 +64,7 @@ class Calibrator(): # Read saved calibration params = Params() calibration_params = params.get("CalibrationParams") - + self.wide_camera = TICI and params.get_bool('EnableWideCamera') rpy_init = RPY_INIT valid_blocks = 0 @@ -80,7 +81,7 @@ class Calibrator(): rpy_init = list(msg.liveCalibration.rpyCalib) valid_blocks = msg.liveCalibration.validBlocks except (ValueError, capnp.lib.capnp.KjException): - # TODO: remove this when offroad can read capnp + # TODO: remove this after next release calibration_params = json.loads(calibration_params) rpy_init = calibration_params["calib_radians"] valid_blocks = calibration_params['valid_blocks'] @@ -134,10 +135,7 @@ class Calibrator(): write_this_cycle = (self.idx == 0) and (self.block_idx % (INPUTS_WANTED//5) == 5) if self.param_put and write_this_cycle: - # TODO: change to raw bytes when offroad can read capnp - cal_params = {"calib_radians": list(self.rpy), - "valid_blocks": int(self.valid_blocks)} - put_nonblocking("CalibrationParams", json.dumps(cal_params).encode('utf8')) + put_nonblocking("CalibrationParams", self.get_msg().to_bytes()) def handle_v_ego(self, v_ego): self.v_ego = v_ego @@ -152,9 +150,12 @@ class Calibrator(): self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) - certain_if_calib = ((np.arctan2(trans_std[1], trans[0]) < MAX_VEL_ANGLE_STD) or + if self.wide_camera: + angle_std_threshold = 4*MAX_VEL_ANGLE_STD + else: + angle_std_threshold = MAX_VEL_ANGLE_STD + certain_if_calib = ((np.arctan2(trans_std[1], trans[0]) < angle_std_threshold) or (self.valid_blocks < INPUTS_NEEDED)) - if not (straight_and_fast and certain_if_calib): return None diff --git a/selfdrive/locationd/generated/gps.cpp b/selfdrive/locationd/generated/gps.cpp new file mode 100644 index 000000000..9b020735b --- /dev/null +++ b/selfdrive/locationd/generated/gps.cpp @@ -0,0 +1,325 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "gps.h" +#include "kaitai/exceptions.h" + +gps_t::gps_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; + m_tlm = 0; + m_how = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::_read() { + m_tlm = new tlm_t(m__io, this, m__root); + m_how = new how_t(m__io, this, m__root); + n_body = true; + switch (how()->subframe_id()) { + case 1: { + n_body = false; + m_body = new subframe_1_t(m__io, this, m__root); + break; + } + case 2: { + n_body = false; + m_body = new subframe_2_t(m__io, this, m__root); + break; + } + case 3: { + n_body = false; + m_body = new subframe_3_t(m__io, this, m__root); + break; + } + case 4: { + n_body = false; + m_body = new subframe_4_t(m__io, this, m__root); + break; + } + } +} + +gps_t::~gps_t() { + _clean_up(); +} + +void gps_t::_clean_up() { + if (m_tlm) { + delete m_tlm; m_tlm = 0; + } + if (m_how) { + delete m_how; m_how = 0; + } + if (!n_body) { + if (m_body) { + delete m_body; m_body = 0; + } + } +} + +gps_t::subframe_1_t::subframe_1_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + f_af_0 = false; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::subframe_1_t::_read() { + m_week_no = m__io->read_bits_int_be(10); + m_code = m__io->read_bits_int_be(2); + m_sv_accuracy = m__io->read_bits_int_be(4); + m_sv_health = m__io->read_bits_int_be(6); + m_iodc_msb = m__io->read_bits_int_be(2); + m_l2_p_data_flag = m__io->read_bits_int_be(1); + m_reserved1 = m__io->read_bits_int_be(23); + m_reserved2 = m__io->read_bits_int_be(24); + m_reserved3 = m__io->read_bits_int_be(24); + m_reserved4 = m__io->read_bits_int_be(16); + m__io->align_to_byte(); + m_t_gd = m__io->read_s1(); + m_iodc_lsb = m__io->read_u1(); + m_t_oc = m__io->read_u2be(); + m_af_2 = m__io->read_s1(); + m_af_1 = m__io->read_s2be(); + m_af_0_sign = m__io->read_bits_int_be(1); + m_af_0_value = m__io->read_bits_int_be(21); + m_reserved5 = m__io->read_bits_int_be(2); +} + +gps_t::subframe_1_t::~subframe_1_t() { + _clean_up(); +} + +void gps_t::subframe_1_t::_clean_up() { +} + +int32_t gps_t::subframe_1_t::af_0() { + if (f_af_0) + return m_af_0; + m_af_0 = ((af_0_sign()) ? ((af_0_value() - (1 << 21))) : (af_0_value())); + f_af_0 = true; + return m_af_0; +} + +gps_t::subframe_3_t::subframe_3_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + f_omega_dot = false; + f_idot = false; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::subframe_3_t::_read() { + m_c_ic = m__io->read_s2be(); + m_omega_0 = m__io->read_s4be(); + m_c_is = m__io->read_s2be(); + m_i_0 = m__io->read_s4be(); + m_c_rc = m__io->read_s2be(); + m_omega = m__io->read_s4be(); + m_omega_dot_sign = m__io->read_bits_int_be(1); + m_omega_dot_value = m__io->read_bits_int_be(23); + m__io->align_to_byte(); + m_iode = m__io->read_u1(); + m_idot_sign = m__io->read_bits_int_be(1); + m_idot_value = m__io->read_bits_int_be(13); + m_reserved = m__io->read_bits_int_be(2); +} + +gps_t::subframe_3_t::~subframe_3_t() { + _clean_up(); +} + +void gps_t::subframe_3_t::_clean_up() { +} + +int32_t gps_t::subframe_3_t::omega_dot() { + if (f_omega_dot) + return m_omega_dot; + m_omega_dot = ((omega_dot_sign()) ? ((omega_dot_value() - (1 << 23))) : (omega_dot_value())); + f_omega_dot = true; + return m_omega_dot; +} + +int32_t gps_t::subframe_3_t::idot() { + if (f_idot) + return m_idot; + m_idot = ((idot_sign()) ? ((idot_value() - (1 << 13))) : (idot_value())); + f_idot = true; + return m_idot; +} + +gps_t::subframe_4_t::subframe_4_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::subframe_4_t::_read() { + m_data_id = m__io->read_bits_int_be(2); + m_page_id = m__io->read_bits_int_be(6); + m__io->align_to_byte(); + n_body = true; + switch (page_id()) { + case 56: { + n_body = false; + m_body = new ionosphere_data_t(m__io, this, m__root); + break; + } + } +} + +gps_t::subframe_4_t::~subframe_4_t() { + _clean_up(); +} + +void gps_t::subframe_4_t::_clean_up() { + if (!n_body) { + if (m_body) { + delete m_body; m_body = 0; + } + } +} + +gps_t::subframe_4_t::ionosphere_data_t::ionosphere_data_t(kaitai::kstream* p__io, gps_t::subframe_4_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::subframe_4_t::ionosphere_data_t::_read() { + m_a0 = m__io->read_s1(); + m_a1 = m__io->read_s1(); + m_a2 = m__io->read_s1(); + m_a3 = m__io->read_s1(); + m_b0 = m__io->read_s1(); + m_b1 = m__io->read_s1(); + m_b2 = m__io->read_s1(); + m_b3 = m__io->read_s1(); +} + +gps_t::subframe_4_t::ionosphere_data_t::~ionosphere_data_t() { + _clean_up(); +} + +void gps_t::subframe_4_t::ionosphere_data_t::_clean_up() { +} + +gps_t::how_t::how_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::how_t::_read() { + m_tow_count = m__io->read_bits_int_be(17); + m_alert = m__io->read_bits_int_be(1); + m_anti_spoof = m__io->read_bits_int_be(1); + m_subframe_id = m__io->read_bits_int_be(3); + m_reserved = m__io->read_bits_int_be(2); +} + +gps_t::how_t::~how_t() { + _clean_up(); +} + +void gps_t::how_t::_clean_up() { +} + +gps_t::tlm_t::tlm_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::tlm_t::_read() { + m_magic = m__io->read_bytes(1); + if (!(magic() == std::string("\x8B", 1))) { + throw kaitai::validation_not_equal_error(std::string("\x8B", 1), magic(), _io(), std::string("/types/tlm/seq/0")); + } + m_tlm = m__io->read_bits_int_be(14); + m_integrity_status = m__io->read_bits_int_be(1); + m_reserved = m__io->read_bits_int_be(1); +} + +gps_t::tlm_t::~tlm_t() { + _clean_up(); +} + +void gps_t::tlm_t::_clean_up() { +} + +gps_t::subframe_2_t::subframe_2_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void gps_t::subframe_2_t::_read() { + m_iode = m__io->read_u1(); + m_c_rs = m__io->read_s2be(); + m_delta_n = m__io->read_s2be(); + m_m_0 = m__io->read_s4be(); + m_c_uc = m__io->read_s2be(); + m_e = m__io->read_s4be(); + m_c_us = m__io->read_s2be(); + m_sqrt_a = m__io->read_u4be(); + m_t_oe = m__io->read_u2be(); + m_fit_interval_flag = m__io->read_bits_int_be(1); + m_aoda = m__io->read_bits_int_be(5); + m_reserved = m__io->read_bits_int_be(2); +} + +gps_t::subframe_2_t::~subframe_2_t() { + _clean_up(); +} + +void gps_t::subframe_2_t::_clean_up() { +} diff --git a/selfdrive/locationd/generated/gps.h b/selfdrive/locationd/generated/gps.h new file mode 100644 index 000000000..293e2e4a0 --- /dev/null +++ b/selfdrive/locationd/generated/gps.h @@ -0,0 +1,359 @@ +#ifndef GPS_H_ +#define GPS_H_ + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "kaitai/kaitaistruct.h" +#include + +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" +#endif + +class gps_t : public kaitai::kstruct { + +public: + class subframe_1_t; + class subframe_3_t; + class subframe_4_t; + class how_t; + class tlm_t; + class subframe_2_t; + + gps_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, gps_t* p__root = 0); + +private: + void _read(); + void _clean_up(); + +public: + ~gps_t(); + + class subframe_1_t : public kaitai::kstruct { + + public: + + subframe_1_t(kaitai::kstream* p__io, gps_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~subframe_1_t(); + + private: + bool f_af_0; + int32_t m_af_0; + + public: + int32_t af_0(); + + private: + uint64_t m_week_no; + uint64_t m_code; + uint64_t m_sv_accuracy; + uint64_t m_sv_health; + uint64_t m_iodc_msb; + bool m_l2_p_data_flag; + uint64_t m_reserved1; + uint64_t m_reserved2; + uint64_t m_reserved3; + uint64_t m_reserved4; + int8_t m_t_gd; + uint8_t m_iodc_lsb; + uint16_t m_t_oc; + int8_t m_af_2; + int16_t m_af_1; + bool m_af_0_sign; + uint64_t m_af_0_value; + uint64_t m_reserved5; + gps_t* m__root; + gps_t* m__parent; + + public: + uint64_t week_no() const { return m_week_no; } + uint64_t code() const { return m_code; } + uint64_t sv_accuracy() const { return m_sv_accuracy; } + uint64_t sv_health() const { return m_sv_health; } + uint64_t iodc_msb() const { return m_iodc_msb; } + bool l2_p_data_flag() const { return m_l2_p_data_flag; } + uint64_t reserved1() const { return m_reserved1; } + uint64_t reserved2() const { return m_reserved2; } + uint64_t reserved3() const { return m_reserved3; } + uint64_t reserved4() const { return m_reserved4; } + int8_t t_gd() const { return m_t_gd; } + uint8_t iodc_lsb() const { return m_iodc_lsb; } + uint16_t t_oc() const { return m_t_oc; } + int8_t af_2() const { return m_af_2; } + int16_t af_1() const { return m_af_1; } + bool af_0_sign() const { return m_af_0_sign; } + uint64_t af_0_value() const { return m_af_0_value; } + uint64_t reserved5() const { return m_reserved5; } + gps_t* _root() const { return m__root; } + gps_t* _parent() const { return m__parent; } + }; + + class subframe_3_t : public kaitai::kstruct { + + public: + + subframe_3_t(kaitai::kstream* p__io, gps_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~subframe_3_t(); + + private: + bool f_omega_dot; + int32_t m_omega_dot; + + public: + int32_t omega_dot(); + + private: + bool f_idot; + int32_t m_idot; + + public: + int32_t idot(); + + private: + int16_t m_c_ic; + int32_t m_omega_0; + int16_t m_c_is; + int32_t m_i_0; + int16_t m_c_rc; + int32_t m_omega; + bool m_omega_dot_sign; + uint64_t m_omega_dot_value; + uint8_t m_iode; + bool m_idot_sign; + uint64_t m_idot_value; + uint64_t m_reserved; + gps_t* m__root; + gps_t* m__parent; + + public: + int16_t c_ic() const { return m_c_ic; } + int32_t omega_0() const { return m_omega_0; } + int16_t c_is() const { return m_c_is; } + int32_t i_0() const { return m_i_0; } + int16_t c_rc() const { return m_c_rc; } + int32_t omega() const { return m_omega; } + bool omega_dot_sign() const { return m_omega_dot_sign; } + uint64_t omega_dot_value() const { return m_omega_dot_value; } + uint8_t iode() const { return m_iode; } + bool idot_sign() const { return m_idot_sign; } + uint64_t idot_value() const { return m_idot_value; } + uint64_t reserved() const { return m_reserved; } + gps_t* _root() const { return m__root; } + gps_t* _parent() const { return m__parent; } + }; + + class subframe_4_t : public kaitai::kstruct { + + public: + class ionosphere_data_t; + + subframe_4_t(kaitai::kstream* p__io, gps_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~subframe_4_t(); + + class ionosphere_data_t : public kaitai::kstruct { + + public: + + ionosphere_data_t(kaitai::kstream* p__io, gps_t::subframe_4_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~ionosphere_data_t(); + + private: + int8_t m_a0; + int8_t m_a1; + int8_t m_a2; + int8_t m_a3; + int8_t m_b0; + int8_t m_b1; + int8_t m_b2; + int8_t m_b3; + gps_t* m__root; + gps_t::subframe_4_t* m__parent; + + public: + int8_t a0() const { return m_a0; } + int8_t a1() const { return m_a1; } + int8_t a2() const { return m_a2; } + int8_t a3() const { return m_a3; } + int8_t b0() const { return m_b0; } + int8_t b1() const { return m_b1; } + int8_t b2() const { return m_b2; } + int8_t b3() const { return m_b3; } + gps_t* _root() const { return m__root; } + gps_t::subframe_4_t* _parent() const { return m__parent; } + }; + + private: + uint64_t m_data_id; + uint64_t m_page_id; + ionosphere_data_t* m_body; + bool n_body; + + public: + bool _is_null_body() { body(); return n_body; }; + + private: + gps_t* m__root; + gps_t* m__parent; + + public: + uint64_t data_id() const { return m_data_id; } + uint64_t page_id() const { return m_page_id; } + ionosphere_data_t* body() const { return m_body; } + gps_t* _root() const { return m__root; } + gps_t* _parent() const { return m__parent; } + }; + + class how_t : public kaitai::kstruct { + + public: + + how_t(kaitai::kstream* p__io, gps_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~how_t(); + + private: + uint64_t m_tow_count; + bool m_alert; + bool m_anti_spoof; + uint64_t m_subframe_id; + uint64_t m_reserved; + gps_t* m__root; + gps_t* m__parent; + + public: + uint64_t tow_count() const { return m_tow_count; } + bool alert() const { return m_alert; } + bool anti_spoof() const { return m_anti_spoof; } + uint64_t subframe_id() const { return m_subframe_id; } + uint64_t reserved() const { return m_reserved; } + gps_t* _root() const { return m__root; } + gps_t* _parent() const { return m__parent; } + }; + + class tlm_t : public kaitai::kstruct { + + public: + + tlm_t(kaitai::kstream* p__io, gps_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~tlm_t(); + + private: + std::string m_magic; + uint64_t m_tlm; + bool m_integrity_status; + bool m_reserved; + gps_t* m__root; + gps_t* m__parent; + + public: + std::string magic() const { return m_magic; } + uint64_t tlm() const { return m_tlm; } + bool integrity_status() const { return m_integrity_status; } + bool reserved() const { return m_reserved; } + gps_t* _root() const { return m__root; } + gps_t* _parent() const { return m__parent; } + }; + + class subframe_2_t : public kaitai::kstruct { + + public: + + subframe_2_t(kaitai::kstream* p__io, gps_t* p__parent = 0, gps_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~subframe_2_t(); + + private: + uint8_t m_iode; + int16_t m_c_rs; + int16_t m_delta_n; + int32_t m_m_0; + int16_t m_c_uc; + int32_t m_e; + int16_t m_c_us; + uint32_t m_sqrt_a; + uint16_t m_t_oe; + bool m_fit_interval_flag; + uint64_t m_aoda; + uint64_t m_reserved; + gps_t* m__root; + gps_t* m__parent; + + public: + uint8_t iode() const { return m_iode; } + int16_t c_rs() const { return m_c_rs; } + int16_t delta_n() const { return m_delta_n; } + int32_t m_0() const { return m_m_0; } + int16_t c_uc() const { return m_c_uc; } + int32_t e() const { return m_e; } + int16_t c_us() const { return m_c_us; } + uint32_t sqrt_a() const { return m_sqrt_a; } + uint16_t t_oe() const { return m_t_oe; } + bool fit_interval_flag() const { return m_fit_interval_flag; } + uint64_t aoda() const { return m_aoda; } + uint64_t reserved() const { return m_reserved; } + gps_t* _root() const { return m__root; } + gps_t* _parent() const { return m__parent; } + }; + +private: + tlm_t* m_tlm; + how_t* m_how; + kaitai::kstruct* m_body; + bool n_body; + +public: + bool _is_null_body() { body(); return n_body; }; + +private: + gps_t* m__root; + kaitai::kstruct* m__parent; + +public: + tlm_t* tlm() const { return m_tlm; } + how_t* how() const { return m_how; } + kaitai::kstruct* body() const { return m_body; } + gps_t* _root() const { return m__root; } + kaitai::kstruct* _parent() const { return m__parent; } +}; + +#endif // GPS_H_ diff --git a/selfdrive/locationd/generated/ubx.cpp b/selfdrive/locationd/generated/ubx.cpp new file mode 100644 index 000000000..5e743e1ee --- /dev/null +++ b/selfdrive/locationd/generated/ubx.cpp @@ -0,0 +1,340 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "ubx.h" +#include "kaitai/exceptions.h" + +ubx_t::ubx_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; + f_checksum = false; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::_read() { + m_magic = m__io->read_bytes(2); + if (!(magic() == std::string("\xB5\x62", 2))) { + throw kaitai::validation_not_equal_error(std::string("\xB5\x62", 2), magic(), _io(), std::string("/seq/0")); + } + m_msg_type = m__io->read_u2be(); + m_length = m__io->read_u2le(); + n_body = true; + switch (msg_type()) { + case 2569: { + n_body = false; + m_body = new mon_hw_t(m__io, this, m__root); + break; + } + case 533: { + n_body = false; + m_body = new rxm_rawx_t(m__io, this, m__root); + break; + } + case 531: { + n_body = false; + m_body = new rxm_sfrbx_t(m__io, this, m__root); + break; + } + case 2571: { + n_body = false; + m_body = new mon_hw2_t(m__io, this, m__root); + break; + } + case 263: { + n_body = false; + m_body = new nav_pvt_t(m__io, this, m__root); + break; + } + } +} + +ubx_t::~ubx_t() { + _clean_up(); +} + +void ubx_t::_clean_up() { + if (!n_body) { + if (m_body) { + delete m_body; m_body = 0; + } + } + if (f_checksum) { + } +} + +ubx_t::rxm_rawx_t::rxm_rawx_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_measurements = 0; + m__raw_measurements = 0; + m__io__raw_measurements = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::rxm_rawx_t::_read() { + m_rcv_tow = m__io->read_f8le(); + m_week = m__io->read_u2le(); + m_leap_s = m__io->read_s1(); + m_num_meas = m__io->read_u1(); + m_rec_stat = m__io->read_u1(); + m_reserved1 = m__io->read_bytes(3); + int l_measurements = num_meas(); + m__raw_measurements = new std::vector(); + m__raw_measurements->reserve(l_measurements); + m__io__raw_measurements = new std::vector(); + m__io__raw_measurements->reserve(l_measurements); + m_measurements = new std::vector(); + m_measurements->reserve(l_measurements); + for (int i = 0; i < l_measurements; i++) { + m__raw_measurements->push_back(m__io->read_bytes(32)); + kaitai::kstream* io__raw_measurements = new kaitai::kstream(m__raw_measurements->at(m__raw_measurements->size() - 1)); + m__io__raw_measurements->push_back(io__raw_measurements); + m_measurements->push_back(new meas_t(io__raw_measurements, this, m__root)); + } +} + +ubx_t::rxm_rawx_t::~rxm_rawx_t() { + _clean_up(); +} + +void ubx_t::rxm_rawx_t::_clean_up() { + if (m__raw_measurements) { + delete m__raw_measurements; m__raw_measurements = 0; + } + if (m__io__raw_measurements) { + for (std::vector::iterator it = m__io__raw_measurements->begin(); it != m__io__raw_measurements->end(); ++it) { + delete *it; + } + delete m__io__raw_measurements; m__io__raw_measurements = 0; + } + if (m_measurements) { + for (std::vector::iterator it = m_measurements->begin(); it != m_measurements->end(); ++it) { + delete *it; + } + delete m_measurements; m_measurements = 0; + } +} + +ubx_t::rxm_rawx_t::meas_t::meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::rxm_rawx_t::meas_t::_read() { + m_pr_mes = m__io->read_f8le(); + m_cp_mes = m__io->read_f8le(); + m_do_mes = m__io->read_f4le(); + m_gnss_id = static_cast(m__io->read_u1()); + m_sv_id = m__io->read_u1(); + m_reserved2 = m__io->read_bytes(1); + m_freq_id = m__io->read_u1(); + m_lock_time = m__io->read_u2le(); + m_cno = m__io->read_u1(); + m_pr_stdev = m__io->read_u1(); + m_cp_stdev = m__io->read_u1(); + m_do_stdev = m__io->read_u1(); + m_trk_stat = m__io->read_u1(); + m_reserved3 = m__io->read_bytes(1); +} + +ubx_t::rxm_rawx_t::meas_t::~meas_t() { + _clean_up(); +} + +void ubx_t::rxm_rawx_t::meas_t::_clean_up() { +} + +ubx_t::rxm_sfrbx_t::rxm_sfrbx_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_body = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::rxm_sfrbx_t::_read() { + m_gnss_id = static_cast(m__io->read_u1()); + m_sv_id = m__io->read_u1(); + m_reserved1 = m__io->read_bytes(1); + m_freq_id = m__io->read_u1(); + m_num_words = m__io->read_u1(); + m_reserved2 = m__io->read_bytes(1); + m_version = m__io->read_u1(); + m_reserved3 = m__io->read_bytes(1); + int l_body = num_words(); + m_body = new std::vector(); + m_body->reserve(l_body); + for (int i = 0; i < l_body; i++) { + m_body->push_back(m__io->read_u4le()); + } +} + +ubx_t::rxm_sfrbx_t::~rxm_sfrbx_t() { + _clean_up(); +} + +void ubx_t::rxm_sfrbx_t::_clean_up() { + if (m_body) { + delete m_body; m_body = 0; + } +} + +ubx_t::nav_pvt_t::nav_pvt_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::nav_pvt_t::_read() { + m_i_tow = m__io->read_u4le(); + m_year = m__io->read_u2le(); + m_month = m__io->read_u1(); + m_day = m__io->read_u1(); + m_hour = m__io->read_u1(); + m_min = m__io->read_u1(); + m_sec = m__io->read_u1(); + m_valid = m__io->read_u1(); + m_t_acc = m__io->read_u4le(); + m_nano = m__io->read_s4le(); + m_fix_type = m__io->read_u1(); + m_flags = m__io->read_u1(); + m_flags2 = m__io->read_u1(); + m_num_sv = m__io->read_u1(); + m_lon = m__io->read_s4le(); + m_lat = m__io->read_s4le(); + m_height = m__io->read_s4le(); + m_h_msl = m__io->read_s4le(); + m_h_acc = m__io->read_u4le(); + m_v_acc = m__io->read_u4le(); + m_vel_n = m__io->read_s4le(); + m_vel_e = m__io->read_s4le(); + m_vel_d = m__io->read_s4le(); + m_g_speed = m__io->read_s4le(); + m_head_mot = m__io->read_s4le(); + m_s_acc = m__io->read_s4le(); + m_head_acc = m__io->read_u4le(); + m_p_dop = m__io->read_u2le(); + m_flags3 = m__io->read_u1(); + m_reserved1 = m__io->read_bytes(5); + m_head_veh = m__io->read_s4le(); + m_mag_dec = m__io->read_s2le(); + m_mag_acc = m__io->read_u2le(); +} + +ubx_t::nav_pvt_t::~nav_pvt_t() { + _clean_up(); +} + +void ubx_t::nav_pvt_t::_clean_up() { +} + +ubx_t::mon_hw2_t::mon_hw2_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::mon_hw2_t::_read() { + m_ofs_i = m__io->read_s1(); + m_mag_i = m__io->read_u1(); + m_ofs_q = m__io->read_s1(); + m_mag_q = m__io->read_u1(); + m_cfg_source = static_cast(m__io->read_u1()); + m_reserved1 = m__io->read_bytes(3); + m_low_lev_cfg = m__io->read_u4le(); + m_reserved2 = m__io->read_bytes(8); + m_post_status = m__io->read_u4le(); + m_reserved3 = m__io->read_bytes(4); +} + +ubx_t::mon_hw2_t::~mon_hw2_t() { + _clean_up(); +} + +void ubx_t::mon_hw2_t::_clean_up() { +} + +ubx_t::mon_hw_t::mon_hw_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::mon_hw_t::_read() { + m_pin_sel = m__io->read_u4le(); + m_pin_bank = m__io->read_u4le(); + m_pin_dir = m__io->read_u4le(); + m_pin_val = m__io->read_u4le(); + m_noise_per_ms = m__io->read_u2le(); + m_agc_cnt = m__io->read_u2le(); + m_a_status = static_cast(m__io->read_u1()); + m_a_power = static_cast(m__io->read_u1()); + m_flags = m__io->read_u1(); + m_reserved1 = m__io->read_bytes(1); + m_used_mask = m__io->read_u4le(); + m_vp = m__io->read_bytes(17); + m_jam_ind = m__io->read_u1(); + m_reserved2 = m__io->read_bytes(2); + m_pin_irq = m__io->read_u4le(); + m_pull_h = m__io->read_u4le(); + m_pull_l = m__io->read_u4le(); +} + +ubx_t::mon_hw_t::~mon_hw_t() { + _clean_up(); +} + +void ubx_t::mon_hw_t::_clean_up() { +} + +uint16_t ubx_t::checksum() { + if (f_checksum) + return m_checksum; + std::streampos _pos = m__io->pos(); + m__io->seek((length() + 6)); + m_checksum = m__io->read_u2le(); + m__io->seek(_pos); + f_checksum = true; + return m_checksum; +} diff --git a/selfdrive/locationd/generated/ubx.h b/selfdrive/locationd/generated/ubx.h new file mode 100644 index 000000000..6be4ce8c4 --- /dev/null +++ b/selfdrive/locationd/generated/ubx.h @@ -0,0 +1,410 @@ +#ifndef UBX_H_ +#define UBX_H_ + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "kaitai/kaitaistruct.h" +#include +#include + +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" +#endif + +class ubx_t : public kaitai::kstruct { + +public: + class rxm_rawx_t; + class rxm_sfrbx_t; + class nav_pvt_t; + class mon_hw2_t; + class mon_hw_t; + + enum gnss_type_t { + GNSS_TYPE_GPS = 0, + GNSS_TYPE_SBAS = 1, + GNSS_TYPE_GALILEO = 2, + GNSS_TYPE_BEIDOU = 3, + GNSS_TYPE_IMES = 4, + GNSS_TYPE_QZSS = 5, + GNSS_TYPE_GLONASS = 6 + }; + + ubx_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, ubx_t* p__root = 0); + +private: + void _read(); + void _clean_up(); + +public: + ~ubx_t(); + + class rxm_rawx_t : public kaitai::kstruct { + + public: + class meas_t; + + rxm_rawx_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~rxm_rawx_t(); + + class meas_t : public kaitai::kstruct { + + public: + + meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~meas_t(); + + private: + double m_pr_mes; + double m_cp_mes; + float m_do_mes; + gnss_type_t m_gnss_id; + uint8_t m_sv_id; + std::string m_reserved2; + uint8_t m_freq_id; + uint16_t m_lock_time; + uint8_t m_cno; + uint8_t m_pr_stdev; + uint8_t m_cp_stdev; + uint8_t m_do_stdev; + uint8_t m_trk_stat; + std::string m_reserved3; + ubx_t* m__root; + ubx_t::rxm_rawx_t* m__parent; + + public: + double pr_mes() const { return m_pr_mes; } + double cp_mes() const { return m_cp_mes; } + float do_mes() const { return m_do_mes; } + gnss_type_t gnss_id() const { return m_gnss_id; } + uint8_t sv_id() const { return m_sv_id; } + std::string reserved2() const { return m_reserved2; } + uint8_t freq_id() const { return m_freq_id; } + uint16_t lock_time() const { return m_lock_time; } + uint8_t cno() const { return m_cno; } + uint8_t pr_stdev() const { return m_pr_stdev; } + uint8_t cp_stdev() const { return m_cp_stdev; } + uint8_t do_stdev() const { return m_do_stdev; } + uint8_t trk_stat() const { return m_trk_stat; } + std::string reserved3() const { return m_reserved3; } + ubx_t* _root() const { return m__root; } + ubx_t::rxm_rawx_t* _parent() const { return m__parent; } + }; + + private: + double m_rcv_tow; + uint16_t m_week; + int8_t m_leap_s; + uint8_t m_num_meas; + uint8_t m_rec_stat; + std::string m_reserved1; + std::vector* m_measurements; + ubx_t* m__root; + ubx_t* m__parent; + std::vector* m__raw_measurements; + std::vector* m__io__raw_measurements; + + public: + double rcv_tow() const { return m_rcv_tow; } + uint16_t week() const { return m_week; } + int8_t leap_s() const { return m_leap_s; } + uint8_t num_meas() const { return m_num_meas; } + uint8_t rec_stat() const { return m_rec_stat; } + std::string reserved1() const { return m_reserved1; } + std::vector* measurements() const { return m_measurements; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + std::vector* _raw_measurements() const { return m__raw_measurements; } + std::vector* _io__raw_measurements() const { return m__io__raw_measurements; } + }; + + class rxm_sfrbx_t : public kaitai::kstruct { + + public: + + rxm_sfrbx_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~rxm_sfrbx_t(); + + private: + gnss_type_t m_gnss_id; + uint8_t m_sv_id; + std::string m_reserved1; + uint8_t m_freq_id; + uint8_t m_num_words; + std::string m_reserved2; + uint8_t m_version; + std::string m_reserved3; + std::vector* m_body; + ubx_t* m__root; + ubx_t* m__parent; + + public: + gnss_type_t gnss_id() const { return m_gnss_id; } + uint8_t sv_id() const { return m_sv_id; } + std::string reserved1() const { return m_reserved1; } + uint8_t freq_id() const { return m_freq_id; } + uint8_t num_words() const { return m_num_words; } + std::string reserved2() const { return m_reserved2; } + uint8_t version() const { return m_version; } + std::string reserved3() const { return m_reserved3; } + std::vector* body() const { return m_body; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + }; + + class nav_pvt_t : public kaitai::kstruct { + + public: + + nav_pvt_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~nav_pvt_t(); + + private: + uint32_t m_i_tow; + uint16_t m_year; + uint8_t m_month; + uint8_t m_day; + uint8_t m_hour; + uint8_t m_min; + uint8_t m_sec; + uint8_t m_valid; + uint32_t m_t_acc; + int32_t m_nano; + uint8_t m_fix_type; + uint8_t m_flags; + uint8_t m_flags2; + uint8_t m_num_sv; + int32_t m_lon; + int32_t m_lat; + int32_t m_height; + int32_t m_h_msl; + uint32_t m_h_acc; + uint32_t m_v_acc; + int32_t m_vel_n; + int32_t m_vel_e; + int32_t m_vel_d; + int32_t m_g_speed; + int32_t m_head_mot; + int32_t m_s_acc; + uint32_t m_head_acc; + uint16_t m_p_dop; + uint8_t m_flags3; + std::string m_reserved1; + int32_t m_head_veh; + int16_t m_mag_dec; + uint16_t m_mag_acc; + ubx_t* m__root; + ubx_t* m__parent; + + public: + uint32_t i_tow() const { return m_i_tow; } + uint16_t year() const { return m_year; } + uint8_t month() const { return m_month; } + uint8_t day() const { return m_day; } + uint8_t hour() const { return m_hour; } + uint8_t min() const { return m_min; } + uint8_t sec() const { return m_sec; } + uint8_t valid() const { return m_valid; } + uint32_t t_acc() const { return m_t_acc; } + int32_t nano() const { return m_nano; } + uint8_t fix_type() const { return m_fix_type; } + uint8_t flags() const { return m_flags; } + uint8_t flags2() const { return m_flags2; } + uint8_t num_sv() const { return m_num_sv; } + int32_t lon() const { return m_lon; } + int32_t lat() const { return m_lat; } + int32_t height() const { return m_height; } + int32_t h_msl() const { return m_h_msl; } + uint32_t h_acc() const { return m_h_acc; } + uint32_t v_acc() const { return m_v_acc; } + int32_t vel_n() const { return m_vel_n; } + int32_t vel_e() const { return m_vel_e; } + int32_t vel_d() const { return m_vel_d; } + int32_t g_speed() const { return m_g_speed; } + int32_t head_mot() const { return m_head_mot; } + int32_t s_acc() const { return m_s_acc; } + uint32_t head_acc() const { return m_head_acc; } + uint16_t p_dop() const { return m_p_dop; } + uint8_t flags3() const { return m_flags3; } + std::string reserved1() const { return m_reserved1; } + int32_t head_veh() const { return m_head_veh; } + int16_t mag_dec() const { return m_mag_dec; } + uint16_t mag_acc() const { return m_mag_acc; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + }; + + class mon_hw2_t : public kaitai::kstruct { + + public: + + enum config_source_t { + CONFIG_SOURCE_FLASH = 102, + CONFIG_SOURCE_OTP = 111, + CONFIG_SOURCE_CONFIG_PINS = 112, + CONFIG_SOURCE_ROM = 113 + }; + + mon_hw2_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~mon_hw2_t(); + + private: + int8_t m_ofs_i; + uint8_t m_mag_i; + int8_t m_ofs_q; + uint8_t m_mag_q; + config_source_t m_cfg_source; + std::string m_reserved1; + uint32_t m_low_lev_cfg; + std::string m_reserved2; + uint32_t m_post_status; + std::string m_reserved3; + ubx_t* m__root; + ubx_t* m__parent; + + public: + int8_t ofs_i() const { return m_ofs_i; } + uint8_t mag_i() const { return m_mag_i; } + int8_t ofs_q() const { return m_ofs_q; } + uint8_t mag_q() const { return m_mag_q; } + config_source_t cfg_source() const { return m_cfg_source; } + std::string reserved1() const { return m_reserved1; } + uint32_t low_lev_cfg() const { return m_low_lev_cfg; } + std::string reserved2() const { return m_reserved2; } + uint32_t post_status() const { return m_post_status; } + std::string reserved3() const { return m_reserved3; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + }; + + class mon_hw_t : public kaitai::kstruct { + + public: + + enum antenna_status_t { + ANTENNA_STATUS_INIT = 0, + ANTENNA_STATUS_DONTKNOW = 1, + ANTENNA_STATUS_OK = 2, + ANTENNA_STATUS_SHORT = 3, + ANTENNA_STATUS_OPEN = 4 + }; + + enum antenna_power_t { + ANTENNA_POWER_FALSE = 0, + ANTENNA_POWER_TRUE = 1, + ANTENNA_POWER_DONTKNOW = 2 + }; + + mon_hw_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~mon_hw_t(); + + private: + uint32_t m_pin_sel; + uint32_t m_pin_bank; + uint32_t m_pin_dir; + uint32_t m_pin_val; + uint16_t m_noise_per_ms; + uint16_t m_agc_cnt; + antenna_status_t m_a_status; + antenna_power_t m_a_power; + uint8_t m_flags; + std::string m_reserved1; + uint32_t m_used_mask; + std::string m_vp; + uint8_t m_jam_ind; + std::string m_reserved2; + uint32_t m_pin_irq; + uint32_t m_pull_h; + uint32_t m_pull_l; + ubx_t* m__root; + ubx_t* m__parent; + + public: + uint32_t pin_sel() const { return m_pin_sel; } + uint32_t pin_bank() const { return m_pin_bank; } + uint32_t pin_dir() const { return m_pin_dir; } + uint32_t pin_val() const { return m_pin_val; } + uint16_t noise_per_ms() const { return m_noise_per_ms; } + uint16_t agc_cnt() const { return m_agc_cnt; } + antenna_status_t a_status() const { return m_a_status; } + antenna_power_t a_power() const { return m_a_power; } + uint8_t flags() const { return m_flags; } + std::string reserved1() const { return m_reserved1; } + uint32_t used_mask() const { return m_used_mask; } + std::string vp() const { return m_vp; } + uint8_t jam_ind() const { return m_jam_ind; } + std::string reserved2() const { return m_reserved2; } + uint32_t pin_irq() const { return m_pin_irq; } + uint32_t pull_h() const { return m_pull_h; } + uint32_t pull_l() const { return m_pull_l; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + }; + +private: + bool f_checksum; + uint16_t m_checksum; + +public: + uint16_t checksum(); + +private: + std::string m_magic; + uint16_t m_msg_type; + uint16_t m_length; + kaitai::kstruct* m_body; + bool n_body; + +public: + bool _is_null_body() { body(); return n_body; }; + +private: + ubx_t* m__root; + kaitai::kstruct* m__parent; + +public: + std::string magic() const { return m_magic; } + uint16_t msg_type() const { return m_msg_type; } + uint16_t length() const { return m_length; } + kaitai::kstruct* body() const { return m_body; } + ubx_t* _root() const { return m__root; } + kaitai::kstruct* _parent() const { return m__parent; } +}; + +#endif // UBX_H_ diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc new file mode 100755 index 000000000..b9749bb70 --- /dev/null +++ b/selfdrive/locationd/locationd.cc @@ -0,0 +1,457 @@ +#include +#include + +#include "locationd.h" + +using namespace EKFS; +using namespace Eigen; + +ExitHandler do_exit; +const double ACCEL_SANITY_CHECK = 100.0; // m/s^2 +const double ROTATION_SANITY_CHECK = 10.0; // rad/s +const double TRANS_SANITY_CHECK = 200.0; // m/s +const double CALIB_RPY_SANITY_CHECK = 0.5; // rad (+- 30 deg) +const double ALTITUDE_SANITY_CHECK = 10000; // m +const double MIN_STD_SANITY_CHECK = 1e-5; // m or rad + +static VectorXd floatlist2vector(const capnp::List::Reader& floatlist) { + VectorXd res(floatlist.size()); + for (int i = 0; i < floatlist.size(); i++) { + res[i] = floatlist[i]; + } + return res; +} + +static Vector4d quat2vector(const Quaterniond& quat) { + return Vector4d(quat.w(), quat.x(), quat.y(), quat.z()); +} + +static Quaterniond vector2quat(const VectorXd& vec) { + return Quaterniond(vec(0), vec(1), vec(2), vec(3)); +} + +static void init_measurement(cereal::LiveLocationKalman::Measurement::Builder meas, const VectorXd& val, const VectorXd& std, bool valid) { + meas.setValue(kj::arrayPtr(val.data(), val.size())); + meas.setStd(kj::arrayPtr(std.data(), std.size())); + meas.setValid(valid); +} + + +static MatrixXdr rotate_cov(const MatrixXdr& rot_matrix, const MatrixXdr& cov_in) { + // To rotate a covariance matrix, the cov matrix needs to multiplied left and right by the transform matrix + return ((rot_matrix * cov_in) * rot_matrix.transpose()); +} + +static VectorXd rotate_std(const MatrixXdr& rot_matrix, const VectorXd& std_in) { + // Stds cannot be rotated like values, only covariances can be rotated + return rotate_cov(rot_matrix, std_in.array().square().matrix().asDiagonal()).diagonal().array().sqrt(); +} + +Localizer::Localizer() { + this->kf = std::make_unique(); + this->reset_kalman(); + + this->calib = Vector3d(0.0, 0.0, 0.0); + this->device_from_calib = MatrixXdr::Identity(3, 3); + this->calib_from_device = MatrixXdr::Identity(3, 3); + + for (int i = 0; i < POSENET_STD_HIST_HALF * 2; i++) { + this->posenet_stds.push_back(10.0); + } + + VectorXd ecef_pos = this->kf->get_x().segment(STATE_ECEF_POS_START); + this->converter = std::make_unique((ECEF) { .x = ecef_pos[0], .y = ecef_pos[1], .z = ecef_pos[2] }); +} + +void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { + VectorXd predicted_state = this->kf->get_x(); + MatrixXdr predicted_cov = this->kf->get_P(); + VectorXd predicted_std = predicted_cov.diagonal().array().sqrt(); + + VectorXd fix_ecef = predicted_state.segment(STATE_ECEF_POS_START); + ECEF fix_ecef_ecef = { .x = fix_ecef(0), .y = fix_ecef(1), .z = fix_ecef(2) }; + VectorXd fix_ecef_std = predicted_std.segment(STATE_ECEF_POS_ERR_START); + VectorXd vel_ecef = predicted_state.segment(STATE_ECEF_VELOCITY_START); + VectorXd vel_ecef_std = predicted_std.segment(STATE_ECEF_VELOCITY_ERR_START); + VectorXd fix_pos_geo_vec = this->get_position_geodetic(); + //fix_pos_geo_std = np.abs(coord.ecef2geodetic(fix_ecef + fix_ecef_std) - fix_pos_geo) + VectorXd orientation_ecef = quat2euler(vector2quat(predicted_state.segment(STATE_ECEF_ORIENTATION_START))); + VectorXd orientation_ecef_std = predicted_std.segment(STATE_ECEF_ORIENTATION_ERR_START); + MatrixXdr device_from_ecef = quat2rot(vector2quat(predicted_state.segment(STATE_ECEF_ORIENTATION_START))).transpose(); + VectorXd calibrated_orientation_ecef = rot2euler(this->calib_from_device * device_from_ecef); + + VectorXd acc_calib = this->calib_from_device * predicted_state.segment(STATE_ACCELERATION_START); + MatrixXdr acc_calib_cov = predicted_cov.block(STATE_ACCELERATION_ERR_START, STATE_ACCELERATION_ERR_START); + VectorXd acc_calib_std = rotate_cov(this->calib_from_device, acc_calib_cov).diagonal().array().sqrt(); + VectorXd ang_vel_calib = this->calib_from_device * predicted_state.segment(STATE_ANGULAR_VELOCITY_START); + + MatrixXdr vel_angular_cov = predicted_cov.block(STATE_ANGULAR_VELOCITY_ERR_START, STATE_ANGULAR_VELOCITY_ERR_START); + VectorXd ang_vel_calib_std = rotate_cov(this->calib_from_device, vel_angular_cov).diagonal().array().sqrt(); + + VectorXd vel_device = device_from_ecef * vel_ecef; + VectorXd device_from_ecef_eul = quat2euler(vector2quat(predicted_state.segment(STATE_ECEF_ORIENTATION_START))).transpose(); + MatrixXdr condensed_cov(STATE_ECEF_ORIENTATION_ERR_LEN + STATE_ECEF_VELOCITY_ERR_LEN, STATE_ECEF_ORIENTATION_ERR_LEN + STATE_ECEF_VELOCITY_ERR_LEN); + condensed_cov.topLeftCorner() = + predicted_cov.block(STATE_ECEF_ORIENTATION_ERR_START, STATE_ECEF_ORIENTATION_ERR_START); + condensed_cov.topRightCorner() = + predicted_cov.block(STATE_ECEF_ORIENTATION_ERR_START, STATE_ECEF_VELOCITY_ERR_START); + condensed_cov.bottomRightCorner() = + predicted_cov.block(STATE_ECEF_VELOCITY_ERR_START, STATE_ECEF_VELOCITY_ERR_START); + condensed_cov.bottomLeftCorner() = + predicted_cov.block(STATE_ECEF_VELOCITY_ERR_START, STATE_ECEF_ORIENTATION_ERR_START); + VectorXd H_input(device_from_ecef_eul.size() + vel_ecef.size()); + H_input << device_from_ecef_eul, vel_ecef; + MatrixXdr HH = this->kf->H(H_input); + MatrixXdr vel_device_cov = (HH * condensed_cov) * HH.transpose(); + VectorXd vel_device_std = vel_device_cov.diagonal().array().sqrt(); + + VectorXd vel_calib = this->calib_from_device * vel_device; + VectorXd vel_calib_std = rotate_cov(this->calib_from_device, vel_device_cov).diagonal().array().sqrt(); + + VectorXd orientation_ned = ned_euler_from_ecef(fix_ecef_ecef, orientation_ecef); + //orientation_ned_std = ned_euler_from_ecef(fix_ecef, orientation_ecef + orientation_ecef_std) - orientation_ned + VectorXd nextfix_ecef = fix_ecef + vel_ecef; + VectorXd ned_vel = this->converter->ecef2ned((ECEF) { .x = nextfix_ecef(0), .y = nextfix_ecef(1), .z = nextfix_ecef(2) }).to_vector() - converter->ecef2ned(fix_ecef_ecef).to_vector(); + //ned_vel_std = self.converter->ecef2ned(fix_ecef + vel_ecef + vel_ecef_std) - self.converter->ecef2ned(fix_ecef + vel_ecef) + + VectorXd accDevice = predicted_state.segment(STATE_ACCELERATION_START); + VectorXd accDeviceErr = predicted_std.segment(STATE_ACCELERATION_ERR_START); + + VectorXd angVelocityDevice = predicted_state.segment(STATE_ANGULAR_VELOCITY_START); + VectorXd angVelocityDeviceErr = predicted_std.segment(STATE_ANGULAR_VELOCITY_ERR_START); + + Vector3d nans = Vector3d(NAN, NAN, NAN); + + // write measurements to msg + init_measurement(fix.initPositionGeodetic(), fix_pos_geo_vec, nans, true); + init_measurement(fix.initPositionECEF(), fix_ecef, fix_ecef_std, true); + init_measurement(fix.initVelocityECEF(), vel_ecef, vel_ecef_std, true); + init_measurement(fix.initVelocityNED(), ned_vel, nans, true); + init_measurement(fix.initVelocityDevice(), vel_device, vel_device_std, true); + init_measurement(fix.initAccelerationDevice(), accDevice, accDeviceErr, true); + init_measurement(fix.initOrientationECEF(), orientation_ecef, orientation_ecef_std, true); + init_measurement(fix.initCalibratedOrientationECEF(), calibrated_orientation_ecef, nans, this->calibrated); + init_measurement(fix.initOrientationNED(), orientation_ned, nans, true); + init_measurement(fix.initAngularVelocityDevice(), angVelocityDevice, angVelocityDeviceErr, true); + init_measurement(fix.initVelocityCalibrated(), vel_calib, vel_calib_std, this->calibrated); + init_measurement(fix.initAngularVelocityCalibrated(), ang_vel_calib, ang_vel_calib_std, this->calibrated); + init_measurement(fix.initAccelerationCalibrated(), acc_calib, acc_calib_std, this->calibrated); + + double old_mean = 0.0, new_mean = 0.0; + int i = 0; + for (double x : this->posenet_stds) { + if (i < POSENET_STD_HIST_HALF) { + old_mean += x; + } else { + new_mean += x; + } + i++; + } + old_mean /= POSENET_STD_HIST_HALF; + new_mean /= POSENET_STD_HIST_HALF; + // experimentally found these values, no false positives in 20k minutes of driving + bool std_spike = (new_mean / old_mean > 4.0 && new_mean > 7.0); + + fix.setPosenetOK(!(std_spike && this->car_speed > 5.0)); + fix.setDeviceStable(!this->device_fell); + this->device_fell = false; + + //fix.setGpsWeek(this->time.week); + //fix.setGpsTimeOfWeek(this->time.tow); + fix.setUnixTimestampMillis(this->unix_timestamp_millis); + + if (fix_ecef_std.norm() < 50.0 && this->calibrated) { + fix.setStatus(cereal::LiveLocationKalman::Status::VALID); + } else if (fix_ecef_std.norm() < 50.0) { + fix.setStatus(cereal::LiveLocationKalman::Status::UNCALIBRATED); + } else { + fix.setStatus(cereal::LiveLocationKalman::Status::UNINITIALIZED); + } +} + +VectorXd Localizer::get_position_geodetic() { + VectorXd fix_ecef = this->kf->get_x().segment(STATE_ECEF_POS_START); + ECEF fix_ecef_ecef = { .x = fix_ecef(0), .y = fix_ecef(1), .z = fix_ecef(2) }; + Geodetic fix_pos_geo = ecef2geodetic(fix_ecef_ecef); + return Vector3d(fix_pos_geo.lat, fix_pos_geo.lon, fix_pos_geo.alt); +} + +void Localizer::handle_sensors(double current_time, const capnp::List::Reader& log) { + // TODO does not yet account for double sensor readings in the log + for (int i = 0; i < log.size(); i++) { + const cereal::SensorEventData::Reader& sensor_reading = log[i]; + + // Ignore empty readings (e.g. in case the magnetometer had no data ready) + if (sensor_reading.getTimestamp() == 0){ + continue; + } + + double sensor_time = 1e-9 * sensor_reading.getTimestamp(); + + // sensor time and log time should be close + if (abs(current_time - sensor_time) > 0.1) { + LOGE("Sensor reading ignored, sensor timestamp more than 100ms off from log time"); + return; + } + + // TODO: handle messages from two IMUs at the same time + if (sensor_reading.getSource() == cereal::SensorEventData::SensorSource::LSM6DS3) { + continue; + } + + // Gyro Uncalibrated + if (sensor_reading.getSensor() == SENSOR_GYRO_UNCALIBRATED && sensor_reading.getType() == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) { + auto v = sensor_reading.getGyroUncalibrated().getV(); + auto meas = Vector3d(-v[2], -v[1], -v[0]); + if (meas.norm() < ROTATION_SANITY_CHECK) { + this->kf->predict_and_observe(sensor_time, OBSERVATION_PHONE_GYRO, { meas }); + } + } + + // Accelerometer + if (sensor_reading.getSensor() == SENSOR_ACCELEROMETER && sensor_reading.getType() == SENSOR_TYPE_ACCELEROMETER) { + auto v = sensor_reading.getAcceleration().getV(); + + // check if device fell, estimate 10 for g + // 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving + this->device_fell |= (floatlist2vector(v) - Vector3d(10.0, 0.0, 0.0)).norm() > 40.0; + + auto meas = Vector3d(-v[2], -v[1], -v[0]); + if (meas.norm() < ACCEL_SANITY_CHECK) { + this->kf->predict_and_observe(sensor_time, OBSERVATION_PHONE_ACCEL, { meas }); + } + } + } +} + +void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::Reader& log) { + // ignore the message if the fix is invalid + if (log.getFlags() % 2 == 0) { + return; + } + + // Sanity checks + if ((log.getVerticalAccuracy() <= 0) || (log.getSpeedAccuracy() <= 0) || (log.getBearingAccuracyDeg() <= 0)) { + return; + } + + if ((std::abs(log.getLatitude()) > 90) || (std::abs(log.getLongitude()) > 180) || (std::abs(log.getAltitude()) > ALTITUDE_SANITY_CHECK)) { + return; + } + + if (floatlist2vector(log.getVNED()).norm() > TRANS_SANITY_CHECK){ + return; + } + + // Process message + this->last_gps_fix = current_time; + Geodetic geodetic = { log.getLatitude(), log.getLongitude(), log.getAltitude() }; + this->converter = std::make_unique(geodetic); + + VectorXd ecef_pos = this->converter->ned2ecef({ 0.0, 0.0, 0.0 }).to_vector(); + VectorXd ecef_vel = this->converter->ned2ecef({ log.getVNED()[0], log.getVNED()[1], log.getVNED()[2] }).to_vector() - ecef_pos; + MatrixXdr ecef_pos_R = Vector3d::Constant(std::pow(3.0 * log.getVerticalAccuracy(), 2)).asDiagonal(); + MatrixXdr ecef_vel_R = Vector3d::Constant(std::pow(log.getSpeedAccuracy(), 2)).asDiagonal(); + + this->unix_timestamp_millis = log.getTimestamp(); + double gps_est_error = (this->kf->get_x().head(3) - ecef_pos).norm(); + + VectorXd orientation_ecef = quat2euler(vector2quat(this->kf->get_x().segment(STATE_ECEF_ORIENTATION_START))); + VectorXd orientation_ned = ned_euler_from_ecef({ ecef_pos(0), ecef_pos(1), ecef_pos(2) }, orientation_ecef); + VectorXd orientation_ned_gps = Vector3d(0.0, 0.0, DEG2RAD(log.getBearingDeg())); + VectorXd orientation_error = (orientation_ned - orientation_ned_gps).array() - M_PI; + for (int i = 0; i < orientation_error.size(); i++) { + orientation_error(i) = std::fmod(orientation_error(i), 2.0 * M_PI); + if (orientation_error(i) < 0.0) { + orientation_error(i) += 2.0 * M_PI; + } + orientation_error(i) -= M_PI; + } + VectorXd initial_pose_ecef_quat = quat2vector(euler2quat(ecef_euler_from_ned({ ecef_pos(0), ecef_pos(1), ecef_pos(2) }, orientation_ned_gps))); + + if (ecef_vel.norm() > 5.0 && orientation_error.norm() > 1.0) { + LOGE("Locationd vs ubloxLocation orientation difference too large, kalman reset"); + this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos); + this->kf->predict_and_observe(current_time, OBSERVATION_ECEF_ORIENTATION_FROM_GPS, { initial_pose_ecef_quat }); + } else if (gps_est_error > 50.0) { + LOGE("Locationd vs ubloxLocation position difference too large, kalman reset"); + this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos); + } + + this->kf->predict_and_observe(current_time, OBSERVATION_ECEF_POS, { ecef_pos }, { ecef_pos_R }); + this->kf->predict_and_observe(current_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); +} + +void Localizer::handle_car_state(double current_time, const cereal::CarState::Reader& log) { + this->car_speed = std::abs(log.getVEgo()); + if (log.getStandstill()) { + this->kf->predict_and_observe(current_time, OBSERVATION_NO_ROT, { Vector3d(0.0, 0.0, 0.0) }); + } +} + +void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log) { + VectorXd rot_device = this->device_from_calib * floatlist2vector(log.getRot()); + VectorXd trans_device = this->device_from_calib * floatlist2vector(log.getTrans()); + + if ((rot_device.norm() > ROTATION_SANITY_CHECK) || (trans_device.norm() > TRANS_SANITY_CHECK)) { + return; + } + + VectorXd rot_calib_std = floatlist2vector(log.getRotStd()); + VectorXd trans_calib_std = floatlist2vector(log.getTransStd()); + + if ((rot_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK) || (trans_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK)){ + return; + } + + if ((rot_calib_std.norm() > 10 * ROTATION_SANITY_CHECK) || (trans_calib_std.norm() > 10 * TRANS_SANITY_CHECK)) { + return; + } + + this->posenet_stds.pop_front(); + this->posenet_stds.push_back(trans_calib_std[0]); + + // Multiply by 10 to avoid to high certainty in kalman filter because of temporally correlated noise + trans_calib_std *= 10.0; + rot_calib_std *= 10.0; + VectorXd rot_device_std = rotate_std(this->device_from_calib, rot_calib_std); + VectorXd trans_device_std = rotate_std(this->device_from_calib, trans_calib_std); + + this->kf->predict_and_observe(current_time, OBSERVATION_CAMERA_ODO_ROTATION, + { (VectorXd(rot_device.rows() + rot_device_std.rows()) << rot_device, rot_device_std).finished() }); + this->kf->predict_and_observe(current_time, OBSERVATION_CAMERA_ODO_TRANSLATION, + { (VectorXd(trans_device.rows() + trans_device_std.rows()) << trans_device, trans_device_std).finished() }); +} + +void Localizer::handle_live_calib(double current_time, const cereal::LiveCalibrationData::Reader& log) { + if (log.getRpyCalib().size() > 0) { + auto calib = floatlist2vector(log.getRpyCalib()); + if ((calib.minCoeff() < -CALIB_RPY_SANITY_CHECK) || (calib.maxCoeff() > CALIB_RPY_SANITY_CHECK)){ + return; + } + + this->calib = calib; + this->device_from_calib = euler2rot(this->calib); + this->calib_from_device = this->device_from_calib.transpose(); + this->calibrated = log.getCalStatus() == 1; + } +} + +void Localizer::reset_kalman(double current_time) { + VectorXd init_x = this->kf->get_initial_x(); + this->reset_kalman(current_time, init_x.segment<4>(3), init_x.head(3)); +} + +void Localizer::finite_check(double current_time) { + bool all_finite = this->kf->get_x().array().isFinite().all() or this->kf->get_P().array().isFinite().all(); + if (!all_finite){ + LOGE("Non-finite values detected, kalman reset"); + this->reset_kalman(current_time); + } +} + +void Localizer::time_check(double current_time) { + double filter_time = this->kf->get_filter_time(); + bool big_time_gap = !isnan(filter_time) && (current_time - filter_time > 10); + if (big_time_gap){ + LOGE("Time gap of over 10s detected, kalman reset"); + this->reset_kalman(current_time); + } +} + +void Localizer::reset_kalman(double current_time, VectorXd init_orient, VectorXd init_pos) { + // too nonlinear to init on completely wrong + VectorXd init_x = this->kf->get_initial_x(); + MatrixXdr init_P = this->kf->get_initial_P(); + init_x.segment<4>(3) = init_orient; + init_x.head(3) = init_pos; + + this->kf->init_state(init_x, init_P, current_time); +} + +void Localizer::handle_msg_bytes(const char *data, const size_t size) { + AlignedBuffer aligned_buf; + + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(data, size)); + cereal::Event::Reader event = cmsg.getRoot(); + + this->handle_msg(event); +} + +void Localizer::handle_msg(const cereal::Event::Reader& log) { + double t = log.getLogMonoTime() * 1e-9; + this->time_check(t); + if (log.isSensorEvents()) { + this->handle_sensors(t, log.getSensorEvents()); + } else if (log.isGpsLocationExternal()) { + this->handle_gps(t, log.getGpsLocationExternal()); + } else if (log.isCarState()) { + this->handle_car_state(t, log.getCarState()); + } else if (log.isCameraOdometry()) { + this->handle_cam_odo(t, log.getCameraOdometry()); + } else if (log.isLiveCalibration()) { + this->handle_live_calib(t, log.getLiveCalibration()); + } + this->finite_check(); +} + +kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_builder, uint64_t logMonoTime, + bool inputsOK, bool sensorsOK, bool gpsOK) +{ + cereal::Event::Builder evt = msg_builder.initEvent(); + evt.setLogMonoTime(logMonoTime); + cereal::LiveLocationKalman::Builder liveLoc = evt.initLiveLocationKalman(); + this->build_live_location(liveLoc); + liveLoc.setInputsOK(inputsOK); + liveLoc.setSensorsOK(sensorsOK); + liveLoc.setGpsOK(gpsOK); + return msg_builder.toBytes(); +} + +int Localizer::locationd_thread() { + const std::initializer_list service_list = + { "gpsLocationExternal", "sensorEvents", "cameraOdometry", "liveCalibration", "carState" }; + PubMaster pm({ "liveLocationKalman" }); + SubMaster sm(service_list, nullptr, { "gpsLocationExternal" }); + + Params params; + + while (!do_exit) { + sm.update(); + for (const char* service : service_list) { + if (sm.updated(service) && sm.valid(service)) { + const cereal::Event::Reader log = sm[service]; + this->handle_msg(log); + } + } + + if (sm.updated("cameraOdometry")) { + uint64_t logMonoTime = sm["cameraOdometry"].getLogMonoTime(); + bool inputsOK = sm.allAliveAndValid(); + bool sensorsOK = sm.alive("sensorEvents") && sm.valid("sensorEvents"); + bool gpsOK = (logMonoTime / 1e9) - this->last_gps_fix < 1.0; + + MessageBuilder msg_builder; + kj::ArrayPtr bytes = this->get_message_bytes(msg_builder, logMonoTime, inputsOK, sensorsOK, gpsOK); + pm.send("liveLocationKalman", bytes.begin(), bytes.size()); + + if (sm.frame % 1200 == 0 && gpsOK) { // once a minute + VectorXd posGeo = this->get_position_geodetic(); + std::string lastGPSPosJSON = util::string_format( + "{\"latitude\": %.15f, \"longitude\": %.15f, \"altitude\": %.15f}", posGeo(0), posGeo(1), posGeo(2)); + + std::thread([¶ms] (const std::string gpsjson) { + params.put("LastGPSPosition", gpsjson); + }, lastGPSPosJSON).detach(); + } + } + } + return 0; +} + +int main() { + setpriority(PRIO_PROCESS, 0, -20); + + Localizer localizer; + return localizer.locationd_thread(); +} diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h new file mode 100755 index 000000000..58030cd92 --- /dev/null +++ b/selfdrive/locationd/locationd.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#include + +#include "cereal/messaging/messaging.h" +#include "common/transformations/coordinates.hpp" +#include "common/transformations/orientation.hpp" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" +#include + +#include "selfdrive/sensord/sensors/constants.h" +#define VISION_DECIMATION 2 +#define SENSOR_DECIMATION 10 +#include "selfdrive/locationd/models/live_kf.h" + +#define POSENET_STD_HIST_HALF 20 + +class Localizer { +public: + Localizer(); + + int locationd_thread(); + + void reset_kalman(double current_time = NAN); + void reset_kalman(double current_time, Eigen::VectorXd init_orient, Eigen::VectorXd init_pos); + void finite_check(double current_time = NAN); + void time_check(double current_time = NAN); + + kj::ArrayPtr get_message_bytes(MessageBuilder& msg_builder, uint64_t logMonoTime, + bool inputsOK, bool sensorsOK, bool gpsOK); + void build_live_location(cereal::LiveLocationKalman::Builder& fix); + + Eigen::VectorXd get_position_geodetic(); + + void handle_msg_bytes(const char *data, const size_t size); + void handle_msg(const cereal::Event::Reader& log); + void handle_sensors(double current_time, const capnp::List::Reader& log); + void handle_gps(double current_time, const cereal::GpsLocationData::Reader& log); + void handle_car_state(double current_time, const cereal::CarState::Reader& log); + void handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log); + void handle_live_calib(double current_time, const cereal::LiveCalibrationData::Reader& log); + +private: + std::unique_ptr kf; + + Eigen::VectorXd calib; + MatrixXdr device_from_calib; + MatrixXdr calib_from_device; + bool calibrated = false; + + double car_speed = 0.0; + std::deque posenet_stds; + + std::unique_ptr converter; + + int64_t unix_timestamp_millis = 0; + double last_gps_fix = 0; + bool device_fell = false; +}; diff --git a/selfdrive/locationd/locationd.py b/selfdrive/locationd/locationd.py deleted file mode 100755 index f7267f0cc..000000000 --- a/selfdrive/locationd/locationd.py +++ /dev/null @@ -1,350 +0,0 @@ -#!/usr/bin/env python3 -import json -import numpy as np -import sympy as sp -import cereal.messaging as messaging -from cereal import log -from common.params import Params -import common.transformations.coordinates as coord -from common.transformations.orientation import ecef_euler_from_ned, \ - euler_from_quat, \ - ned_euler_from_ecef, \ - quat_from_euler, euler_from_rot, \ - rot_from_quat, rot_from_euler -from rednose.helpers import KalmanError -from selfdrive.locationd.models.live_kf import LiveKalman, States, ObservationKind -from selfdrive.locationd.models.constants import GENERATED_DIR -from selfdrive.swaglog import cloudlog - -#from datetime import datetime -#from laika.gps_time import GPSTime - -from sympy.utilities.lambdify import lambdify -from rednose.helpers.sympy_helpers import euler_rotate - -SensorSource = log.SensorEventData.SensorSource - - -VISION_DECIMATION = 2 -SENSOR_DECIMATION = 10 -POSENET_STD_HIST = 40 - - -def to_float(arr): - return [float(arr[0]), float(arr[1]), float(arr[2])] - - -def get_H(): - # this returns a function to eval the jacobian - # of the observation function of the local vel - roll = sp.Symbol('roll') - pitch = sp.Symbol('pitch') - yaw = sp.Symbol('yaw') - vx = sp.Symbol('vx') - vy = sp.Symbol('vy') - vz = sp.Symbol('vz') - - h = euler_rotate(roll, pitch, yaw).T*(sp.Matrix([vx, vy, vz])) - H = h.jacobian(sp.Matrix([roll, pitch, yaw, vx, vy, vz])) - H_f = lambdify([roll, pitch, yaw, vx, vy, vz], H) - return H_f - - -class Localizer(): - def __init__(self, disabled_logs=None, dog=None): - if disabled_logs is None: - disabled_logs = [] - - self.kf = LiveKalman(GENERATED_DIR) - self.reset_kalman() - self.max_age = .1 # seconds - self.disabled_logs = disabled_logs - self.calib = np.zeros(3) - self.device_from_calib = np.eye(3) - self.calib_from_device = np.eye(3) - self.calibrated = False - self.H = get_H() - - self.posenet_invalid_count = 0 - self.posenet_speed = 0 - self.car_speed = 0 - self.posenet_stds = 10*np.ones((POSENET_STD_HIST)) - - self.converter = coord.LocalCoord.from_ecef(self.kf.x[States.ECEF_POS]) - - self.unix_timestamp_millis = 0 - self.last_gps_fix = 0 - self.device_fell = False - - @staticmethod - def msg_from_state(converter, calib_from_device, H, predicted_state, predicted_cov, calibrated): - predicted_std = np.sqrt(np.diagonal(predicted_cov)) - - fix_ecef = predicted_state[States.ECEF_POS] - fix_ecef_std = predicted_std[States.ECEF_POS_ERR] - vel_ecef = predicted_state[States.ECEF_VELOCITY] - vel_ecef_std = predicted_std[States.ECEF_VELOCITY_ERR] - fix_pos_geo = coord.ecef2geodetic(fix_ecef) - #fix_pos_geo_std = np.abs(coord.ecef2geodetic(fix_ecef + fix_ecef_std) - fix_pos_geo) - orientation_ecef = euler_from_quat(predicted_state[States.ECEF_ORIENTATION]) - orientation_ecef_std = predicted_std[States.ECEF_ORIENTATION_ERR] - device_from_ecef = rot_from_quat(predicted_state[States.ECEF_ORIENTATION]).T - calibrated_orientation_ecef = euler_from_rot(calib_from_device.dot(device_from_ecef)) - - acc_calib = calib_from_device.dot(predicted_state[States.ACCELERATION]) - acc_calib_std = np.sqrt(np.diagonal(calib_from_device.dot( - predicted_cov[States.ACCELERATION_ERR, States.ACCELERATION_ERR]).dot( - calib_from_device.T))) - ang_vel_calib = calib_from_device.dot(predicted_state[States.ANGULAR_VELOCITY]) - ang_vel_calib_std = np.sqrt(np.diagonal(calib_from_device.dot( - predicted_cov[States.ANGULAR_VELOCITY_ERR, States.ANGULAR_VELOCITY_ERR]).dot( - calib_from_device.T))) - - vel_device = device_from_ecef.dot(vel_ecef) - device_from_ecef_eul = euler_from_quat(predicted_state[States.ECEF_ORIENTATION]).T - idxs = list(range(States.ECEF_ORIENTATION_ERR.start, States.ECEF_ORIENTATION_ERR.stop)) + \ - list(range(States.ECEF_VELOCITY_ERR.start, States.ECEF_VELOCITY_ERR.stop)) - condensed_cov = predicted_cov[idxs][:, idxs] - HH = H(*list(np.concatenate([device_from_ecef_eul, vel_ecef]))) - vel_device_cov = HH.dot(condensed_cov).dot(HH.T) - vel_device_std = np.sqrt(np.diagonal(vel_device_cov)) - - vel_calib = calib_from_device.dot(vel_device) - vel_calib_std = np.sqrt(np.diagonal(calib_from_device.dot( - vel_device_cov).dot(calib_from_device.T))) - - orientation_ned = ned_euler_from_ecef(fix_ecef, orientation_ecef) - #orientation_ned_std = ned_euler_from_ecef(fix_ecef, orientation_ecef + orientation_ecef_std) - orientation_ned - ned_vel = converter.ecef2ned(fix_ecef + vel_ecef) - converter.ecef2ned(fix_ecef) - #ned_vel_std = self.converter.ecef2ned(fix_ecef + vel_ecef + vel_ecef_std) - self.converter.ecef2ned(fix_ecef + vel_ecef) - - fix = messaging.log.LiveLocationKalman.new_message() - - # write measurements to msg - measurements = [ - # measurement field, value, std, valid - (fix.positionGeodetic, fix_pos_geo, np.nan*np.zeros(3), True), - (fix.positionECEF, fix_ecef, fix_ecef_std, True), - (fix.velocityECEF, vel_ecef, vel_ecef_std, True), - (fix.velocityNED, ned_vel, np.nan*np.zeros(3), True), - (fix.velocityDevice, vel_device, vel_device_std, True), - (fix.accelerationDevice, predicted_state[States.ACCELERATION], predicted_std[States.ACCELERATION_ERR], True), - (fix.orientationECEF, orientation_ecef, orientation_ecef_std, True), - (fix.calibratedOrientationECEF, calibrated_orientation_ecef, np.nan*np.zeros(3), calibrated), - (fix.orientationNED, orientation_ned, np.nan*np.zeros(3), True), - (fix.angularVelocityDevice, predicted_state[States.ANGULAR_VELOCITY], predicted_std[States.ANGULAR_VELOCITY_ERR], True), - (fix.velocityCalibrated, vel_calib, vel_calib_std, calibrated), - (fix.angularVelocityCalibrated, ang_vel_calib, ang_vel_calib_std, calibrated), - (fix.accelerationCalibrated, acc_calib, acc_calib_std, calibrated), - ] - - for field, value, std, valid in measurements: - # TODO: can we write the lists faster? - field.value = to_float(value) - field.std = to_float(std) - field.valid = valid - - return fix - - def liveLocationMsg(self): - fix = self.msg_from_state(self.converter, self.calib_from_device, self.H, self.kf.x, self.kf.P, self.calibrated) - # experimentally found these values, no false positives in 20k minutes of driving - old_mean, new_mean = np.mean(self.posenet_stds[:POSENET_STD_HIST//2]), np.mean(self.posenet_stds[POSENET_STD_HIST//2:]) - std_spike = new_mean/old_mean > 4 and new_mean > 7 - - fix.posenetOK = not (std_spike and self.car_speed > 5) - fix.deviceStable = not self.device_fell - self.device_fell = False - - #fix.gpsWeek = self.time.week - #fix.gpsTimeOfWeek = self.time.tow - fix.unixTimestampMillis = self.unix_timestamp_millis - - if np.linalg.norm(fix.positionECEF.std) < 50 and self.calibrated: - fix.status = 'valid' - elif np.linalg.norm(fix.positionECEF.std) < 50: - fix.status = 'uncalibrated' - else: - fix.status = 'uninitialized' - return fix - - def update_kalman(self, time, kind, meas, R=None): - try: - self.kf.predict_and_observe(time, kind, meas, R) - except KalmanError: - cloudlog.error("Error in predict and observe, kalman reset") - self.reset_kalman() - - def handle_gps(self, current_time, log): - # ignore the message if the fix is invalid - if log.flags % 2 == 0: - return - - self.last_gps_fix = current_time - - self.converter = coord.LocalCoord.from_geodetic([log.latitude, log.longitude, log.altitude]) - ecef_pos = self.converter.ned2ecef([0, 0, 0]) - ecef_vel = self.converter.ned2ecef(np.array(log.vNED)) - ecef_pos - ecef_pos_R = np.diag([(3*log.verticalAccuracy)**2]*3) - ecef_vel_R = np.diag([(log.speedAccuracy)**2]*3) - - #self.time = GPSTime.from_datetime(datetime.utcfromtimestamp(log.timestamp*1e-3)) - self.unix_timestamp_millis = log.timestamp - gps_est_error = np.sqrt((self.kf.x[0] - ecef_pos[0])**2 + - (self.kf.x[1] - ecef_pos[1])**2 + - (self.kf.x[2] - ecef_pos[2])**2) - - orientation_ecef = euler_from_quat(self.kf.x[States.ECEF_ORIENTATION]) - orientation_ned = ned_euler_from_ecef(ecef_pos, orientation_ecef) - orientation_ned_gps = np.array([0, 0, np.radians(log.bearingDeg)]) - orientation_error = np.mod(orientation_ned - orientation_ned_gps - np.pi, 2*np.pi) - np.pi - initial_pose_ecef_quat = quat_from_euler(ecef_euler_from_ned(ecef_pos, orientation_ned_gps)) - if np.linalg.norm(ecef_vel) > 5 and np.linalg.norm(orientation_error) > 1: - cloudlog.error("Locationd vs ubloxLocation orientation difference too large, kalman reset") - self.reset_kalman(init_pos=ecef_pos, init_orient=initial_pose_ecef_quat) - self.update_kalman(current_time, ObservationKind.ECEF_ORIENTATION_FROM_GPS, initial_pose_ecef_quat) - elif gps_est_error > 50: - cloudlog.error("Locationd vs ubloxLocation position difference too large, kalman reset") - self.reset_kalman(init_pos=ecef_pos, init_orient=initial_pose_ecef_quat) - - self.update_kalman(current_time, ObservationKind.ECEF_POS, ecef_pos, R=ecef_pos_R) - self.update_kalman(current_time, ObservationKind.ECEF_VEL, ecef_vel, R=ecef_vel_R) - - def handle_car_state(self, current_time, log): - self.speed_counter += 1 - - if self.speed_counter % SENSOR_DECIMATION == 0: - self.update_kalman(current_time, ObservationKind.ODOMETRIC_SPEED, [log.vEgo]) - self.car_speed = abs(log.vEgo) - if log.vEgo == 0: - self.update_kalman(current_time, ObservationKind.NO_ROT, [0, 0, 0]) - - def handle_cam_odo(self, current_time, log): - self.cam_counter += 1 - - if self.cam_counter % VISION_DECIMATION == 0: - rot_device = self.device_from_calib.dot(log.rot) - rot_device_std = self.device_from_calib.dot(log.rotStd) - self.update_kalman(current_time, - ObservationKind.CAMERA_ODO_ROTATION, - np.concatenate([rot_device, 10*rot_device_std])) - trans_device = self.device_from_calib.dot(log.trans) - trans_device_std = self.device_from_calib.dot(log.transStd) - self.posenet_speed = np.linalg.norm(trans_device) - self.posenet_stds[:-1] = self.posenet_stds[1:] - self.posenet_stds[-1] = trans_device_std[0] - self.update_kalman(current_time, - ObservationKind.CAMERA_ODO_TRANSLATION, - np.concatenate([trans_device, 10*trans_device_std])) - - def handle_sensors(self, current_time, log): - # TODO does not yet account for double sensor readings in the log - for sensor_reading in log: - sensor_time = 1e-9 * sensor_reading.timestamp - # TODO: handle messages from two IMUs at the same time - if sensor_reading.source == SensorSource.lsm6ds3: - continue - - # Gyro Uncalibrated - if sensor_reading.sensor == 5 and sensor_reading.type == 16: - self.gyro_counter += 1 - if self.gyro_counter % SENSOR_DECIMATION == 0: - v = sensor_reading.gyroUncalibrated.v - self.update_kalman(sensor_time, ObservationKind.PHONE_GYRO, [-v[2], -v[1], -v[0]]) - - # Accelerometer - if sensor_reading.sensor == 1 and sensor_reading.type == 1: - # check if device fell, estimate 10 for g - # 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving - self.device_fell = self.device_fell or (np.linalg.norm(np.array(sensor_reading.acceleration.v) - np.array([10, 0, 0])) > 40) - - self.acc_counter += 1 - if self.acc_counter % SENSOR_DECIMATION == 0: - v = sensor_reading.acceleration.v - self.update_kalman(sensor_time, ObservationKind.PHONE_ACCEL, [-v[2], -v[1], -v[0]]) - - def handle_live_calib(self, current_time, log): - if len(log.rpyCalib): - self.calib = log.rpyCalib - self.device_from_calib = rot_from_euler(self.calib) - self.calib_from_device = self.device_from_calib.T - self.calibrated = log.calStatus == 1 - - def reset_kalman(self, current_time=None, init_orient=None, init_pos=None): - self.filter_time = current_time - init_x = LiveKalman.initial_x.copy() - # too nonlinear to init on completely wrong - if init_orient is not None: - init_x[3:7] = init_orient - if init_pos is not None: - init_x[:3] = init_pos - self.kf.init_state(init_x, covs=np.diag(LiveKalman.initial_P_diag), filter_time=current_time) - - self.observation_buffer = [] - - self.gyro_counter = 0 - self.acc_counter = 0 - self.speed_counter = 0 - self.cam_counter = 0 - - -def locationd_thread(sm, pm, disabled_logs=None): - if disabled_logs is None: - disabled_logs = [] - - if sm is None: - socks = ['gpsLocationExternal', 'sensorEvents', 'cameraOdometry', 'liveCalibration', 'carState'] - sm = messaging.SubMaster(socks, ignore_alive=['gpsLocationExternal']) - if pm is None: - pm = messaging.PubMaster(['liveLocationKalman']) - - params = Params() - localizer = Localizer(disabled_logs=disabled_logs) - - while True: - sm.update() - - for sock, updated in sm.updated.items(): - if updated and sm.valid[sock]: - t = sm.logMonoTime[sock] * 1e-9 - if sock == "sensorEvents": - localizer.handle_sensors(t, sm[sock]) - elif sock == "gpsLocationExternal": - localizer.handle_gps(t, sm[sock]) - elif sock == "carState": - localizer.handle_car_state(t, sm[sock]) - elif sock == "cameraOdometry": - localizer.handle_cam_odo(t, sm[sock]) - elif sock == "liveCalibration": - localizer.handle_live_calib(t, sm[sock]) - - if sm.updated['cameraOdometry']: - t = sm.logMonoTime['cameraOdometry'] - msg = messaging.new_message('liveLocationKalman') - msg.logMonoTime = t - - msg.liveLocationKalman = localizer.liveLocationMsg() - msg.liveLocationKalman.inputsOK = sm.all_alive_and_valid() - msg.liveLocationKalman.sensorsOK = sm.alive['sensorEvents'] and sm.valid['sensorEvents'] - - gps_age = (t / 1e9) - localizer.last_gps_fix - msg.liveLocationKalman.gpsOK = gps_age < 1.0 - pm.send('liveLocationKalman', msg) - - if sm.frame % 1200 == 0 and msg.liveLocationKalman.gpsOK: # once a minute - location = { - 'latitude': msg.liveLocationKalman.positionGeodetic.value[0], - 'longitude': msg.liveLocationKalman.positionGeodetic.value[1], - 'altitude': msg.liveLocationKalman.positionGeodetic.value[2], - } - params.put("LastGPSPosition", json.dumps(location)) - - -def main(sm=None, pm=None): - locationd_thread(sm, pm) - - -if __name__ == "__main__": - import os - os.environ["OMP_NUM_THREADS"] = "1" - main() diff --git a/selfdrive/locationd/models/SConscript b/selfdrive/locationd/models/SConscript deleted file mode 100644 index 0a197ffda..000000000 --- a/selfdrive/locationd/models/SConscript +++ /dev/null @@ -1,37 +0,0 @@ -Import('env', 'arch') - -templates = Glob('#rednose/templates/*') - -sympy_helpers = "#rednose/helpers/sympy_helpers.py" -ekf_sym = "#rednose/helpers/ekf_sym.py" - -to_build = { - 'live': ('live_kf.py', 'generated'), - 'car': ('car_kf.py', 'generated'), -} - -if arch != "aarch64": - to_build.update({ - 'gnss': ('gnss_kf.py', 'generated'), - 'loc_4': ('loc_kf.py', 'generated'), - 'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', 'generated'), - 'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', 'generated'), - 'feature_handler_5': ('#rednose/helpers/feature_handler.py', 'generated'), - 'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', 'generated'), - }) - -found = {} - -for target, (command, generated_folder) in to_build.items(): - if File(command).exists(): - found[target] = (command, generated_folder) - -for target, (command, generated_folder) in found.items(): - target_files = File([f'{generated_folder}/{target}.cpp', f'{generated_folder}/{target}.h']) - command_file = File(command) - - env.Command(target_files, - [templates, command_file, sympy_helpers, ekf_sym], - command_file.get_abspath() + " " + target + " " + Dir(generated_folder).get_abspath()) - - env.SharedLibrary(f'{generated_folder}/' + target, target_files[0]) diff --git a/selfdrive/locationd/models/car_kf.py b/selfdrive/locationd/models/car_kf.py index 6c5357f2d..b440cc9bb 100755 --- a/selfdrive/locationd/models/car_kf.py +++ b/selfdrive/locationd/models/car_kf.py @@ -4,15 +4,20 @@ import sys from typing import Any, Dict import numpy as np -import sympy as sp -from rednose import KalmanFilter -from rednose.helpers.ekf_sym import EKF_sym, gen_code from selfdrive.locationd.models.constants import ObservationKind from selfdrive.swaglog import cloudlog -i = 0 +from rednose.helpers.kalmanfilter import KalmanFilter +if __name__ == '__main__': # Generating sympy + import sympy as sp + from rednose.helpers.ekf_sym import gen_code +else: + from rednose.helpers.ekf_sym_pyx import EKF_sym # pylint: disable=no-name-in-module, import-error + + +i = 0 def _slice(n): global i @@ -70,12 +75,12 @@ class CarKalman(KalmanFilter): } global_vars = [ - sp.Symbol('mass'), - sp.Symbol('rotational_inertia'), - sp.Symbol('center_to_front'), - sp.Symbol('center_to_rear'), - sp.Symbol('stiffness_front'), - sp.Symbol('stiffness_rear'), + 'mass', + 'rotational_inertia', + 'center_to_front', + 'center_to_rear', + 'stiffness_front', + 'stiffness_rear', ] @staticmethod @@ -84,7 +89,8 @@ class CarKalman(KalmanFilter): name = CarKalman.name # globals - m, j, aF, aR, cF_orig, cR_orig = CarKalman.global_vars + global_vars = [sp.Symbol(name) for name in CarKalman.global_vars] + m, j, aF, aR, cF_orig, cR_orig = global_vars # make functions and jacobians with sympy # state variables @@ -138,7 +144,7 @@ class CarKalman(KalmanFilter): [sp.Matrix([x]), ObservationKind.STIFFNESS, None], ] - gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state, global_vars=CarKalman.global_vars) + gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state, global_vars=global_vars) def __init__(self, generated_dir, steer_ratio=15, stiffness_factor=1, angle_offset=0): # pylint: disable=super-init-not-called dim_state = self.initial_x.shape[0] diff --git a/selfdrive/locationd/models/live_kf.cc b/selfdrive/locationd/models/live_kf.cc new file mode 100755 index 000000000..00080ab83 --- /dev/null +++ b/selfdrive/locationd/models/live_kf.cc @@ -0,0 +1,144 @@ +#include "live_kf.h" + +using namespace EKFS; +using namespace Eigen; + +Eigen::Map get_mapvec(Eigen::VectorXd& vec) { + return Eigen::Map(vec.data(), vec.rows(), vec.cols()); +} + +Eigen::Map get_mapmat(MatrixXdr& mat) { + return Eigen::Map(mat.data(), mat.rows(), mat.cols()); +} + +std::vector> get_vec_mapvec(std::vector& vec_vec) { + std::vector> res; + for (Eigen::VectorXd& vec : vec_vec) { + res.push_back(get_mapvec(vec)); + } + return res; +} + +std::vector> get_vec_mapmat(std::vector& mat_vec) { + std::vector> res; + for (MatrixXdr& mat : mat_vec) { + res.push_back(get_mapmat(mat)); + } + return res; +} + +LiveKalman::LiveKalman() { + this->dim_state = 23; + this->dim_state_err = 22; + + this->initial_x = live_initial_x; + this->initial_P = live_initial_P_diag.asDiagonal(); + this->Q = live_Q_diag.asDiagonal(); + for (auto& pair : live_obs_noise_diag) { + this->obs_noise[pair.first] = pair.second.asDiagonal(); + } + + // init filter + this->filter = std::make_shared(this->name, get_mapmat(this->Q), get_mapvec(this->initial_x), + get_mapmat(initial_P), this->dim_state, this->dim_state_err, 0, 0, 0, std::vector(), + std::vector{3}, std::vector(), 0.2); +} + +void LiveKalman::init_state(VectorXd& state, VectorXd& covs_diag, double filter_time) { + MatrixXdr covs = covs_diag.asDiagonal(); + this->filter->init_state(get_mapvec(state), get_mapmat(covs), filter_time); +} + +void LiveKalman::init_state(VectorXd& state, MatrixXdr& covs, double filter_time) { + this->filter->init_state(get_mapvec(state), get_mapmat(covs), filter_time); +} + +void LiveKalman::init_state(VectorXd& state, double filter_time) { + MatrixXdr covs = this->filter->covs(); + this->filter->init_state(get_mapvec(state), get_mapmat(covs), filter_time); +} + +VectorXd LiveKalman::get_x() { + return this->filter->state(); +} + +MatrixXdr LiveKalman::get_P() { + return this->filter->covs(); +} + +double LiveKalman::get_filter_time() { + return this->filter->get_filter_time(); +} + +std::vector LiveKalman::get_R(int kind, int n) { + std::vector R; + for (int i = 0; i < n; i++) { + R.push_back(this->obs_noise[kind]); + } + return R; +} + +std::optional LiveKalman::predict_and_observe(double t, int kind, std::vector meas, std::vector R) { + std::optional r; + switch (kind) { + case OBSERVATION_CAMERA_ODO_TRANSLATION: + r = this->predict_and_update_odo_trans(meas, t, kind); + break; + case OBSERVATION_CAMERA_ODO_ROTATION: + r = this->predict_and_update_odo_rot(meas, t, kind); + break; + case OBSERVATION_ODOMETRIC_SPEED: + r = this->predict_and_update_odo_speed(meas, t, kind); + break; + default: + if (R.size() == 0) { + R = this->get_R(kind, meas.size()); + } + r = this->filter->predict_and_update_batch(t, kind, get_vec_mapvec(meas), get_vec_mapmat(R)); + break; + } + return r; +} + +std::optional LiveKalman::predict_and_update_odo_speed(std::vector speed, double t, int kind) { + std::vector R; + R.assign(speed.size(), (MatrixXdr(1, 1) << std::pow(0.2, 2)).finished().asDiagonal()); + return this->filter->predict_and_update_batch(t, kind, get_vec_mapvec(speed), get_vec_mapmat(R)); +} + +std::optional LiveKalman::predict_and_update_odo_trans(std::vector trans, double t, int kind) { + std::vector z; + std::vector R; + for (VectorXd& trns : trans) { + assert(trns.size() == 6); // TODO remove + z.push_back(trns.head(3)); + R.push_back(trns.segment<3>(3).array().square().matrix().asDiagonal()); + } + return this->filter->predict_and_update_batch(t, kind, get_vec_mapvec(z), get_vec_mapmat(R)); +} + +std::optional LiveKalman::predict_and_update_odo_rot(std::vector rot, double t, int kind) { + std::vector z; + std::vector R; + for (VectorXd& rt : rot) { + assert(rt.size() == 6); // TODO remove + z.push_back(rt.head(3)); + R.push_back(rt.segment<3>(3).array().square().matrix().asDiagonal()); + } + return this->filter->predict_and_update_batch(t, kind, get_vec_mapvec(z), get_vec_mapmat(R)); +} + +Eigen::VectorXd LiveKalman::get_initial_x() { + return this->initial_x; +} + +MatrixXdr LiveKalman::get_initial_P() { + return this->initial_P; +} + +MatrixXdr LiveKalman::H(VectorXd in) { + assert(in.size() == 6); + Matrix res; + this->filter->get_extra_routine("H")(in.data(), res.data()); + return res; +} diff --git a/selfdrive/locationd/models/live_kf.h b/selfdrive/locationd/models/live_kf.h new file mode 100755 index 000000000..4cd4756c9 --- /dev/null +++ b/selfdrive/locationd/models/live_kf.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include "generated/live_kf_constants.h" +#include "rednose/helpers/ekf_sym.h" + +#define EARTH_GM 3.986005e14 // m^3/s^2 (gravitational constant * mass of earth) + +using namespace EKFS; + +Eigen::Map get_mapvec(Eigen::VectorXd& vec); +Eigen::Map get_mapmat(MatrixXdr& mat); +std::vector> get_vec_mapvec(std::vector& vec_vec); +std::vector> get_vec_mapmat(std::vector& mat_vec); + +class LiveKalman { +public: + LiveKalman(); + + void init_state(Eigen::VectorXd& state, Eigen::VectorXd& covs_diag, double filter_time); + void init_state(Eigen::VectorXd& state, MatrixXdr& covs, double filter_time); + void init_state(Eigen::VectorXd& state, double filter_time); + + Eigen::VectorXd get_x(); + MatrixXdr get_P(); + double get_filter_time(); + std::vector get_R(int kind, int n); + + std::optional predict_and_observe(double t, int kind, std::vector meas, std::vector R = {}); + std::optional predict_and_update_odo_speed(std::vector speed, double t, int kind); + std::optional predict_and_update_odo_trans(std::vector trans, double t, int kind); + std::optional predict_and_update_odo_rot(std::vector rot, double t, int kind); + + Eigen::VectorXd get_initial_x(); + MatrixXdr get_initial_P(); + + MatrixXdr H(Eigen::VectorXd in); + +private: + std::string name = "live"; + + std::shared_ptr filter; + + int dim_state; + int dim_state_err; + + Eigen::VectorXd initial_x; + MatrixXdr initial_P; + MatrixXdr Q; // process noise + std::unordered_map obs_noise; +}; diff --git a/selfdrive/locationd/models/live_kf.py b/selfdrive/locationd/models/live_kf.py index 3d8a1f65d..3df1416ae 100755 --- a/selfdrive/locationd/models/live_kf.py +++ b/selfdrive/locationd/models/live_kf.py @@ -1,18 +1,25 @@ #!/usr/bin/env python3 import sys - +import os import numpy as np -import sympy as sp -from selfdrive.swaglog import cloudlog from selfdrive.locationd.models.constants import ObservationKind -from rednose.helpers.ekf_sym import EKF_sym, gen_code + +import sympy as sp +import inspect from rednose.helpers.sympy_helpers import euler_rotate, quat_matrix_r, quat_rotate +from rednose.helpers.ekf_sym import gen_code EARTH_GM = 3.986005e14 # m^3/s^2 (gravitational constant * mass of earth) +def numpy2eigenstring(arr): + assert(len(arr.shape) == 1) + arr_str = np.array2string(arr, precision=20, separator=',')[1:-1].replace(' ', '').replace('\n', '') + return f"(Eigen::VectorXd({len(arr)}) << {arr_str}).finished()" + + class States(): ECEF_POS = slice(0, 3) # x, y and z in ECEF in meters ECEF_ORIENTATION = slice(3, 7) # quat for pose of phone in ecef @@ -48,8 +55,8 @@ class LiveKalman(): # state covariance initial_P_diag = np.array([1e16, 1e16, 1e16, - 1e6, 1e6, 1e6, - 1e4, 1e4, 1e4, + 10**2, 10**2, 10**2, + 10**2, 10**2, 10**2, 1**2, 1**2, 1**2, 0.05**2, 0.05**2, 0.05**2, 0.02**2, @@ -57,14 +64,24 @@ class LiveKalman(): (0.01)**2, (0.01)**2, (0.01)**2]) # process noise - Q = np.diag([0.03**2, 0.03**2, 0.03**2, - 0.001**2, 0.001**2, 0.001**2, - 0.01**2, 0.01**2, 0.01**2, - 0.1**2, 0.1**2, 0.1**2, - (0.005 / 100)**2, (0.005 / 100)**2, (0.005 / 100)**2, - (0.02 / 100)**2, - 3**2, 3**2, 3**2, - (0.05 / 60)**2, (0.05 / 60)**2, (0.05 / 60)**2]) + Q_diag = np.array([0.03**2, 0.03**2, 0.03**2, + 0.001**2, 0.001**2, 0.001**2, + 0.01**2, 0.01**2, 0.01**2, + 0.1**2, 0.1**2, 0.1**2, + (0.005 / 100)**2, (0.005 / 100)**2, (0.005 / 100)**2, + (0.02 / 100)**2, + 3**2, 3**2, 3**2, + (0.05 / 60)**2, (0.05 / 60)**2, (0.05 / 60)**2]) + + obs_noise_diag = {ObservationKind.ODOMETRIC_SPEED: np.array([0.2**2]), + ObservationKind.PHONE_GYRO: np.array([0.025**2, 0.025**2, 0.025**2]), + ObservationKind.PHONE_ACCEL: np.array([.5**2, .5**2, .5**2]), + ObservationKind.CAMERA_ODO_ROTATION: np.array([0.05**2, 0.05**2, 0.05**2]), + ObservationKind.IMU_FRAME: np.array([0.05**2, 0.05**2, 0.05**2]), + ObservationKind.NO_ROT: np.array([0.005**2, 0.005**2, 0.005**2]), + ObservationKind.ECEF_POS: np.array([5**2, 5**2, 5**2]), + ObservationKind.ECEF_VEL: np.array([.5**2, .5**2, .5**2]), + ObservationKind.ECEF_ORIENTATION_FROM_GPS: np.array([.2**2, .2**2, .2**2, .2**2])} @staticmethod def generate_code(generated_dir): @@ -190,99 +207,37 @@ class LiveKalman(): [h_phone_rot_sym, ObservationKind.CAMERA_ODO_ROTATION, None], [h_imu_frame_sym, ObservationKind.IMU_FRAME, None]] - gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state_err, eskf_params) + # this returns a sympy routine for the jacobian of the observation function of the local vel + in_vec = sp.MatrixSymbol('in_vec', 6, 1) # roll, pitch, yaw, vx, vy, vz + h = euler_rotate(in_vec[0], in_vec[1], in_vec[2]).T*(sp.Matrix([in_vec[3], in_vec[4], in_vec[5]])) + extra_routines = [('H', h.jacobian(in_vec), [in_vec])] - def __init__(self, generated_dir): - self.dim_state = self.initial_x.shape[0] - self.dim_state_err = self.initial_P_diag.shape[0] + gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state_err, eskf_params, extra_routines=extra_routines) - self.obs_noise = {ObservationKind.ODOMETRIC_SPEED: np.atleast_2d(0.2**2), - ObservationKind.PHONE_GYRO: np.diag([0.025**2, 0.025**2, 0.025**2]), - ObservationKind.PHONE_ACCEL: np.diag([.5**2, .5**2, .5**2]), - ObservationKind.CAMERA_ODO_ROTATION: np.diag([0.05**2, 0.05**2, 0.05**2]), - ObservationKind.IMU_FRAME: np.diag([0.05**2, 0.05**2, 0.05**2]), - ObservationKind.NO_ROT: np.diag([0.005**2, 0.005**2, 0.005**2]), - ObservationKind.ECEF_POS: np.diag([5**2, 5**2, 5**2]), - ObservationKind.ECEF_VEL: np.diag([.5**2, .5**2, .5**2]), - ObservationKind.ECEF_ORIENTATION_FROM_GPS: np.diag([.2**2, .2**2, .2**2, .2**2])} + # write constants to extra header file for use in cpp + live_kf_header = "#pragma once\n\n" + live_kf_header += "#include \n" + live_kf_header += "#include \n\n" + for state, slc in inspect.getmembers(States, lambda x: type(x) == slice): + assert(slc.step is None) # unsupported + live_kf_header += f'#define STATE_{state}_START {slc.start}\n' + live_kf_header += f'#define STATE_{state}_END {slc.stop}\n' + live_kf_header += f'#define STATE_{state}_LEN {slc.stop - slc.start}\n' + live_kf_header += "\n" - # init filter - self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, np.diag(self.initial_P_diag), self.dim_state, self.dim_state_err, max_rewind_age=0.2, logger=cloudlog) + for kind, val in inspect.getmembers(ObservationKind, lambda x: type(x) == int): + live_kf_header += f'#define OBSERVATION_{kind} {val}\n' + live_kf_header += "\n" - @property - def x(self): - return self.filter.state() + live_kf_header += f"static const Eigen::VectorXd live_initial_x = {numpy2eigenstring(LiveKalman.initial_x)};\n" + live_kf_header += f"static const Eigen::VectorXd live_initial_P_diag = {numpy2eigenstring(LiveKalman.initial_P_diag)};\n" + live_kf_header += f"static const Eigen::VectorXd live_Q_diag = {numpy2eigenstring(LiveKalman.Q_diag)};\n" + live_kf_header += "static const std::unordered_map> live_obs_noise_diag = {\n" + for kind, noise in LiveKalman.obs_noise_diag.items(): + live_kf_header += f" {{ {kind}, {numpy2eigenstring(noise)} }},\n" + live_kf_header += "};\n\n" - @property - def t(self): - return self.filter.filter_time - - @property - def P(self): - return self.filter.covs() - - def rts_smooth(self, estimates): - return self.filter.rts_smooth(estimates, norm_quats=True) - - def init_state(self, state, covs_diag=None, covs=None, filter_time=None): - if covs_diag is not None: - P = np.diag(covs_diag) - elif covs is not None: - P = covs - else: - P = self.filter.covs() - self.filter.init_state(state, P, filter_time) - - def predict_and_observe(self, t, kind, meas, R=None): - if len(meas) > 0: - meas = np.atleast_2d(meas) - if kind == ObservationKind.CAMERA_ODO_TRANSLATION: - r = self.predict_and_update_odo_trans(meas, t, kind) - elif kind == ObservationKind.CAMERA_ODO_ROTATION: - r = self.predict_and_update_odo_rot(meas, t, kind) - elif kind == ObservationKind.ODOMETRIC_SPEED: - r = self.predict_and_update_odo_speed(meas, t, kind) - else: - if R is None: - R = self.get_R(kind, len(meas)) - elif len(R.shape) == 2: - R = R[None] - r = self.filter.predict_and_update_batch(t, kind, meas, R) - - # Normalize quats - quat_norm = np.linalg.norm(self.filter.x[3:7, 0]) - self.filter.x[States.ECEF_ORIENTATION, 0] = self.filter.x[States.ECEF_ORIENTATION, 0] / quat_norm - - return r - - def get_R(self, kind, n): - obs_noise = self.obs_noise[kind] - dim = obs_noise.shape[0] - R = np.zeros((n, dim, dim)) - for i in range(n): - R[i, :, :] = obs_noise - return R - - def predict_and_update_odo_speed(self, speed, t, kind): - z = np.array(speed) - R = np.zeros((len(speed), 1, 1)) - for i, _ in enumerate(z): - R[i, :, :] = np.diag([0.2**2]) - return self.filter.predict_and_update_batch(t, kind, z, R) - - def predict_and_update_odo_trans(self, trans, t, kind): - z = trans[:, :3] - R = np.zeros((len(trans), 3, 3)) - for i, _ in enumerate(z): - R[i, :, :] = np.diag(trans[i, 3:]**2) - return self.filter.predict_and_update_batch(t, kind, z, R) - - def predict_and_update_odo_rot(self, rot, t, kind): - z = rot[:, :3] - R = np.zeros((len(rot), 3, 3)) - for i, _ in enumerate(z): - R[i, :, :] = np.diag(rot[i, 3:]**2) - return self.filter.predict_and_update_batch(t, kind, z, R) + open(os.path.join(generated_dir, "live_kf_constants.h"), 'w').write(live_kf_header) if __name__ == "__main__": diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index 96b3c26dc..119d22fb8 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import gc import math import json @@ -16,12 +17,12 @@ class ParamsLearner: def __init__(self, CP, steer_ratio, stiffness_factor, angle_offset): self.kf = CarKalman(GENERATED_DIR, steer_ratio, stiffness_factor, angle_offset) - self.kf.filter.set_mass(CP.mass) # pylint: disable=no-member - self.kf.filter.set_rotational_inertia(CP.rotationalInertia) # pylint: disable=no-member - self.kf.filter.set_center_to_front(CP.centerToFront) # pylint: disable=no-member - self.kf.filter.set_center_to_rear(CP.wheelbase - CP.centerToFront) # pylint: disable=no-member - self.kf.filter.set_stiffness_front(CP.tireStiffnessFront) # pylint: disable=no-member - self.kf.filter.set_stiffness_rear(CP.tireStiffnessRear) # pylint: disable=no-member + self.kf.filter.set_global("mass", CP.mass) + self.kf.filter.set_global("rotational_inertia", CP.rotationalInertia) + self.kf.filter.set_global("center_to_front", CP.centerToFront) + self.kf.filter.set_global("center_to_rear", CP.wheelbase - CP.centerToFront) + self.kf.filter.set_global("stiffness_front", CP.tireStiffnessFront) + self.kf.filter.set_global("stiffness_rear", CP.tireStiffnessRear) self.active = False @@ -33,18 +34,20 @@ class ParamsLearner: def handle_log(self, t, which, msg): if which == 'liveLocationKalman': - yaw_rate = msg.angularVelocityCalibrated.value[2] yaw_rate_std = msg.angularVelocityCalibrated.std[2] + yaw_rate_valid = msg.angularVelocityCalibrated.valid + yaw_rate_valid = yaw_rate_valid and 0 < yaw_rate_std < 10 # rad/s + yaw_rate_valid = yaw_rate_valid and abs(yaw_rate) < 1 # rad/s if self.active: if msg.inputsOK and msg.posenetOK and yaw_rate_valid: self.kf.predict_and_observe(t, ObservationKind.ROAD_FRAME_YAW_RATE, - np.array([[[-yaw_rate]]]), + np.array([[-yaw_rate]]), np.array([np.atleast_2d(yaw_rate_std**2)])) - self.kf.predict_and_observe(t, ObservationKind.ANGLE_OFFSET_FAST, np.array([[[0]]])) + self.kf.predict_and_observe(t, ObservationKind.ANGLE_OFFSET_FAST, np.array([[0]])) elif which == 'carState': self.steering_angle = msg.steeringAngleDeg @@ -55,16 +58,18 @@ class ParamsLearner: self.active = self.speed > 5 and in_linear_region if self.active: - self.kf.predict_and_observe(t, ObservationKind.STEER_ANGLE, np.array([[[math.radians(msg.steeringAngleDeg)]]])) - self.kf.predict_and_observe(t, ObservationKind.ROAD_FRAME_X_SPEED, np.array([[[self.speed]]])) + self.kf.predict_and_observe(t, ObservationKind.STEER_ANGLE, np.array([[math.radians(msg.steeringAngleDeg)]])) + self.kf.predict_and_observe(t, ObservationKind.ROAD_FRAME_X_SPEED, np.array([[self.speed]])) if not self.active: # Reset time when stopped so uncertainty doesn't grow - self.kf.filter.filter_time = t + self.kf.filter.set_filter_time(t) self.kf.filter.reset_rewind() def main(sm=None, pm=None): + gc.disable() + if sm is None: sm = messaging.SubMaster(['liveLocationKalman', 'carState'], poll=['liveLocationKalman']) if pm is None: @@ -87,16 +92,18 @@ def main(sm=None, pm=None): cloudlog.info("Parameter learner found parameters for wrong car.") params = None - try: - angle_offset_sane = abs(params.get('angleOffsetAverageDeg')) < 10.0 - steer_ratio_sane = min_sr <= params['steerRatio'] <= max_sr - params_sane = angle_offset_sane and steer_ratio_sane - if params is not None and not params_sane: - cloudlog.info(f"Invalid starting values found {params}") + # Check if starting values are sane + if params is not None: + try: + angle_offset_sane = abs(params.get('angleOffsetAverageDeg')) < 10.0 + steer_ratio_sane = min_sr <= params['steerRatio'] <= max_sr + params_sane = angle_offset_sane and steer_ratio_sane + if not params_sane: + cloudlog.info(f"Invalid starting values found {params}") + params = None + except Exception as e: + cloudlog.info(f"Error reading params {params}: {str(e)}") params = None - except Exception as e: - cloudlog.info(f"Error reading params {params}: {str(e)}") - params = None # TODO: cache the params with the capnp struct if params is None: @@ -123,13 +130,17 @@ def main(sm=None, pm=None): learner.handle_log(t, which, sm[which]) if sm.updated['liveLocationKalman']: + x = learner.kf.x + if not all(map(math.isfinite, x)): + cloudlog.error("NaN in liveParameters estimate. Resetting to default values") + learner = ParamsLearner(CP, CP.steerRatio, 1.0, 0.0) + x = learner.kf.x + msg = messaging.new_message('liveParameters') msg.logMonoTime = sm.logMonoTime['carState'] msg.liveParameters.posenetValid = True msg.liveParameters.sensorValid = True - - x = learner.kf.x msg.liveParameters.steerRatio = float(x[States.STEER_RATIO]) msg.liveParameters.stiffnessFactor = float(x[States.STIFFNESS]) msg.liveParameters.angleOffsetAverageDeg = math.degrees(x[States.ANGLE_OFFSET]) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 154200c08..064d4f90d 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -1,144 +1,30 @@ -#include -#include -#include -#include -#include -#include - -#include "common/swaglog.h" - #include "ublox_msg.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "selfdrive/common/swaglog.h" + +const double gpsPi = 3.1415926535898; #define UBLOX_MSG_SIZE(hdr) (*(uint16_t *)&hdr[4]) -#define GET_FIELD_U(w, nb, pos) (((w) >> (pos)) & ((1<<(nb))-1)) -namespace ublox { - -inline int twos_complement(uint32_t v, uint32_t nb) { - int sign = v >> (nb - 1); - int value = v; - if(sign != 0) - value = value - (1 << nb); - return value; -} - -inline int GET_FIELD_S(uint32_t w, uint32_t nb, uint32_t pos) { - int v = GET_FIELD_U(w, nb, pos); - return twos_complement(v, nb); -} - -class EphemerisData { - public: - EphemerisData(uint8_t svId, subframes_map &subframes) { - this->svId = svId; - int week_no = GET_FIELD_U(subframes[1][2+0], 10, 20); - int t_gd = GET_FIELD_S(subframes[1][2+4], 8, 6); - int iodc = (GET_FIELD_U(subframes[1][2+0], 2, 6) << 8) | GET_FIELD_U( - subframes[1][2+5], 8, 22); - - int t_oc = GET_FIELD_U(subframes[1][2+5], 16, 6); - int a_f2 = GET_FIELD_S(subframes[1][2+6], 8, 22); - int a_f1 = GET_FIELD_S(subframes[1][2+6], 16, 6); - int a_f0 = GET_FIELD_S(subframes[1][2+7], 22, 8); - - int c_rs = GET_FIELD_S(subframes[2][2+0], 16, 6); - int delta_n = GET_FIELD_S(subframes[2][2+1], 16, 14); - int m_0 = (GET_FIELD_S(subframes[2][2+1], 8, 6) << 24) | GET_FIELD_U( - subframes[2][2+2], 24, 6); - int c_uc = GET_FIELD_S(subframes[2][2+3], 16, 14); - int e = (GET_FIELD_U(subframes[2][2+3], 8, 6) << 24) | GET_FIELD_U(subframes[2][2+4], 24, 6); - int c_us = GET_FIELD_S(subframes[2][2+5], 16, 14); - uint32_t a_powhalf = (GET_FIELD_U(subframes[2][2+5], 8, 6) << 24) | GET_FIELD_U( - subframes[2][2+6], 24, 6); - int t_oe = GET_FIELD_U(subframes[2][2+7], 16, 14); - - int c_ic = GET_FIELD_S(subframes[3][2+0], 16, 14); - int omega_0 = (GET_FIELD_S(subframes[3][2+0], 8, 6) << 24) | GET_FIELD_U( - subframes[3][2+1], 24, 6); - int c_is = GET_FIELD_S(subframes[3][2+2], 16, 14); - int i_0 = (GET_FIELD_S(subframes[3][2+2], 8, 6) << 24) | GET_FIELD_U( - subframes[3][2+3], 24, 6); - int c_rc = GET_FIELD_S(subframes[3][2+4], 16, 14); - int w = (GET_FIELD_S(subframes[3][2+4], 8, 6) << 24) | GET_FIELD_U(subframes[3][5], 24, 6); - int omega_dot = GET_FIELD_S(subframes[3][2+6], 24, 6); - int idot = GET_FIELD_S(subframes[3][2+7], 14, 8); - - this->_rsvd1 = GET_FIELD_U(subframes[1][2+1], 23, 6); - this->_rsvd2 = GET_FIELD_U(subframes[1][2+2], 24, 6); - this->_rsvd3 = GET_FIELD_U(subframes[1][2+3], 24, 6); - this->_rsvd4 = GET_FIELD_U(subframes[1][2+4], 16, 14); - this->aodo = GET_FIELD_U(subframes[2][2+7], 5, 8); - - double gpsPi = 3.1415926535898; - - // now form variables in radians, meters and seconds etc - this->Tgd = t_gd * pow(2, -31); - this->A = pow(a_powhalf * pow(2, -19), 2.0); - this->cic = c_ic * pow(2, -29); - this->cis = c_is * pow(2, -29); - this->crc = c_rc * pow(2, -5); - this->crs = c_rs * pow(2, -5); - this->cuc = c_uc * pow(2, -29); - this->cus = c_us * pow(2, -29); - this->deltaN = delta_n * pow(2, -43) * gpsPi; - this->ecc = e * pow(2, -33); - this->i0 = i_0 * pow(2, -31) * gpsPi; - this->idot = idot * pow(2, -43) * gpsPi; - this->M0 = m_0 * pow(2, -31) * gpsPi; - this->omega = w * pow(2, -31) * gpsPi; - this->omega_dot = omega_dot * pow(2, -43) * gpsPi; - this->omega0 = omega_0 * pow(2, -31) * gpsPi; - this->toe = t_oe * pow(2, 4); - - this->toc = t_oc * pow(2, 4); - this->gpsWeek = week_no; - this->af0 = a_f0 * pow(2, -31); - this->af1 = a_f1 * pow(2, -43); - this->af2 = a_f2 * pow(2, -55); - - uint32_t iode1 = GET_FIELD_U(subframes[2][2+0], 8, 22); - uint32_t iode2 = GET_FIELD_U(subframes[3][2+7], 8, 22); - this->valid = (iode1 == iode2) && (iode1 == (iodc & 0xff)); - this->iode = iode1; - - if (GET_FIELD_U(subframes[4][2+0], 6, 22) == 56 && - GET_FIELD_U(subframes[4][2+0], 2, 28) == 1 && - GET_FIELD_U(subframes[5][2+0], 2, 28) == 1) { - double a0 = GET_FIELD_S(subframes[4][2], 8, 14) * pow(2, -30); - double a1 = GET_FIELD_S(subframes[4][2], 8, 6) * pow(2, -27); - double a2 = GET_FIELD_S(subframes[4][3], 8, 22) * pow(2, -24); - double a3 = GET_FIELD_S(subframes[4][3], 8, 14) * pow(2, -24); - double b0 = GET_FIELD_S(subframes[4][3], 8, 6) * pow(2, 11); - double b1 = GET_FIELD_S(subframes[4][4], 8, 22) * pow(2, 14); - double b2 = GET_FIELD_S(subframes[4][4], 8, 14) * pow(2, 16); - double b3 = GET_FIELD_S(subframes[4][4], 8, 6) * pow(2, 16); - this->ionoAlpha[0] = a0;this->ionoAlpha[1] = a1;this->ionoAlpha[2] = a2;this->ionoAlpha[3] = a3; - this->ionoBeta[0] = b0;this->ionoBeta[1] = b1;this->ionoBeta[2] = b2;this->ionoBeta[3] = b3; - this->ionoCoeffsValid = true; - } else { - this->ionoCoeffsValid = false; - } - } - uint16_t svId; - double Tgd, A, cic, cis, crc, crs, cuc, cus, deltaN, ecc, i0, idot, M0, omega, omega_dot, omega0, toe, toc; - uint32_t gpsWeek, iode, _rsvd1, _rsvd2, _rsvd3, _rsvd4, aodo; - double af0, af1, af2; - bool valid; - double ionoAlpha[4], ionoBeta[4]; - bool ionoCoeffsValid; -}; - -UbloxMsgParser::UbloxMsgParser() :bytes_in_parse_buf(0) { - nav_frame_buffer[0U] = std::map(); - for(int i = 1;i < 33;i++) - nav_frame_buffer[0U][i] = subframes_map(); +inline static bool bit_to_bool(uint8_t val, int shifts) { + return (bool)(val & (1 << shifts)); } inline int UbloxMsgParser::needed_bytes() { // Msg header incomplete? - if(bytes_in_parse_buf < UBLOX_HEADER_SIZE) - return UBLOX_HEADER_SIZE + UBLOX_CHECKSUM_SIZE - bytes_in_parse_buf; - uint16_t needed = UBLOX_MSG_SIZE(msg_parse_buf) + UBLOX_HEADER_SIZE + UBLOX_CHECKSUM_SIZE; + if(bytes_in_parse_buf < ublox::UBLOX_HEADER_SIZE) + return ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_CHECKSUM_SIZE - bytes_in_parse_buf; + uint16_t needed = UBLOX_MSG_SIZE(msg_parse_buf) + ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_CHECKSUM_SIZE; // too much data if(needed < (uint16_t)bytes_in_parse_buf) return -1; @@ -147,7 +33,7 @@ inline int UbloxMsgParser::needed_bytes() { inline bool UbloxMsgParser::valid_cheksum() { uint8_t ck_a = 0, ck_b = 0; - for(int i = 2; i < bytes_in_parse_buf - UBLOX_CHECKSUM_SIZE;i++) { + for(int i = 2; i < bytes_in_parse_buf - ublox::UBLOX_CHECKSUM_SIZE;i++) { ck_a = (ck_a + msg_parse_buf[i]) & 0xFF; ck_b = (ck_b + ck_a) & 0xFF; } @@ -163,17 +49,15 @@ inline bool UbloxMsgParser::valid_cheksum() { } inline bool UbloxMsgParser::valid() { - return bytes_in_parse_buf >= UBLOX_HEADER_SIZE + UBLOX_CHECKSUM_SIZE && + return bytes_in_parse_buf >= ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_CHECKSUM_SIZE && needed_bytes() == 0 && valid_cheksum(); } inline bool UbloxMsgParser::valid_so_far() { - if(bytes_in_parse_buf > 0 && msg_parse_buf[0] != PREAMBLE1) { - //LOGD("PREAMBLE1 invalid, %02X.", msg_parse_buf[0]); + if(bytes_in_parse_buf > 0 && msg_parse_buf[0] != ublox::PREAMBLE1) { return false; } - if(bytes_in_parse_buf > 1 && msg_parse_buf[1] != PREAMBLE2) { - //LOGD("PREAMBLE2 invalid, %02X.", msg_parse_buf[1]); + if(bytes_in_parse_buf > 1 && msg_parse_buf[1] != ublox::PREAMBLE2) { return false; } if(needed_bytes() == 0 && !valid()) { @@ -182,192 +66,6 @@ inline bool UbloxMsgParser::valid_so_far() { return true; } -kj::Array UbloxMsgParser::gen_solution() { - nav_pvt_msg *msg = (nav_pvt_msg *)&msg_parse_buf[UBLOX_HEADER_SIZE]; - MessageBuilder msg_builder; - auto gpsLoc = msg_builder.initEvent().initGpsLocationExternal(); - gpsLoc.setSource(cereal::GpsLocationData::SensorSource::UBLOX); - gpsLoc.setFlags(msg->flags); - gpsLoc.setLatitude(msg->lat * 1e-07); - gpsLoc.setLongitude(msg->lon * 1e-07); - gpsLoc.setAltitude(msg->height * 1e-03); - gpsLoc.setSpeed(msg->gSpeed * 1e-03); - gpsLoc.setBearingDeg(msg->headMot * 1e-5); - gpsLoc.setAccuracy(msg->hAcc * 1e-03); - std::tm timeinfo = std::tm(); - timeinfo.tm_year = msg->year - 1900; - timeinfo.tm_mon = msg->month - 1; - timeinfo.tm_mday = msg->day; - timeinfo.tm_hour = msg->hour; - timeinfo.tm_min = msg->min; - timeinfo.tm_sec = msg->sec; - std::time_t utc_tt = timegm(&timeinfo); - gpsLoc.setTimestamp(utc_tt * 1e+03 + msg->nano * 1e-06); - float f[] = { msg->velN * 1e-03f, msg->velE * 1e-03f, msg->velD * 1e-03f }; - gpsLoc.setVNED(f); - gpsLoc.setVerticalAccuracy(msg->vAcc * 1e-03); - gpsLoc.setSpeedAccuracy(msg->sAcc * 1e-03); - gpsLoc.setBearingAccuracyDeg(msg->headAcc * 1e-05); - return capnp::messageToFlatArray(msg_builder); -} - -inline bool bit_to_bool(uint8_t val, int shifts) { - return (bool)(val & (1 << shifts)); -} - -kj::Array UbloxMsgParser::gen_raw() { - rxm_raw_msg *msg = (rxm_raw_msg *)&msg_parse_buf[UBLOX_HEADER_SIZE]; - if(bytes_in_parse_buf != ( - UBLOX_HEADER_SIZE + sizeof(rxm_raw_msg) + msg->numMeas * sizeof(rxm_raw_msg_extra) + UBLOX_CHECKSUM_SIZE - )) { - LOGD("Invalid measurement size %u, %u, %u, %u", msg->numMeas, bytes_in_parse_buf, sizeof(rxm_raw_msg_extra), sizeof(rxm_raw_msg)); - return kj::Array(); - } - rxm_raw_msg_extra *measurements = (rxm_raw_msg_extra *)&msg_parse_buf[UBLOX_HEADER_SIZE + sizeof(rxm_raw_msg)]; - MessageBuilder msg_builder; - auto mr = msg_builder.initEvent().initUbloxGnss().initMeasurementReport(); - mr.setRcvTow(msg->rcvTow); - mr.setGpsWeek(msg->week); - mr.setLeapSeconds(msg->leapS); - mr.setGpsWeek(msg->week); - auto mb = mr.initMeasurements(msg->numMeas); - for(int8_t i = 0; i < msg->numMeas; i++) { - mb[i].setSvId(measurements[i].svId); - mb[i].setSigId(measurements[i].sigId); - mb[i].setPseudorange(measurements[i].prMes); - mb[i].setCarrierCycles(measurements[i].cpMes); - mb[i].setDoppler(measurements[i].doMes); - mb[i].setGnssId(measurements[i].gnssId); - mb[i].setGlonassFrequencyIndex(measurements[i].freqId); - mb[i].setLocktime(measurements[i].locktime); - mb[i].setCno(measurements[i].cno); - mb[i].setPseudorangeStdev(0.01*(pow(2, (measurements[i].prStdev & 15)))); // weird scaling, might be wrong - mb[i].setCarrierPhaseStdev(0.004*(measurements[i].cpStdev & 15)); - mb[i].setDopplerStdev(0.002*(pow(2, (measurements[i].doStdev & 15)))); // weird scaling, might be wrong - auto ts = mb[i].initTrackingStatus(); - ts.setPseudorangeValid(bit_to_bool(measurements[i].trkStat, 0)); - ts.setCarrierPhaseValid(bit_to_bool(measurements[i].trkStat, 1)); - ts.setHalfCycleValid(bit_to_bool(measurements[i].trkStat, 2)); - ts.setHalfCycleSubtracted(bit_to_bool(measurements[i].trkStat, 3)); - } - - mr.setNumMeas(msg->numMeas); - auto rs = mr.initReceiverStatus(); - rs.setLeapSecValid(bit_to_bool(msg->recStat, 0)); - rs.setClkReset(bit_to_bool(msg->recStat, 2)); - return capnp::messageToFlatArray(msg_builder); -} - -kj::Array UbloxMsgParser::gen_nav_data() { - rxm_sfrbx_msg *msg = (rxm_sfrbx_msg *)&msg_parse_buf[UBLOX_HEADER_SIZE]; - if(bytes_in_parse_buf != ( - UBLOX_HEADER_SIZE + sizeof(rxm_sfrbx_msg) + msg->numWords * sizeof(rxm_sfrbx_msg_extra) + UBLOX_CHECKSUM_SIZE - )) { - LOGD("Invalid sfrbx words size %u, %u, %u, %u", msg->numWords, bytes_in_parse_buf, sizeof(rxm_raw_msg_extra), sizeof(rxm_raw_msg)); - return kj::Array(); - } - rxm_sfrbx_msg_extra *measurements = (rxm_sfrbx_msg_extra *)&msg_parse_buf[UBLOX_HEADER_SIZE + sizeof(rxm_sfrbx_msg)]; - if(msg->gnssId == 0) { - uint8_t subframeId = GET_FIELD_U(measurements[1].dwrd, 3, 8); - std::vector words; - for(int i = 0; i < msg->numWords;i++) - words.push_back(measurements[i].dwrd); - - subframes_map &map = nav_frame_buffer[msg->gnssId][msg->svid]; - if (subframeId == 1) { - map = subframes_map(); - map[subframeId] = words; - } else if (map.find(subframeId-1) != map.end()) { - map[subframeId] = words; - } - if(map.size() == 5) { - EphemerisData ephem_data(msg->svid, map); - MessageBuilder msg_builder; - auto eph = msg_builder.initEvent().initUbloxGnss().initEphemeris(); - eph.setSvId(ephem_data.svId); - eph.setToc(ephem_data.toc); - eph.setGpsWeek(ephem_data.gpsWeek); - eph.setAf0(ephem_data.af0); - eph.setAf1(ephem_data.af1); - eph.setAf2(ephem_data.af2); - eph.setIode(ephem_data.iode); - eph.setCrs(ephem_data.crs); - eph.setDeltaN(ephem_data.deltaN); - eph.setM0(ephem_data.M0); - eph.setCuc(ephem_data.cuc); - eph.setEcc(ephem_data.ecc); - eph.setCus(ephem_data.cus); - eph.setA(ephem_data.A); - eph.setToe(ephem_data.toe); - eph.setCic(ephem_data.cic); - eph.setOmega0(ephem_data.omega0); - eph.setCis(ephem_data.cis); - eph.setI0(ephem_data.i0); - eph.setCrc(ephem_data.crc); - eph.setOmega(ephem_data.omega); - eph.setOmegaDot(ephem_data.omega_dot); - eph.setIDot(ephem_data.idot); - eph.setTgd(ephem_data.Tgd); - eph.setIonoCoeffsValid(ephem_data.ionoCoeffsValid); - if(ephem_data.ionoCoeffsValid) { - eph.setIonoAlpha(ephem_data.ionoAlpha); - eph.setIonoBeta(ephem_data.ionoBeta); - } else { - eph.setIonoAlpha(kj::ArrayPtr()); - eph.setIonoBeta(kj::ArrayPtr()); - } - return capnp::messageToFlatArray(msg_builder); - } - } - return kj::Array(); -} - -kj::Array UbloxMsgParser::gen_mon_hw() { - mon_hw_msg *msg = (mon_hw_msg *)&msg_parse_buf[UBLOX_HEADER_SIZE]; - - MessageBuilder msg_builder; - auto hwStatus = msg_builder.initEvent().initUbloxGnss().initHwStatus(); - hwStatus.setNoisePerMS(msg->noisePerMS); - hwStatus.setAgcCnt(msg->agcCnt); - hwStatus.setAStatus((cereal::UbloxGnss::HwStatus::AntennaSupervisorState) msg->aStatus); - hwStatus.setAPower((cereal::UbloxGnss::HwStatus::AntennaPowerStatus) msg->aPower); - hwStatus.setJamInd(msg->jamInd); - return capnp::messageToFlatArray(msg_builder); -} - -kj::Array UbloxMsgParser::gen_mon_hw2() { - mon_hw2_msg *msg = (mon_hw2_msg *)&msg_parse_buf[UBLOX_HEADER_SIZE]; - - MessageBuilder msg_builder; - auto hwStatus = msg_builder.initEvent().initUbloxGnss().initHwStatus2(); - hwStatus.setOfsI(msg->ofsI); - hwStatus.setMagI(msg->magI); - hwStatus.setOfsQ(msg->ofsQ); - hwStatus.setMagQ(msg->magQ); - - switch (msg->cfgSource) { - case 114: - hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::ROM); - break; - case 111: - hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::OTP); - break; - case 112: - hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::CONFIGPINS); - break; - case 102: - hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::FLASH); - break; - default: - hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::UNDEFINED); - break; - } - - hwStatus.setLowLevCfg(msg->lowLevCfg); - hwStatus.setPostStatus(msg->postStatus); - - return capnp::messageToFlatArray(msg_builder); -} bool UbloxMsgParser::add_data(const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed) { int needed = needed_bytes(); @@ -379,18 +77,268 @@ bool UbloxMsgParser::add_data(const uint8_t *incoming_data, uint32_t incoming_da } else { bytes_consumed = incoming_data_len; } + // Validate msg format, detect invalid header and invalid checksum. while(!valid_so_far() && bytes_in_parse_buf != 0) { - //LOGD("Drop corrupt data, remained in buf: %u", bytes_in_parse_buf); // Corrupted msg, drop a byte. bytes_in_parse_buf -= 1; if(bytes_in_parse_buf > 0) memmove(&msg_parse_buf[0], &msg_parse_buf[1], bytes_in_parse_buf); } + // There is redundant data at the end of buffer, reset the buffer. - if(needed_bytes() == -1) + if(needed_bytes() == -1) { bytes_in_parse_buf = 0; + } return valid(); } + +std::pair> UbloxMsgParser::gen_msg() { + std::string dat = data(); + kaitai::kstream stream(dat); + + ubx_t ubx_message(&stream); + auto body = ubx_message.body(); + + switch (ubx_message.msg_type()) { + case 0x0107: + return {"gpsLocationExternal", gen_nav_pvt(static_cast(body))}; + break; + case 0x0213: + return {"ubloxGnss", gen_rxm_sfrbx(static_cast(body))}; + break; + case 0x0215: + return {"ubloxGnss", gen_rxm_rawx(static_cast(body))}; + break; + case 0x0a09: + return {"ubloxGnss", gen_mon_hw(static_cast(body))}; + break; + case 0x0a0b: + return {"ubloxGnss", gen_mon_hw2(static_cast(body))}; + break; + default: + LOGE("Unkown message type %x", ubx_message.msg_type()); + return {"ubloxGnss", kj::Array()}; + break; + } +} + + +kj::Array UbloxMsgParser::gen_nav_pvt(ubx_t::nav_pvt_t *msg) { + MessageBuilder msg_builder; + auto gpsLoc = msg_builder.initEvent().initGpsLocationExternal(); + gpsLoc.setSource(cereal::GpsLocationData::SensorSource::UBLOX); + gpsLoc.setFlags(msg->flags()); + gpsLoc.setLatitude(msg->lat() * 1e-07); + gpsLoc.setLongitude(msg->lon() * 1e-07); + gpsLoc.setAltitude(msg->height() * 1e-03); + gpsLoc.setSpeed(msg->g_speed() * 1e-03); + gpsLoc.setBearingDeg(msg->head_mot() * 1e-5); + gpsLoc.setAccuracy(msg->h_acc() * 1e-03); + std::tm timeinfo = std::tm(); + timeinfo.tm_year = msg->year() - 1900; + timeinfo.tm_mon = msg->month() - 1; + timeinfo.tm_mday = msg->day(); + timeinfo.tm_hour = msg->hour(); + timeinfo.tm_min = msg->min(); + timeinfo.tm_sec = msg->sec(); + + std::time_t utc_tt = timegm(&timeinfo); + gpsLoc.setTimestamp(utc_tt * 1e+03 + msg->nano() * 1e-06); + float f[] = { msg->vel_n() * 1e-03f, msg->vel_e() * 1e-03f, msg->vel_d() * 1e-03f }; + gpsLoc.setVNED(f); + gpsLoc.setVerticalAccuracy(msg->v_acc() * 1e-03); + gpsLoc.setSpeedAccuracy(msg->s_acc() * 1e-03); + gpsLoc.setBearingAccuracyDeg(msg->head_acc() * 1e-05); + return capnp::messageToFlatArray(msg_builder); +} + + +kj::Array UbloxMsgParser::gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg) { + auto body = *msg->body(); + + if (msg->gnss_id() == ubx_t::gnss_type_t::GNSS_TYPE_GPS) { + // GPS subframes are packed into 10x 4 bytes, each containing 3 actual bytes + // We will first need to separate the data from the padding and parity + assert(body.size() == 10); + + std::string subframe_data; + subframe_data.reserve(30); + for (uint32_t word : body) { + word = word >> 6; // TODO: Verify parity + subframe_data.push_back(word >> 16); + subframe_data.push_back(word >> 8); + subframe_data.push_back(word >> 0); + } + + // Collect subframes in map and parse when we have all the parts + kaitai::kstream stream(subframe_data); + gps_t subframe(&stream); + int subframe_id = subframe.how()->subframe_id(); + + if (subframe_id == 1) gps_subframes[msg->sv_id()].clear(); + gps_subframes[msg->sv_id()][subframe_id] = subframe_data; + + if (gps_subframes[msg->sv_id()].size() == 5) { + MessageBuilder msg_builder; + auto eph = msg_builder.initEvent().initUbloxGnss().initEphemeris(); + eph.setSvId(msg->sv_id()); + + // Subframe 1 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][1]); + gps_t subframe(&stream); + gps_t::subframe_1_t* subframe_1 = static_cast(subframe.body()); + + eph.setGpsWeek(subframe_1->week_no()); + eph.setTgd(subframe_1->t_gd() * pow(2, -31)); + eph.setToc(subframe_1->t_oc() * pow(2, 4)); + eph.setAf2(subframe_1->af_2() * pow(2, -55)); + eph.setAf1(subframe_1->af_1() * pow(2, -43)); + eph.setAf0(subframe_1->af_0() * pow(2, -31)); + } + + // Subframe 2 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][2]); + gps_t subframe(&stream); + gps_t::subframe_2_t* subframe_2 = static_cast(subframe.body()); + + eph.setCrs(subframe_2->c_rs() * pow(2, -5)); + eph.setDeltaN(subframe_2->delta_n() * pow(2, -43) * gpsPi); + eph.setM0(subframe_2->m_0() * pow(2, -31) * gpsPi); + eph.setCuc(subframe_2->c_uc() * pow(2, -29)); + eph.setEcc(subframe_2->e() * pow(2, -33)); + eph.setCus(subframe_2->c_us() * pow(2, -29)); + eph.setA(pow(subframe_2->sqrt_a() * pow(2, -19), 2.0)); + eph.setToe(subframe_2->t_oe() * pow(2, 4)); + } + + // Subframe 3 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][3]); + gps_t subframe(&stream); + gps_t::subframe_3_t* subframe_3 = static_cast(subframe.body()); + + eph.setCic(subframe_3->c_ic() * pow(2, -29)); + eph.setOmega0(subframe_3->omega_0() * pow(2, -31) * gpsPi); + eph.setCis(subframe_3->c_is() * pow(2, -29)); + eph.setI0(subframe_3->i_0() * pow(2, -31) * gpsPi); + eph.setCrc(subframe_3->c_rc() * pow(2, -5)); + eph.setOmega(subframe_3->omega() * pow(2, -31) * gpsPi); + eph.setOmegaDot(subframe_3->omega_dot() * pow(2, -43) * gpsPi); + eph.setIode(subframe_3->iode()); + eph.setIDot(subframe_3->idot() * pow(2, -43) * gpsPi); + } + + // Subframe 4 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][4]); + gps_t subframe(&stream); + gps_t::subframe_4_t* subframe_4 = static_cast(subframe.body()); + + // This is page 18, why is the page id 56? + if (subframe_4->data_id() == 1 && subframe_4->page_id() == 56) { + auto iono = static_cast(subframe_4->body()); + double a0 = iono->a0() * pow(2, -30); + double a1 = iono->a1() * pow(2, -27); + double a2 = iono->a2() * pow(2, -24); + double a3 = iono->a3() * pow(2, -24); + eph.setIonoAlpha({a0, a1, a2, a3}); + + double b0 = iono->b0() * pow(2, 11); + double b1 = iono->b1() * pow(2, 14); + double b2 = iono->b2() * pow(2, 16); + double b3 = iono->b3() * pow(2, 16); + eph.setIonoBeta({b0, b1, b2, b3}); + } + } + + return capnp::messageToFlatArray(msg_builder); + } + } + return kj::Array(); +} + +kj::Array UbloxMsgParser::gen_rxm_rawx(ubx_t::rxm_rawx_t *msg) { + MessageBuilder msg_builder; + auto mr = msg_builder.initEvent().initUbloxGnss().initMeasurementReport(); + mr.setRcvTow(msg->rcv_tow()); + mr.setGpsWeek(msg->week()); + mr.setLeapSeconds(msg->leap_s()); + mr.setGpsWeek(msg->week()); + + auto mb = mr.initMeasurements(msg->num_meas()); + auto measurements = *msg->measurements(); + for(int8_t i = 0; i < msg->num_meas(); i++) { + mb[i].setSvId(measurements[i]->sv_id()); + mb[i].setPseudorange(measurements[i]->pr_mes()); + mb[i].setCarrierCycles(measurements[i]->cp_mes()); + mb[i].setDoppler(measurements[i]->do_mes()); + mb[i].setGnssId(measurements[i]->gnss_id()); + mb[i].setGlonassFrequencyIndex(measurements[i]->freq_id()); + mb[i].setLocktime(measurements[i]->lock_time()); + mb[i].setCno(measurements[i]->cno()); + mb[i].setPseudorangeStdev(0.01 * (pow(2, (measurements[i]->pr_stdev() & 15)))); // weird scaling, might be wrong + mb[i].setCarrierPhaseStdev(0.004 * (measurements[i]->cp_stdev() & 15)); + mb[i].setDopplerStdev(0.002 * (pow(2, (measurements[i]->do_stdev() & 15)))); // weird scaling, might be wrong + + auto ts = mb[i].initTrackingStatus(); + auto trk_stat = measurements[i]->trk_stat(); + ts.setPseudorangeValid(bit_to_bool(trk_stat, 0)); + ts.setCarrierPhaseValid(bit_to_bool(trk_stat, 1)); + ts.setHalfCycleValid(bit_to_bool(trk_stat, 2)); + ts.setHalfCycleSubtracted(bit_to_bool(trk_stat, 3)); + } + + mr.setNumMeas(msg->num_meas()); + auto rs = mr.initReceiverStatus(); + rs.setLeapSecValid(bit_to_bool(msg->rec_stat(), 0)); + rs.setClkReset(bit_to_bool(msg->rec_stat(), 2)); + return capnp::messageToFlatArray(msg_builder); +} + +kj::Array UbloxMsgParser::gen_mon_hw(ubx_t::mon_hw_t *msg) { + MessageBuilder msg_builder; + auto hwStatus = msg_builder.initEvent().initUbloxGnss().initHwStatus(); + hwStatus.setNoisePerMS(msg->noise_per_ms()); + hwStatus.setFlags(msg->flags()); + hwStatus.setAgcCnt(msg->agc_cnt()); + hwStatus.setAStatus((cereal::UbloxGnss::HwStatus::AntennaSupervisorState) msg->a_status()); + hwStatus.setAPower((cereal::UbloxGnss::HwStatus::AntennaPowerStatus) msg->a_power()); + hwStatus.setJamInd(msg->jam_ind()); + return capnp::messageToFlatArray(msg_builder); +} + +kj::Array UbloxMsgParser::gen_mon_hw2(ubx_t::mon_hw2_t *msg) { + MessageBuilder msg_builder; + auto hwStatus = msg_builder.initEvent().initUbloxGnss().initHwStatus2(); + hwStatus.setOfsI(msg->ofs_i()); + hwStatus.setMagI(msg->mag_i()); + hwStatus.setOfsQ(msg->ofs_q()); + hwStatus.setMagQ(msg->mag_q()); + + switch (msg->cfg_source()) { + case ubx_t::mon_hw2_t::config_source_t::CONFIG_SOURCE_ROM: + hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::ROM); + break; + case ubx_t::mon_hw2_t::config_source_t::CONFIG_SOURCE_OTP: + hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::OTP); + break; + case ubx_t::mon_hw2_t::config_source_t::CONFIG_SOURCE_CONFIG_PINS: + hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::CONFIGPINS); + break; + case ubx_t::mon_hw2_t::config_source_t::CONFIG_SOURCE_FLASH: + hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::FLASH); + break; + default: + hwStatus.setCfgSource(cereal::UbloxGnss::HwStatus2::ConfigSource::UNDEFINED); + break; + } + + hwStatus.setLowLevCfg(msg->low_lev_cfg()); + hwStatus.setPostStatus(msg->post_status()); + + return capnp::messageToFlatArray(msg_builder); } diff --git a/selfdrive/locationd/ublox_msg.h b/selfdrive/locationd/ublox_msg.h index 2e99e94e1..1f8ed9747 100644 --- a/selfdrive/locationd/ublox_msg.h +++ b/selfdrive/locationd/ublox_msg.h @@ -1,191 +1,52 @@ #pragma once -#include -#include "messaging.hpp" +#include +#include +#include +#include -// NAV_PVT -typedef struct __attribute__((packed)) { - uint32_t iTOW; - uint16_t year; - int8_t month; - int8_t day; - int8_t hour; - int8_t min; - int8_t sec; - int8_t valid; - uint32_t tAcc; - int32_t nano; - int8_t fixType; - int8_t flags; - int8_t flags2; - int8_t numSV; - int32_t lon; - int32_t lat; - int32_t height; - int32_t hMSL; - uint32_t hAcc; - uint32_t vAcc; - int32_t velN; - int32_t velE; - int32_t velD; - int32_t gSpeed; - int32_t headMot; - uint32_t sAcc; - uint32_t headAcc; - uint16_t pDOP; - int8_t reserverd1[6]; - int32_t headVeh; - int16_t magDec; - uint16_t magAcc; -} nav_pvt_msg; - -// RXM_RAW -typedef struct __attribute__((packed)) { - double rcvTow; - uint16_t week; - int8_t leapS; - int8_t numMeas; - int8_t recStat; - int8_t reserved1[3]; -} rxm_raw_msg; - -// Extra data count is in numMeas -typedef struct __attribute__((packed)) { - double prMes; - double cpMes; - float doMes; - int8_t gnssId; - int8_t svId; - int8_t sigId; - int8_t freqId; - uint16_t locktime; - int8_t cno; - int8_t prStdev; - int8_t cpStdev; - int8_t doStdev; - int8_t trkStat; - int8_t reserved3; -} rxm_raw_msg_extra; - -// RXM_SFRBX -typedef struct __attribute__((packed)) { - int8_t gnssId; - int8_t svid; - int8_t reserved1; - int8_t freqId; - int8_t numWords; - int8_t reserved2; - int8_t version; - int8_t reserved3; -} rxm_sfrbx_msg; - -// Extra data count is in numWords -typedef struct __attribute__((packed)) { - uint32_t dwrd; -} rxm_sfrbx_msg_extra; - -// MON_HW -typedef struct __attribute__((packed)) { - uint32_t pinSel; - uint32_t pinBank; - uint32_t pinDir; - uint32_t pinVal; - uint16_t noisePerMS; - uint16_t agcCnt; - uint8_t aStatus; - uint8_t aPower; - uint8_t flags; - uint8_t reserved1; - uint32_t usedMask; - uint8_t VP[17]; - uint8_t jamInd; - uint8_t reserved2[2]; - uint32_t pinIrq; - uint32_t pullH; - uint32_t pullL; -} mon_hw_msg; - -// MON_HW2 -typedef struct __attribute__((packed)) { - int8_t ofsI; - uint8_t magI; - int8_t ofsQ; - uint8_t magQ; - uint8_t cfgSource; - uint8_t reserved1[3]; - uint32_t lowLevCfg; - uint8_t reserved2[8]; - uint32_t postStatus; - uint8_t reserved3[4]; -} mon_hw2_msg; +#include "cereal/messaging/messaging.h" +#include "selfdrive/locationd/generated/gps.h" +#include "selfdrive/locationd/generated/ubx.h" +// protocol constants namespace ublox { - // protocol constants const uint8_t PREAMBLE1 = 0xb5; const uint8_t PREAMBLE2 = 0x62; - // message classes - const uint8_t CLASS_NAV = 0x01; - const uint8_t CLASS_RXM = 0x02; - const uint8_t CLASS_MON = 0x0A; - - // NAV messages - const uint8_t MSG_NAV_PVT = 0x7; - - // RXM messages - const uint8_t MSG_RXM_RAW = 0x15; - const uint8_t MSG_RXM_SFRBX = 0x13; - - // MON messages - const uint8_t MSG_MON_HW = 0x09; - const uint8_t MSG_MON_HW2 = 0x0B; - const int UBLOX_HEADER_SIZE = 6; const int UBLOX_CHECKSUM_SIZE = 2; const int UBLOX_MAX_MSG_SIZE = 65536; - typedef std::map> subframes_map; - - class UbloxMsgParser { - public: - - UbloxMsgParser(); - kj::Array gen_solution(); - kj::Array gen_raw(); - kj::Array gen_mon_hw(); - kj::Array gen_mon_hw2(); - - kj::Array gen_nav_data(); - bool add_data(const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed); - inline void reset() {bytes_in_parse_buf = 0;} - inline uint8_t msg_class() { - return msg_parse_buf[2]; - } - - inline uint8_t msg_id() { - return msg_parse_buf[3]; - } - inline int needed_bytes(); - - void hexdump(uint8_t *d, int l) { - for (int i = 0; i < l; i++) { - if (i%0x10 == 0 && i != 0) printf("\n"); - printf("%02X ", d[i]); - } - printf("\n"); - } - private: - inline bool valid_cheksum(); - inline bool valid(); - inline bool valid_so_far(); - - uint8_t msg_parse_buf[UBLOX_HEADER_SIZE + UBLOX_MAX_MSG_SIZE]; - int bytes_in_parse_buf; - std::map> nav_frame_buffer; - }; - + // Boardd still uses these: + const uint8_t CLASS_NAV = 0x01; + const uint8_t CLASS_RXM = 0x02; + const uint8_t CLASS_MON = 0x0A; } -typedef Message * (*poll_ubloxraw_msg_func)(Poller *poller); -typedef int (*send_gps_event_func)(PubSocket *s, const void *buf, size_t len); -int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func); +class UbloxMsgParser { + public: + bool add_data(const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed); + inline void reset() {bytes_in_parse_buf = 0;} + inline int needed_bytes(); + inline std::string data() {return std::string((const char*)msg_parse_buf, bytes_in_parse_buf);} + + std::pair> gen_msg(); + kj::Array gen_nav_pvt(ubx_t::nav_pvt_t *msg); + kj::Array gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg); + kj::Array gen_rxm_rawx(ubx_t::rxm_rawx_t *msg); + kj::Array gen_mon_hw(ubx_t::mon_hw_t *msg); + kj::Array gen_mon_hw2(ubx_t::mon_hw2_t *msg); + + private: + inline bool valid_cheksum(); + inline bool valid(); + inline bool valid_so_far(); + + std::unordered_map> gps_subframes; + + size_t bytes_in_parse_buf = 0; + uint8_t msg_parse_buf[ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_MAX_MSG_SIZE]; + +}; + diff --git a/selfdrive/locationd/ubloxd.cc b/selfdrive/locationd/ubloxd.cc index 5fdcebba0..445495a86 100644 --- a/selfdrive/locationd/ubloxd.cc +++ b/selfdrive/locationd/ubloxd.cc @@ -1,23 +1,66 @@ -#include +#include -#include "messaging.hpp" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/locationd/ublox_msg.h" -#include "ublox_msg.h" - -Message * poll_ubloxraw_msg(Poller * poller) { - auto p = poller->poll(1000); - - if (p.size()) { - return p[0]->receive(); - } else { - return NULL; - } -} - -int send_gps_event(PubSocket *s, const void *buf, size_t len) { - return s->send((char*)buf, len); -} +ExitHandler do_exit; +using namespace ublox; int main() { - return ubloxd_main(poll_ubloxraw_msg, send_gps_event); -} \ No newline at end of file + LOGW("starting ubloxd"); + AlignedBuffer aligned_buf; + UbloxMsgParser parser; + + PubMaster pm({"ubloxGnss", "gpsLocationExternal"}); + + Context * context = Context::create(); + SubSocket * subscriber = SubSocket::create(context, "ubloxRaw"); + assert(subscriber != NULL); + subscriber->setTimeout(100); + + + while (!do_exit) { + Message * msg = subscriber->receive(); + if (!msg){ + if (errno == EINTR) { + do_exit = true; + } + continue; + } + + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg)); + cereal::Event::Reader event = cmsg.getRoot(); + auto ubloxRaw = event.getUbloxRaw(); + + const uint8_t *data = ubloxRaw.begin(); + size_t len = ubloxRaw.size(); + size_t bytes_consumed = 0; + + while(bytes_consumed < len && !do_exit) { + size_t bytes_consumed_this_time = 0U; + if(parser.add_data(data + bytes_consumed, (uint32_t)(len - bytes_consumed), bytes_consumed_this_time)) { + + try { + auto msg = parser.gen_msg(); + if (msg.second.size() > 0) { + auto bytes = msg.second.asBytes(); + pm.send(msg.first.c_str(), bytes.begin(), bytes.size()); + } + } catch (const std::exception& e) { + LOGE("Error parsing ublox message %s", e.what()); + } + + parser.reset(); + } + bytes_consumed += bytes_consumed_this_time; + } + delete msg; + } + + delete subscriber; + delete context; + + return 0; +} diff --git a/selfdrive/locationd/ubloxd_main.cc b/selfdrive/locationd/ubloxd_main.cc deleted file mode 100644 index 7fd395434..000000000 --- a/selfdrive/locationd/ubloxd_main.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "messaging.hpp" -#include "common/util.h" -#include "common/params.h" -#include "common/swaglog.h" -#include "common/timing.h" - -#include "ublox_msg.h" - -ExitHandler do_exit; -using namespace ublox; -int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) { - LOGW("starting ubloxd"); - AlignedBuffer aligned_buf; - UbloxMsgParser parser; - - Context * context = Context::create(); - SubSocket * subscriber = SubSocket::create(context, "ubloxRaw"); - assert(subscriber != NULL); - subscriber->setTimeout(100); - - PubMaster pm({"ubloxGnss", "gpsLocationExternal"}); - - while (!do_exit) { - Message * msg = subscriber->receive(); - if (!msg){ - if (errno == EINTR) { - do_exit = true; - } - continue; - } - - capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg)); - cereal::Event::Reader event = cmsg.getRoot(); - auto ubloxRaw = event.getUbloxRaw(); - - const uint8_t *data = ubloxRaw.begin(); - size_t len = ubloxRaw.size(); - size_t bytes_consumed = 0; - while(bytes_consumed < len && !do_exit) { - size_t bytes_consumed_this_time = 0U; - if(parser.add_data(data + bytes_consumed, (uint32_t)(len - bytes_consumed), bytes_consumed_this_time)) { - // New message available - if(parser.msg_class() == CLASS_NAV) { - if(parser.msg_id() == MSG_NAV_PVT) { - //LOGD("MSG_NAV_PVT"); - auto words = parser.gen_solution(); - if(words.size() > 0) { - auto bytes = words.asBytes(); - pm.send("gpsLocationExternal", bytes.begin(), bytes.size()); - } - } else - LOGW("Unknown nav msg id: 0x%02X", parser.msg_id()); - } else if(parser.msg_class() == CLASS_RXM) { - if(parser.msg_id() == MSG_RXM_RAW) { - //LOGD("MSG_RXM_RAW"); - auto words = parser.gen_raw(); - if(words.size() > 0) { - auto bytes = words.asBytes(); - pm.send("ubloxGnss", bytes.begin(), bytes.size()); - } - } else if(parser.msg_id() == MSG_RXM_SFRBX) { - //LOGD("MSG_RXM_SFRBX"); - auto words = parser.gen_nav_data(); - if(words.size() > 0) { - auto bytes = words.asBytes(); - pm.send("ubloxGnss", bytes.begin(), bytes.size()); - } - } else - LOGW("Unknown rxm msg id: 0x%02X", parser.msg_id()); - } else if(parser.msg_class() == CLASS_MON) { - if(parser.msg_id() == MSG_MON_HW) { - //LOGD("MSG_MON_HW"); - auto words = parser.gen_mon_hw(); - if(words.size() > 0) { - auto bytes = words.asBytes(); - pm.send("ubloxGnss", bytes.begin(), bytes.size()); - } - } else if(parser.msg_id() == MSG_MON_HW2) { - //LOGD("MSG_MON_HW2"); - auto words = parser.gen_mon_hw2(); - if(words.size() > 0) { - auto bytes = words.asBytes(); - pm.send("ubloxGnss", bytes.begin(), bytes.size()); - } - } else { - LOGW("Unknown mon msg id: 0x%02X", parser.msg_id()); - } - } else - LOGW("Unknown msg class: 0x%02X", parser.msg_class()); - parser.reset(); - } - bytes_consumed += bytes_consumed_this_time; - } - delete msg; - } - - delete subscriber; - delete context; - - return 0; -} diff --git a/selfdrive/logcatd/logcatd_android.cc b/selfdrive/logcatd/logcatd_android.cc index 95a0c7b70..1a982a0fe 100644 --- a/selfdrive/logcatd/logcatd_android.cc +++ b/selfdrive/logcatd/logcatd_android.cc @@ -1,13 +1,17 @@ +#include +#include + #include #include #include -#include "common/util.h" -#include "messaging.hpp" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/util.h" int main() { - ExitHandler do_exit; + setpriority(PRIO_PROCESS, 0, -15); + ExitHandler do_exit; PubMaster pm({"androidLog"}); log_time last_log_time = {}; diff --git a/selfdrive/logcatd/logcatd_systemd.cc b/selfdrive/logcatd/logcatd_systemd.cc index da9b3bb88..61d6cb9b0 100644 --- a/selfdrive/logcatd/logcatd_systemd.cc +++ b/selfdrive/logcatd/logcatd_systemd.cc @@ -1,15 +1,16 @@ -#include -#include -#include -#include -#include - -#include "json11.hpp" #include -#include "common/timing.h" -#include "common/util.h" -#include "messaging.hpp" +#include +#include +#include +#include +#include + +#include "json11.hpp" + +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" ExitHandler do_exit; int main(int argc, char *argv[]) { diff --git a/selfdrive/loggerd/SConscript b/selfdrive/loggerd/SConscript index 1492d92f3..18325c7a4 100644 --- a/selfdrive/loggerd/SConscript +++ b/selfdrive/loggerd/SConscript @@ -2,9 +2,10 @@ Import('env', 'arch', 'cereal', 'messaging', 'common', 'visionipc', 'gpucommon') logger_lib = env.Library('logger', ["logger.cc"]) -libs = [logger_lib, 'zmq', 'capnp', 'kj', 'z', +libs = [logger_lib, common, cereal, messaging, visionipc, + 'zmq', 'capnp', 'kj', 'z', 'avformat', 'avcodec', 'swscale', 'avutil', - 'yuv', 'bz2', 'OpenCL', common, cereal, messaging, visionipc] + 'yuv', 'bz2', 'OpenCL'] src = ['loggerd.cc'] if arch in ["aarch64", "larch64"]: diff --git a/selfdrive/loggerd/bootlog.cc b/selfdrive/loggerd/bootlog.cc index 16ca95b27..e36012bd2 100644 --- a/selfdrive/loggerd/bootlog.cc +++ b/selfdrive/loggerd/bootlog.cc @@ -1,8 +1,10 @@ #include + #include -#include "common/swaglog.h" -#include "logger.h" -#include "messaging.hpp" + +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/loggerd/logger.h" static kj::Array build_boot_log() { MessageBuilder msg; @@ -10,11 +12,25 @@ static kj::Array build_boot_log() { boot.setWallTimeNanos(nanos_since_epoch()); - std::string lastKmsg = util::read_file("/sys/fs/pstore/console-ramoops"); - boot.setLastKmsg(capnp::Data::Reader((const kj::byte*)lastKmsg.data(), lastKmsg.size())); + std::string pstore = "/sys/fs/pstore"; + std::map pstore_map; + util::read_files_in_dir(pstore, &pstore_map); - std::string lastPmsg = util::read_file("/sys/fs/pstore/pmsg-ramoops-0"); - boot.setLastPmsg(capnp::Data::Reader((const kj::byte*)lastPmsg.data(), lastPmsg.size())); + const std::vector log_keywords = {"Kernel panic"}; + auto lpstore = boot.initPstore().initEntries(pstore_map.size()); + int i = 0; + for (auto& kv : pstore_map) { + auto lentry = lpstore[i]; + lentry.setKey(kv.first); + lentry.setValue(capnp::Data::Reader((const kj::byte*)kv.second.data(), kv.second.size())); + i++; + + for (auto &k : log_keywords) { + if (kv.second.find(k) != std::string::npos) { + LOGE("%s: found '%s'", kv.first.c_str(), k.c_str()); + } + } + } std::string launchLog = util::read_file("/tmp/launch_log"); boot.setLaunchLog(capnp::Text::Reader(launchLog.data(), launchLog.size())); diff --git a/selfdrive/loggerd/logger.cc b/selfdrive/loggerd/logger.cc index ca621810e..72bb4cb62 100644 --- a/selfdrive/loggerd/logger.cc +++ b/selfdrive/loggerd/logger.cc @@ -1,27 +1,27 @@ +#include "selfdrive/loggerd/logger.h" + +#include +#include +#include +#include #include #include -#include -#include #include -#include -#include -#include -#include #include +#include +#include -#include #include +#include #include #ifdef QCOM #include #endif -#include "common/swaglog.h" -#include "common/params.h" -#include "common/version.h" -#include "messaging.hpp" -#include "logger.h" - +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/version.h" // ***** logging helpers ***** @@ -53,9 +53,9 @@ kj::Array logger_build_init_data() { MessageBuilder msg; auto init = msg.initEvent().initInitData(); - if (util::file_exists("/EON")) { + if (Hardware::EON()) { init.setDeviceType(cereal::InitData::DeviceType::NEO); - } else if (util::file_exists("/TICI")) { + } else if (Hardware::TICI()) { init.setDeviceType(cereal::InitData::DeviceType::TICI); } else { init.setDeviceType(cereal::InitData::DeviceType::PC); @@ -91,10 +91,6 @@ kj::Array logger_build_init_data() { } #endif - const char* dongle_id = getenv("DONGLE_ID"); - if (dongle_id) { - init.setDongleId(std::string(dongle_id)); - } init.setDirty(!getenv("CLEAN")); // log params @@ -102,10 +98,11 @@ 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")); + init.setDongleId(params.get("DongleId")); { std::map params_map; - params.read_db_all(¶ms_map); + params.readAll(¶ms_map); auto lparams = init.initParams().initEntries(params_map.size()); int i = 0; for (auto& kv : params_map) { diff --git a/selfdrive/loggerd/logger.h b/selfdrive/loggerd/logger.h index 7e26a2246..f530a2b04 100644 --- a/selfdrive/loggerd/logger.h +++ b/selfdrive/loggerd/logger.h @@ -1,20 +1,22 @@ #pragma once -#include -#include #include +#include +#include + #include + #include -#include #include -#include "common/util.h" +#include -#if defined(QCOM) || defined(QCOM2) -const std::string LOG_ROOT = "/data/media/0/realdata"; -#else -const std::string LOG_ROOT = util::getenv_default("HOME", "/.comma/media/0/realdata", "/data/media/0/realdata"); -#endif +#include "selfdrive/common/util.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/hardware/hw.h" +const std::string LOG_ROOT = + Hardware::PC() ? util::getenv_default("HOME", "/.comma/media/0/realdata", "/data/media/0/realdata") + : "/data/media/0/realdata"; #define LOGGER_MAX_HANDLES 16 class BZFile { diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index c28657c6f..c55115402 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -1,57 +1,49 @@ -#include -#include -#include -#include -#include #include -#include +#include #include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include +#include "cereal/messaging/messaging.h" +#include "cereal/services.h" +#include "cereal/visionipc/visionipc.h" +#include "cereal/visionipc/visionipc_client.h" +#include "selfdrive/camerad/cameras/camera_common.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" -#include "common/timing.h" -#include "common/params.h" -#include "common/swaglog.h" -#include "common/util.h" -#include "camerad/cameras/camera_common.h" -#include "logger.h" -#include "messaging.hpp" -#include "services.h" - -#include "visionipc.h" -#include "visionipc_client.h" - -#include "encoder.h" +#include "selfdrive/loggerd/encoder.h" +#include "selfdrive/loggerd/logger.h" #if defined(QCOM) || defined(QCOM2) -#include "omx_encoder.h" +#include "selfdrive/loggerd/omx_encoder.h" #define Encoder OmxEncoder #else -#include "raw_logger.h" +#include "selfdrive/loggerd/raw_logger.h" #define Encoder RawLogger #endif namespace { constexpr int MAIN_FPS = 20; - -#ifndef QCOM2 -constexpr int MAIN_BITRATE = 5000000; -constexpr int MAX_CAM_IDX = LOG_CAMERA_ID_DCAMERA; -constexpr int DCAM_BITRATE = 2500000; -#else -constexpr int MAIN_BITRATE = 10000000; -constexpr int MAX_CAM_IDX = LOG_CAMERA_ID_ECAMERA; -constexpr int DCAM_BITRATE = MAIN_BITRATE; -#endif +const int MAIN_BITRATE = Hardware::TICI() ? 10000000 : 5000000; +const int MAX_CAM_IDX = Hardware::TICI() ? LOG_CAMERA_ID_ECAMERA : LOG_CAMERA_ID_DCAMERA; +const int DCAM_BITRATE = Hardware::TICI() ? MAIN_BITRATE : 2500000; #define NO_CAMERA_PATIENCE 500 // fall back to time-based rotation if all cameras are dead @@ -96,11 +88,8 @@ LogCameraInfo cameras_logged[LOG_CAMERA_ID_MAX] = { .bitrate = 256000, .is_h265 = false, .downscale = true, -#ifndef QCOM2 - .frame_width = 480, .frame_height = 360 -#else - .frame_width = 526, .frame_height = 330 // keep pixel count the same? -#endif + .frame_width = Hardware::TICI() ? 526 : 480, + .frame_height = Hardware::TICI() ? 330 : 360 // keep pixel count the same? }, }; @@ -279,17 +268,18 @@ void encoder_thread(int cam_idx) { eidx.setFrameId(extra.frame_id); eidx.setTimestampSof(extra.timestamp_sof); eidx.setTimestampEof(extra.timestamp_eof); - #ifdef QCOM2 - eidx.setType(cereal::EncodeIndex::Type::FULL_H_E_V_C); - #else - eidx.setType(cam_idx == LOG_CAMERA_ID_DCAMERA ? cereal::EncodeIndex::Type::FRONT : cereal::EncodeIndex::Type::FULL_H_E_V_C); - #endif + if (Hardware::TICI()) { + eidx.setType(cereal::EncodeIndex::Type::FULL_H_E_V_C); + } else { + eidx.setType(cam_idx == LOG_CAMERA_ID_DCAMERA ? cereal::EncodeIndex::Type::FRONT : cereal::EncodeIndex::Type::FULL_H_E_V_C); + } eidx.setEncodeId(cnt); eidx.setSegmentNum(rotate_state.cur_seg); eidx.setSegmentId(out_id); if (lh) { + // TODO: this should read cereal/services.h for qlog decimation auto bytes = msg.toBytes(); - lh_log(lh, bytes.begin(), bytes.size(), false); + lh_log(lh, bytes.begin(), bytes.size(), true); } } } @@ -325,8 +315,7 @@ void clear_locks() { } // namespace int main(int argc, char** argv) { - - setpriority(PRIO_PROCESS, 0, -12); + setpriority(PRIO_PROCESS, 0, -20); clear_locks(); @@ -368,18 +357,14 @@ int main(int argc, char** argv) { encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_FCAMERA)); s.rotate_state[LOG_CAMERA_ID_FCAMERA].enabled = true; -#if defined(QCOM) || defined(QCOM2) - bool record_front = Params().read_db_bool("RecordFront"); - if (record_front) { + if (!Hardware::PC() && Params().getBool("RecordFront")) { encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_DCAMERA)); s.rotate_state[LOG_CAMERA_ID_DCAMERA].enabled = true; } - -#ifdef QCOM2 - encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_ECAMERA)); - s.rotate_state[LOG_CAMERA_ID_ECAMERA].enabled = true; -#endif -#endif + if (Hardware::TICI()) { + encoder_threads.push_back(std::thread(encoder_thread, LOG_CAMERA_ID_ECAMERA)); + s.rotate_state[LOG_CAMERA_ID_ECAMERA].enabled = true; + } uint64_t msg_count = 0; uint64_t bytes_count = 0; @@ -453,9 +438,7 @@ int main(int argc, char** argv) { new_segment &= (((r.stream_frame_id >= r.last_rotate_frame_id + SEGMENT_LENGTH * MAIN_FPS) && (!r.should_rotate) && (r.initialized)) || (!r.enabled)); -#ifndef QCOM2 - break; // only look at fcamera frame id if not QCOM2 -#endif + if (!Hardware::TICI()) break; // only look at fcamera frame id if not QCOM2 } } else { if (tms - last_rotate_tms > SEGMENT_LENGTH * 1000) { diff --git a/selfdrive/loggerd/omx_encoder.cc b/selfdrive/loggerd/omx_encoder.cc index b629490f5..6891d47d5 100644 --- a/selfdrive/loggerd/omx_encoder.cc +++ b/selfdrive/loggerd/omx_encoder.cc @@ -1,25 +1,24 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#include "selfdrive/loggerd/omx_encoder.h" + +#include +#include +#include #include #include -#include -#include -#include #include -#include +#include #include #include -#include #include +#include +#include "libyuv.h" -#include -#include - -#include "common/util.h" -#include "common/swaglog.h" - -#include "omx_encoder.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/loggerd/include/msm_media_info.h" // Check the OMX error code and assert if an error occurred. #define OMX_CHECK(_expr) \ diff --git a/selfdrive/loggerd/omx_encoder.h b/selfdrive/loggerd/omx_encoder.h index 08bb30ec3..271ef113e 100644 --- a/selfdrive/loggerd/omx_encoder.h +++ b/selfdrive/loggerd/omx_encoder.h @@ -1,17 +1,18 @@ #pragma once -#include -#include #include -#include -#include +#include +#include +#include + +#include extern "C" { - #include +#include } -#include "encoder.h" -#include "common/queue.h" +#include "selfdrive/common/queue.h" +#include "selfdrive/loggerd/encoder.h" // OmxEncoder, lossey codec using hardware hevc class OmxEncoder : public VideoEncoder { diff --git a/selfdrive/loggerd/raw_logger.cc b/selfdrive/loggerd/raw_logger.cc index 2e8fd20a7..cd2799773 100644 --- a/selfdrive/loggerd/raw_logger.cc +++ b/selfdrive/loggerd/raw_logger.cc @@ -1,24 +1,24 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" -#include -#include -#include +#include "selfdrive/loggerd/raw_logger.h" #include #include +#include +#include +#include + #define __STDC_CONSTANT_MACROS extern "C" { -#include #include #include +#include } -#include "common/swaglog.h" -#include "common/util.h" - -#include "raw_logger.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" RawLogger::RawLogger(const char* filename, int width, int height, int fps, int bitrate, bool h265, bool downscale) diff --git a/selfdrive/loggerd/raw_logger.h b/selfdrive/loggerd/raw_logger.h index 5df6eabed..7955ef5e1 100644 --- a/selfdrive/loggerd/raw_logger.h +++ b/selfdrive/loggerd/raw_logger.h @@ -2,20 +2,19 @@ #include #include - #include #include extern "C" { -#include #include #include +#include } -#include "encoder.h" +#include "selfdrive/loggerd/encoder.h" class RawLogger : public VideoEncoder { -public: + public: RawLogger(const char* filename, int width, int height, int fps, int bitrate, bool h265, bool downscale); ~RawLogger(); diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index 4a8539dd3..86fdfaee9 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -192,14 +192,14 @@ class Uploader(): def uploader_fn(exit_event): params = Params() - dongle_id = params.get("DongleId").decode('utf8') + dongle_id = params.get("DongleId", encoding='utf8') if dongle_id is None: cloudlog.info("uploader missing dongle_id") raise Exception("uploader can't start without dongle id") if TICI and not Path("/data/media").is_mount(): - cloudlog.debug("NVME not mounted") + cloudlog.warning("NVME not mounted") sm = messaging.SubMaster(['deviceState']) uploader = Uploader(dongle_id, ROOT) @@ -207,7 +207,7 @@ def uploader_fn(exit_event): backoff = 0.1 while not exit_event.is_set(): sm.update(0) - offroad = params.get("IsOffroad") == b'1' + offroad = params.get_bool("IsOffroad") network_type = sm['deviceState'].networkType if not force_wifi else NetworkType.wifi if network_type == NetworkType.none: if allow_sleep: @@ -215,7 +215,7 @@ def uploader_fn(exit_event): continue on_wifi = network_type == NetworkType.wifi - allow_raw_upload = params.get("IsUploadRawEnabled") != b"0" + allow_raw_upload = params.get_bool("IsUploadRawEnabled") d = uploader.next_file_to_upload(with_raw=allow_raw_upload and on_wifi and offroad) if d is None: # Nothing to upload diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 393b51393..b568fee63 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -9,40 +9,39 @@ import traceback import cereal.messaging as messaging import selfdrive.crash as crash from common.basedir import BASEDIR -from common.params import Params +from common.params import Params, ParamKeyType from common.text_window import TextWindow -from selfdrive.hardware import HARDWARE +from selfdrive.boardd.set_time import set_time +from selfdrive.hardware import HARDWARE, PC, TICI from selfdrive.manager.helpers import unblock_stdout from selfdrive.manager.process import ensure_running from selfdrive.manager.process_config import managed_processes -from selfdrive.registration import register +from selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID from selfdrive.swaglog import cloudlog, add_file_handler -from selfdrive.version import dirty, version - +from selfdrive.version import dirty, get_git_commit, version, origin, branch, commit, \ + terms_version, training_version, comma_remote, \ + get_git_branch, get_git_remote def manager_init(): + + # update system time from panda + set_time(cloudlog) + params = Params() - params.manager_start() + params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) default_params = [ - ("CommunityFeaturesToggle", "0"), - ("EndToEndToggle", "0"), ("CompletedTrainingVersion", "0"), - ("IsRHD", "0"), - ("IsMetric", "0"), - ("RecordFront", "0"), ("HasAcceptedTerms", "0"), - ("HasCompletedSetup", "0"), - ("IsUploadRawEnabled", "1"), - ("IsLdwEnabled", "0"), ("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')), ("OpenpilotEnabledToggle", "1"), - ("VisionRadarToggle", "0"), - ("IsDriverViewEnabled", "0"), ] - if params.get("RecordFrontLock", encoding='utf-8') == "1": - params.put("RecordFront", "1") + if TICI: + default_params.append(("IsUploadRawEnabled", "1")) + + if params.get_bool("RecordFrontLock"): + params.put_bool("RecordFront", True) # set unset params for k, v in default_params: @@ -51,7 +50,7 @@ def manager_init(): # is this dashcam? if os.getenv("PASSIVE") is not None: - params.put("Passive", str(int(os.getenv("PASSIVE")))) + params.put_bool("Passive", bool(int(os.getenv("PASSIVE")))) if params.get("Passive") is None: raise Exception("Passive must be set to continue") @@ -66,21 +65,34 @@ def manager_init(): except PermissionError: print("WARNING: failed to make /dev/shm") + # set version params + params.put("Version", version) + params.put("TermsVersion", terms_version) + params.put("TrainingVersion", training_version) + params.put("GitCommit", get_git_commit(default="")) + params.put("GitBranch", get_git_branch(default="")) + params.put("GitRemote", get_git_remote(default="")) + # set dongle id reg_res = register(show_spinner=True) if reg_res: dongle_id = reg_res else: - raise Exception("server registration failed") - os.environ['DONGLE_ID'] = dongle_id # Needed for swaglog and loggerd + serial = params.get("HardwareSerial") + raise Exception(f"Registration failed for device {serial}") + os.environ['DONGLE_ID'] = dongle_id # Needed for swaglog if not dirty: os.environ['CLEAN'] = '1' cloudlog.bind_global(dongle_id=dongle_id, version=version, dirty=dirty, device=HARDWARE.get_device_type()) + + if comma_remote and not (os.getenv("NOLOG") or os.getenv("NOCRASH") or PC): + crash.init() crash.bind_user(id=dongle_id) - crash.bind_extra(version=version, dirty=dirty, device=HARDWARE.get_device_type()) + crash.bind_extra(dirty=dirty, origin=origin, branch=branch, commit=commit, + device=HARDWARE.get_device_type()) def manager_prepare(): @@ -102,7 +114,11 @@ def manager_thread(): # save boot log subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "selfdrive/loggerd")) + params = Params() + ignore = [] + if params.get("DongleId") == UNREGISTERED_DONGLE_ID: + ignore += ["manage_athenad", "uploader"] if os.getenv("NOBOARD") is not None: ignore.append("pandad") if os.getenv("BLOCK") is not None: @@ -111,7 +127,6 @@ def manager_thread(): ensure_running(managed_processes.values(), started=False, not_run=ignore) started_prev = False - params = Params() sm = messaging.SubMaster(['deviceState']) pm = messaging.PubMaster(['managerState']) @@ -123,7 +138,7 @@ def manager_thread(): not_run.append("loggerd") started = sm['deviceState'].started - driverview = params.get("IsDriverViewEnabled") == b"1" + driverview = params.get_bool("IsDriverViewEnabled") ensure_running(managed_processes.values(), started, driverview, not_run) # trigger an update after going offroad @@ -142,8 +157,9 @@ def manager_thread(): msg.managerState.processes = [p.get_process_state_msg() for p in managed_processes.values()] pm.send('managerState', msg) + # TODO: let UI handle this # Exit main loop when uninstall is needed - if params.get("DoUninstall", encoding='utf8') == "1": + if params.get_bool("DoUninstall"): break @@ -152,7 +168,7 @@ def main(): manager_init() - # Start ui early so prepare can happen in the background + # Start UI early so prepare can happen in the background if not prepare_only: managed_processes['ui'].start() @@ -172,7 +188,7 @@ def main(): finally: manager_cleanup() - if Params().get("DoUninstall", encoding='utf8') == "1": + if Params().get_bool("DoUninstall"): cloudlog.warning("uninstalling") HARDWARE.uninstall() diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index f0ae7da2b..b58f4dc2c 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -18,11 +18,11 @@ procs = [ NativeProcess("sensord", "selfdrive/sensord", ["./sensord"], enabled=not PC, persistent=EON, sigkill=EON), NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=(not PC or WEBCAM)), NativeProcess("ui", "selfdrive/ui", ["./ui"], persistent=True, watchdog_max_dt=(10 if TICI else None)), + NativeProcess("locationd", "selfdrive/locationd", ["./locationd"]), PythonProcess("calibrationd", "selfdrive.locationd.calibrationd"), PythonProcess("controlsd", "selfdrive.controls.controlsd"), PythonProcess("deleter", "selfdrive.loggerd.deleter", persistent=True), PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=(not PC or WEBCAM), driverview=True), - PythonProcess("locationd", "selfdrive.locationd.locationd"), PythonProcess("logmessaged", "selfdrive.logmessaged", persistent=True), PythonProcess("pandad", "selfdrive.pandad", persistent=True), PythonProcess("paramsd", "selfdrive.locationd.paramsd"), diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index e19311f0b..fd8934850 100644 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -13,7 +13,7 @@ os.environ['FAKEUPLOAD'] = "1" # TODO: make eon fast MAX_STARTUP_TIME = 30 if EON else 15 -ALL_PROCESSES = [p.name for p in managed_processes.values() if (type(p) is not DaemonProcess) and (p.name not in ['updated', 'pandad'])] +ALL_PROCESSES = [p.name for p in managed_processes.values() if (type(p) is not DaemonProcess) and p.enabled and (p.name not in ['updated', 'pandad'])] class TestManager(unittest.TestCase): @@ -45,9 +45,12 @@ class TestManager(unittest.TestCase): time.sleep(30) for p in reversed(ALL_PROCESSES): + state = managed_processes[p].get_process_state_msg() + self.assertTrue(state.running, f"{p} not running") + exit_code = managed_processes[p].stop(retry=False) - if (not EON and p == 'ui') or (EON and p == 'logcatd'): - # TODO: make Qt UI exit gracefully and fix OMX encoder exiting + if (p == 'ui') or (EON and p == 'logcatd'): + # TODO: make Qt UI exit gracefully continue # Make sure the process is actually dead diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 44a2fc7f2..19c57f1dd 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -1,7 +1,8 @@ Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc') lenv = env.Clone() -libs = [cereal, messaging, common, 'OpenCL', 'SNPE', 'symphony-cpu', 'capnp', 'zmq', 'kj', 'yuv', gpucommon, visionipc] +libs = [cereal, messaging, common, visionipc, gpucommon, + 'OpenCL', 'SNPE', 'symphony-cpu', 'capnp', 'zmq', 'kj', 'yuv'] def get_dlsym_offset(): """Returns the offset between dlopen and dlsym in libdl.so""" diff --git a/selfdrive/modeld/dmonitoringmodeld.cc b/selfdrive/modeld/dmonitoringmodeld.cc index b21bbd784..85b412609 100644 --- a/selfdrive/modeld/dmonitoringmodeld.cc +++ b/selfdrive/modeld/dmonitoringmodeld.cc @@ -1,16 +1,12 @@ #include #include #include +#include -#include "visionipc_client.h" -#include "common/swaglog.h" -#include "common/util.h" - -#include "models/dmonitoring.h" - -#ifndef PATH_MAX -#include -#endif +#include "cereal/visionipc/visionipc_client.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/modeld/models/dmonitoring.h" ExitHandler do_exit; diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 4eb64cfd4..0cfed4acd 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -1,15 +1,18 @@ #include #include + #include + #include -#include "visionipc_client.h" -#include "common/swaglog.h" -#include "common/clutil.h" -#include "common/util.h" - -#include "models/driving.h" -#include "messaging.hpp" +#include "cereal/messaging/messaging.h" +#include "cereal/visionipc/visionipc_client.h" +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/modeld/models/driving.h" ExitHandler do_exit; // globals @@ -17,7 +20,7 @@ bool live_calib_seen; mat3 cur_transform; std::mutex transform_lock; -void calibration_thread() { +void calibration_thread(bool wide_camera) { set_thread_name("calibration"); set_realtime_priority(50); @@ -35,19 +38,19 @@ void calibration_thread() { -1.09890110e-03, 0.00000000e+00, 2.81318681e-01, -1.84808520e-20, 9.00738606e-04,-4.28751576e-02; - Eigen::Matrix fcam_intrinsics = Eigen::Matrix(fcam_intrinsic_matrix.v); + Eigen::Matrix cam_intrinsics = Eigen::Matrix(wide_camera ? ecam_intrinsic_matrix.v : fcam_intrinsic_matrix.v); const mat3 yuv_transform = get_model_yuv_transform(); while (!do_exit) { - if (sm.update(100) > 0){ - + sm.update(100); + if(sm.updated("liveCalibration")){ auto extrinsic_matrix = sm["liveCalibration"].getLiveCalibration().getExtrinsicMatrix(); Eigen::Matrix extrinsic_matrix_eigen; for (int i = 0; i < 4*3; i++){ extrinsic_matrix_eigen(i / 4, i % 4) = extrinsic_matrix[i]; } - auto camera_frame_from_road_frame = fcam_intrinsics * extrinsic_matrix_eigen; + auto camera_frame_from_road_frame = cam_intrinsics * extrinsic_matrix_eigen; Eigen::Matrix camera_frame_from_ground; camera_frame_from_ground.col(0) = camera_frame_from_road_frame.col(0); camera_frame_from_ground.col(1) = camera_frame_from_road_frame.col(1); @@ -72,10 +75,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; @@ -92,11 +92,10 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client) { const bool run_model_this_iter = live_calib_seen; transform_lock.unlock(); - if (sm.update(0) > 0) { - // TODO: path planner timeout? - desire = ((int)sm["lateralPlan"].getLateralPlan().getDesire()); - frame_id = sm["roadCameraState"].getRoadCameraState().getFrameId(); - } + // TODO: path planner timeout? + sm.update(0); + desire = ((int)sm["lateralPlan"].getLateralPlan().getDesire()); + frame_id = sm["roadCameraState"].getRoadCameraState().getFrameId(); if (run_model_this_iter) { run_count++; @@ -114,8 +113,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, @@ -132,15 +135,15 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client) { int main(int argc, char **argv) { set_realtime_priority(54); -#ifdef QCOM - set_core_affinity(2); -#elif QCOM2 - // CPU usage is much lower when pinned to a single big core - set_core_affinity(4); -#endif + if (Hardware::EON()) { + set_core_affinity(2); + } else if (Hardware::TICI()) { + set_core_affinity(7); + } + bool wide_camera = Hardware::TICI() ? Params().getBool("EnableWideCamera") : false; // start calibration thread - std::thread thread = std::thread(calibration_thread); + std::thread thread = std::thread(calibration_thread, wide_camera); // cl init cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); @@ -151,7 +154,7 @@ int main(int argc, char **argv) { model_init(&model, device_id, context); LOGW("models loaded, modeld starting"); - VisionIpcClient vipc_client = VisionIpcClient("camerad", VISION_STREAM_YUV_BACK, true, device_id, context); + VisionIpcClient vipc_client = VisionIpcClient("camerad", wide_camera ? VISION_STREAM_YUV_WIDE : VISION_STREAM_YUV_BACK, true, device_id, context); while (!do_exit && !vipc_client.connect(false)) { util::sleep_for(100); } diff --git a/selfdrive/modeld/models/commonmodel.cc b/selfdrive/modeld/models/commonmodel.cc index 4ce255806..495bfe782 100644 --- a/selfdrive/modeld/models/commonmodel.cc +++ b/selfdrive/modeld/models/commonmodel.cc @@ -1,10 +1,13 @@ +#include "commonmodel.h" + #include #include + #include -#include "commonmodel.h" -#include "common/clutil.h" -#include "common/mat.h" -#include "common/timing.h" + +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/mat.h" +#include "selfdrive/common/timing.h" void frame_init(ModelFrame* frame, int width, int height, cl_device_id device_id, cl_context context) { diff --git a/selfdrive/modeld/models/commonmodel.h b/selfdrive/modeld/models/commonmodel.h index 05bb3e464..281930be6 100644 --- a/selfdrive/modeld/models/commonmodel.h +++ b/selfdrive/modeld/models/commonmodel.h @@ -1,4 +1,8 @@ #pragma once + +#include +#include + #define CL_USE_DEPRECATED_OPENCL_1_2_APIS #ifdef __APPLE__ #include @@ -6,11 +10,9 @@ #include #endif -#include -#include -#include "common/mat.h" -#include "transforms/transform.h" -#include "transforms/loadyuv.h" +#include "selfdrive/common/mat.h" +#include "selfdrive/modeld/transforms/loadyuv.h" +#include "selfdrive/modeld/transforms/transform.h" const bool send_raw_pred = getenv("SEND_RAW_PRED") != NULL; diff --git a/selfdrive/modeld/models/dmonitoring.cc b/selfdrive/modeld/models/dmonitoring.cc index 33900579f..9a1b8723a 100644 --- a/selfdrive/modeld/models/dmonitoring.cc +++ b/selfdrive/modeld/models/dmonitoring.cc @@ -1,10 +1,12 @@ #include -#include "dmonitoring.h" -#include "common/mat.h" -#include "common/timing.h" -#include "common/params.h" -#include +#include "libyuv.h" + +#include "selfdrive/common/mat.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/modeld/models/dmonitoring.h" #define MODEL_WIDTH 320 #define MODEL_HEIGHT 640 @@ -17,15 +19,10 @@ #endif void dmonitoring_init(DMonitoringModelState* s) { -#if defined(QCOM) || defined(QCOM2) - const char* model_path = "../../models/dmonitoring_model_q.dlc"; -#else - const char* model_path = "../../models/dmonitoring_model.dlc"; -#endif - + const char *model_path = "../../models/dmonitoring_model_q.dlc"; 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 @@ -41,70 +38,69 @@ static inline auto get_yuv_buf(std::vector &buf, const int width, int h return std::make_tuple(y, u, v); } +struct Rect {int x, y, w, h;}; +void crop_yuv(uint8_t *raw, int width, int height, uint8_t *y, uint8_t *u, uint8_t *v, const Rect &rect) { + uint8_t *raw_y = raw; + uint8_t *raw_u = raw_y + (width * height); + uint8_t *raw_v = raw_u + ((width / 2) * (height / 2)); + for (int r = 0; r < rect.h / 2; r++) { + memcpy(y + 2 * r * rect.w, raw_y + (2 * r + rect.y) * width + rect.x, rect.w); + memcpy(y + (2 * r + 1) * rect.w, raw_y + (2 * r + rect.y + 1) * width + rect.x, rect.w); + memcpy(u + r * (rect.w / 2), raw_u + (r + (rect.y / 2)) * width / 2 + (rect.x / 2), rect.w / 2); + memcpy(v + r * (rect.w / 2), raw_v + (r + (rect.y / 2)) * width / 2 + (rect.x / 2), rect.w / 2); + } +} + DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_buf, int width, int height) { - uint8_t *raw_buf = (uint8_t*) stream_buf; - uint8_t *raw_y_buf = raw_buf; - uint8_t *raw_u_buf = raw_y_buf + (width * height); - uint8_t *raw_v_buf = raw_u_buf + ((width/2) * (height/2)); + Rect crop_rect; + if (Hardware::TICI()) { + const int full_width_tici = 1928; + const int full_height_tici = 1208; + const int adapt_width_tici = 668; + const int cropped_height = adapt_width_tici / 1.33; + crop_rect = {full_width_tici / 2 - adapt_width_tici / 2, + full_height_tici / 2 - cropped_height / 2 - 196, + cropped_height / 2, + cropped_height}; + if (!s->is_rhd) { + crop_rect.x += adapt_width_tici - crop_rect.w + 32; + } -#ifndef QCOM2 - const int cropped_width = height/2; - const int cropped_height = height; - const int global_x_offset = 0; - const int global_y_offset = 0; - const int crop_x_offset = width - cropped_width; - const int crop_y_offset = 0; -#else - const int full_width_tici = 1928; - const int full_height_tici = 1208; - const int adapt_width_tici = 668; - - const int cropped_height = adapt_width_tici / 1.33; - const int cropped_width = cropped_height / 2; - const int global_x_offset = full_width_tici / 2 - adapt_width_tici / 2; - const int global_y_offset = full_height_tici / 2 - cropped_height / 2; - const int crop_x_offset = adapt_width_tici - cropped_width + 32; - const int crop_y_offset = -196; -#endif + } else { + crop_rect = {0, 0, height / 2, height}; + if (!s->is_rhd) { + crop_rect.x += width - crop_rect.w; + } + } int resized_width = MODEL_WIDTH; int resized_height = MODEL_HEIGHT; - auto [cropped_y_buf, cropped_u_buf, cropped_v_buf] = get_yuv_buf(s->cropped_buf, cropped_width, cropped_height); + auto [cropped_y, cropped_u, cropped_v] = get_yuv_buf(s->cropped_buf, crop_rect.w, crop_rect.h); if (!s->is_rhd) { - for (int r = 0; r < cropped_height/2; r++) { - memcpy(cropped_y_buf + 2*r*cropped_width, raw_y_buf + (2*r + global_y_offset + crop_y_offset)*width + global_x_offset + crop_x_offset, cropped_width); - memcpy(cropped_y_buf + (2*r+1)*cropped_width, raw_y_buf + (2*r + global_y_offset + crop_y_offset + 1)*width + global_x_offset + crop_x_offset, cropped_width); - memcpy(cropped_u_buf + r*(cropped_width/2), raw_u_buf + (r + (global_y_offset + crop_y_offset)/2)*width/2 + (global_x_offset + crop_x_offset)/2, cropped_width/2); - memcpy(cropped_v_buf + r*(cropped_width/2), raw_v_buf + (r + (global_y_offset + crop_y_offset)/2)*width/2 + (global_x_offset + crop_x_offset)/2, cropped_width/2); - } + crop_yuv((uint8_t *)stream_buf, width, height, cropped_y, cropped_u, cropped_v, crop_rect); } else { - auto [premirror_cropped_y_buf, premirror_cropped_u_buf, premirror_cropped_v_buf] = get_yuv_buf(s->premirror_cropped_buf, cropped_width, cropped_height); - for (int r = 0; r < cropped_height/2; r++) { - memcpy(premirror_cropped_y_buf + (2*r)*cropped_width, raw_y_buf + (2*r + global_y_offset + crop_y_offset)*width + global_x_offset, cropped_width); - memcpy(premirror_cropped_y_buf + (2*r+1)*cropped_width, raw_y_buf + (2*r + global_y_offset + crop_y_offset + 1)*width + global_x_offset, cropped_width); - memcpy(premirror_cropped_u_buf + r*(cropped_width/2), raw_u_buf + (r + (global_y_offset + crop_y_offset)/2)*width/2 + global_x_offset/2, cropped_width/2); - memcpy(premirror_cropped_v_buf + r*(cropped_width/2), raw_v_buf + (r + (global_y_offset + crop_y_offset)/2)*width/2 + global_x_offset/2, cropped_width/2); - } - libyuv::I420Mirror(premirror_cropped_y_buf, cropped_width, - premirror_cropped_u_buf, cropped_width/2, - premirror_cropped_v_buf, cropped_width/2, - cropped_y_buf, cropped_width, - cropped_u_buf, cropped_width/2, - cropped_v_buf, cropped_width/2, - cropped_width, cropped_height); + auto [mirror_y, mirror_u, mirror_v] = get_yuv_buf(s->premirror_cropped_buf, crop_rect.w, crop_rect.h); + crop_yuv((uint8_t *)stream_buf, width, height, mirror_y, mirror_u, mirror_v, crop_rect); + libyuv::I420Mirror(mirror_y, crop_rect.w, + mirror_u, crop_rect.w / 2, + mirror_v, crop_rect.w / 2, + cropped_y, crop_rect.w, + cropped_u, crop_rect.w / 2, + cropped_v, crop_rect.w / 2, + crop_rect.w, crop_rect.h); } - auto [resized_buf, resized_u_buf, resized_v_buf] = get_yuv_buf(s->resized_buf, resized_width, resized_height); - uint8_t *resized_y_buf = resized_buf; + auto [resized_buf, resized_u, resized_v] = get_yuv_buf(s->resized_buf, resized_width, resized_height); + uint8_t *resized_y = resized_buf; libyuv::FilterMode mode = libyuv::FilterModeEnum::kFilterBilinear; - libyuv::I420Scale(cropped_y_buf, cropped_width, - cropped_u_buf, cropped_width/2, - cropped_v_buf, cropped_width/2, - cropped_width, cropped_height, - resized_y_buf, resized_width, - resized_u_buf, resized_width/2, - resized_v_buf, resized_width/2, + libyuv::I420Scale(cropped_y, crop_rect.w, + cropped_u, crop_rect.w / 2, + cropped_v, crop_rect.w / 2, + crop_rect.w, crop_rect.h, + resized_y, resized_width, + resized_u, resized_width / 2, + resized_v, resized_width / 2, resized_width, resized_height, mode); diff --git a/selfdrive/modeld/models/dmonitoring.h b/selfdrive/modeld/models/dmonitoring.h index dd015d409..2a134b7b6 100644 --- a/selfdrive/modeld/models/dmonitoring.h +++ b/selfdrive/modeld/models/dmonitoring.h @@ -1,9 +1,11 @@ #pragma once + #include -#include "common/util.h" -#include "commonmodel.h" -#include "runners/run.h" -#include "messaging.hpp" + +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/util.h" +#include "selfdrive/modeld/models/commonmodel.h" +#include "selfdrive/modeld/runners/run.h" #define OUTPUT_SIZE 38 diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 767bc2fe1..a54fd4788 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -1,14 +1,16 @@ -#include +#include "driving.h" + #include #include +#include #include + #include -#include "common/timing.h" -#include "common/params.h" -#include "driving.h" -#include "clutil.h" +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/timing.h" constexpr int DESIRE_PRED_SIZE = 32; constexpr int OTHER_META_SIZE = 4; @@ -70,7 +72,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 @@ -180,40 +182,39 @@ void fill_meta(cereal::ModelDataV2::MetaData::Builder meta, const float *meta_da } void fill_xyzt(cereal::ModelDataV2::XYZTData::Builder xyzt, const float * data, - int columns, int column_offset, float * plan_t_arr) { + int columns, int column_offset, float * plan_t_arr, bool fill_std) { float x_arr[TRAJECTORY_SIZE] = {}; float y_arr[TRAJECTORY_SIZE] = {}; float z_arr[TRAJECTORY_SIZE] = {}; - //float x_std_arr[TRAJECTORY_SIZE]; - //float y_std_arr[TRAJECTORY_SIZE]; - //float z_std_arr[TRAJECTORY_SIZE]; + float x_std_arr[TRAJECTORY_SIZE]; + float y_std_arr[TRAJECTORY_SIZE]; + float z_std_arr[TRAJECTORY_SIZE]; float t_arr[TRAJECTORY_SIZE]; for (int i=0; i= 0) { t_arr[i] = T_IDXS[i]; x_arr[i] = data[i*columns + 0 + column_offset]; - //x_std_arr[i] = data[columns*(TRAJECTORY_SIZE + i) + 0 + column_offset]; + x_std_arr[i] = data[columns*(TRAJECTORY_SIZE + i) + 0 + column_offset]; } else { t_arr[i] = plan_t_arr[i]; x_arr[i] = X_IDXS[i]; - //x_std_arr[i] = NAN; + x_std_arr[i] = NAN; } y_arr[i] = data[i*columns + 1 + column_offset]; - //y_std_arr[i] = data[columns*(TRAJECTORY_SIZE + i) + 1 + column_offset]; + y_std_arr[i] = data[columns*(TRAJECTORY_SIZE + i) + 1 + column_offset]; z_arr[i] = data[i*columns + 2 + column_offset]; - //z_std_arr[i] = data[columns*(TRAJECTORY_SIZE + i) + 2 + column_offset]; + z_std_arr[i] = data[columns*(TRAJECTORY_SIZE + i) + 2 + column_offset]; } - //kj::ArrayPtr x_std(x_std_arr, TRAJECTORY_SIZE); - //kj::ArrayPtr y_std(y_std_arr, TRAJECTORY_SIZE); - //kj::ArrayPtr z_std(z_std_arr, TRAJECTORY_SIZE); xyzt.setX(x_arr); xyzt.setY(y_arr); xyzt.setZ(z_arr); - //xyzt.setXStd(x_std); - //xyzt.setYStd(y_std); - //xyzt.setZStd(z_std); xyzt.setT(t_arr); + if (fill_std) { + xyzt.setXStd(x_std_arr); + xyzt.setYStd(y_std_arr); + xyzt.setZStd(z_std_arr); + } } void fill_model(cereal::ModelDataV2::Builder &framed, const ModelDataRaw &net_outputs) { @@ -224,17 +225,17 @@ void fill_model(cereal::ModelDataV2::Builder &framed, const ModelDataRaw &net_ou plan_t_arr[i] = best_plan[i*PLAN_MHP_COLUMNS + 15]; } - fill_xyzt(framed.initPosition(), best_plan, PLAN_MHP_COLUMNS, 0, plan_t_arr); - fill_xyzt(framed.initVelocity(), best_plan, PLAN_MHP_COLUMNS, 3, plan_t_arr); - fill_xyzt(framed.initOrientation(), best_plan, PLAN_MHP_COLUMNS, 9, plan_t_arr); - fill_xyzt(framed.initOrientationRate(), best_plan, PLAN_MHP_COLUMNS, 12, plan_t_arr); + fill_xyzt(framed.initPosition(), best_plan, PLAN_MHP_COLUMNS, 0, plan_t_arr, true); + fill_xyzt(framed.initVelocity(), best_plan, PLAN_MHP_COLUMNS, 3, plan_t_arr, false); + fill_xyzt(framed.initOrientation(), best_plan, PLAN_MHP_COLUMNS, 9, plan_t_arr, false); + fill_xyzt(framed.initOrientationRate(), best_plan, PLAN_MHP_COLUMNS, 12, plan_t_arr, false); // lane lines auto lane_lines = framed.initLaneLines(4); float lane_line_probs_arr[4]; float lane_line_stds_arr[4]; for (int i = 0; i < 4; i++) { - fill_xyzt(lane_lines[i], &net_outputs.lane_lines[i*TRAJECTORY_SIZE*2], 2, -1, plan_t_arr); + fill_xyzt(lane_lines[i], &net_outputs.lane_lines[i*TRAJECTORY_SIZE*2], 2, -1, plan_t_arr, false); lane_line_probs_arr[i] = sigmoid(net_outputs.lane_lines_prob[i]); lane_line_stds_arr[i] = exp(net_outputs.lane_lines[2*TRAJECTORY_SIZE*(4 + i)]); } @@ -245,7 +246,7 @@ void fill_model(cereal::ModelDataV2::Builder &framed, const ModelDataRaw &net_ou auto road_edges = framed.initRoadEdges(2); float road_edge_stds_arr[2]; for (int i = 0; i < 2; i++) { - fill_xyzt(road_edges[i], &net_outputs.road_edges[i*TRAJECTORY_SIZE*2], 2, -1, plan_t_arr); + fill_xyzt(road_edges[i], &net_outputs.road_edges[i*TRAJECTORY_SIZE*2], 2, -1, plan_t_arr, false); road_edge_stds_arr[i] = exp(net_outputs.road_edges[2*TRAJECTORY_SIZE*(2 + i)]); } framed.setRoadEdgeStds(road_edge_stds_arr); diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index 7b0c21390..d523f47c7 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -5,15 +5,14 @@ #define DESIRE #define TRAFFIC_CONVENTION -#include "common/mat.h" -#include "common/util.h" -#include "common/modeldata.h" - -#include "commonmodel.h" -#include "runners/run.h" - #include -#include "messaging.hpp" + +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/mat.h" +#include "selfdrive/common/modeldata.h" +#include "selfdrive/common/util.h" +#include "selfdrive/modeld/models/commonmodel.h" +#include "selfdrive/modeld/runners/run.h" constexpr int DESIRE_LEN = 8; constexpr int TRAFFIC_CONVENTION_LEN = 2; diff --git a/selfdrive/modeld/runners/run.h b/selfdrive/modeld/runners/run.h index 98a3fb8b6..3051dfb03 100644 --- a/selfdrive/modeld/runners/run.h +++ b/selfdrive/modeld/runners/run.h @@ -4,13 +4,13 @@ #include "snpemodel.h" #if defined(QCOM) || defined(QCOM2) - #include "thneedmodel.h" - #define DefaultRunModel SNPEModel +#include "thneedmodel.h" +#define DefaultRunModel SNPEModel #else - #ifdef USE_ONNX_MODEL - #include "onnxmodel.h" - #define DefaultRunModel ONNXModel - #else - #define DefaultRunModel SNPEModel - #endif +#ifdef USE_ONNX_MODEL +#include "onnxmodel.h" +#define DefaultRunModel ONNXModel +#else +#define DefaultRunModel SNPEModel +#endif #endif diff --git a/selfdrive/modeld/runners/runmodel.h b/selfdrive/modeld/runners/runmodel.h index d3889aaaa..9eb7e1ea6 100644 --- a/selfdrive/modeld/runners/runmodel.h +++ b/selfdrive/modeld/runners/runmodel.h @@ -1,6 +1,4 @@ -#ifndef RUNMODEL_H -#define RUNMODEL_H - +#pragma once class RunModel { public: virtual void addRecurrent(float *state, int state_size) {} @@ -9,5 +7,3 @@ public: virtual void execute(float *net_input_buf, int buf_size) {} }; -#endif - diff --git a/selfdrive/modeld/runners/snpemodel.cc b/selfdrive/modeld/runners/snpemodel.cc index 538c24656..9f26ad27f 100644 --- a/selfdrive/modeld/runners/snpemodel.cc +++ b/selfdrive/modeld/runners/snpemodel.cc @@ -1,10 +1,13 @@ #pragma clang diagnostic ignored "-Wexceptions" -#include -#include +#include "selfdrive/modeld/runners/snpemodel.h" + #include -#include "common/util.h" -#include "snpemodel.h" +#include + +#include + +#include "selfdrive/common/util.h" void PrintErrorStringAndExit() { std::cerr << zdl::DlSystem::getLastErrorString() << std::endl; @@ -24,14 +27,13 @@ SNPEModel::SNPEModel(const char *path, float *loutput, size_t loutput_size, int } assert(zdl::SNPE::SNPEFactory::isRuntimeAvailable(Runtime)); #endif - size_t model_size; - model_data = (uint8_t *)read_file(path, &model_size); - assert(model_data); + model_data = util::read_file(path); + assert(model_data.size() > 0); // load model - std::unique_ptr container = zdl::DlContainer::IDlContainer::open(model_data, model_size); + std::unique_ptr container = zdl::DlContainer::IDlContainer::open((uint8_t*)model_data.data(), model_data.size()); if (!container) { PrintErrorStringAndExit(); } - printf("loaded model with size: %lu\n", model_size); + printf("loaded model with size: %lu\n", model_data.size()); // create model runner zdl::SNPE::SNPEBuilder snpeBuilder(container.get()); diff --git a/selfdrive/modeld/runners/snpemodel.h b/selfdrive/modeld/runners/snpemodel.h index 76339642f..6d3a70414 100644 --- a/selfdrive/modeld/runners/snpemodel.h +++ b/selfdrive/modeld/runners/snpemodel.h @@ -1,15 +1,14 @@ -#ifndef SNPEMODEL_H -#define SNPEMODEL_H +#pragma once -#include -#include -#include #include #include #include #include #include #include +#include +#include +#include #include "runmodel.h" @@ -18,15 +17,12 @@ #define USE_DSP_RUNTIME 2 #ifdef USE_THNEED -#include "thneed/thneed.h" +#include "selfdrive/modeld/thneed/thneed.h" #endif class SNPEModel : public RunModel { public: SNPEModel(const char *path, float *loutput, size_t loutput_size, int runtime); - ~SNPEModel() { - if (model_data) free(model_data); - } void addRecurrent(float *state, int state_size); void addTrafficConvention(float *state, int state_size); void addDesire(float *state, int state_size); @@ -37,7 +33,7 @@ public: #endif private: - uint8_t *model_data = NULL; + std::string model_data; #if defined(QCOM) || defined(QCOM2) zdl::DlSystem::Runtime_t Runtime; @@ -66,6 +62,3 @@ private: float *desire; std::unique_ptr desireBuffer; }; - -#endif - diff --git a/selfdrive/modeld/runners/thneedmodel.cc b/selfdrive/modeld/runners/thneedmodel.cc index 0ebe7226e..c83a58b02 100644 --- a/selfdrive/modeld/runners/thneedmodel.cc +++ b/selfdrive/modeld/runners/thneedmodel.cc @@ -1,4 +1,5 @@ #include "thneedmodel.h" + #include ThneedModel::ThneedModel(const char *path, float *loutput, size_t loutput_size, int runtime) { diff --git a/selfdrive/modeld/runners/thneedmodel.h b/selfdrive/modeld/runners/thneedmodel.h index 05cb2438e..933c751d9 100644 --- a/selfdrive/modeld/runners/thneedmodel.h +++ b/selfdrive/modeld/runners/thneedmodel.h @@ -1,7 +1,7 @@ #pragma once -#include "runmodel.h" -#include "thneed/thneed.h" +#include "selfdrive/modeld/runners/runmodel.h" +#include "selfdrive/modeld/thneed/thneed.h" class ThneedModel : public RunModel { public: diff --git a/selfdrive/modeld/thneed/compile.cc b/selfdrive/modeld/thneed/compile.cc index 63955a6f9..cf15e9ceb 100644 --- a/selfdrive/modeld/thneed/compile.cc +++ b/selfdrive/modeld/thneed/compile.cc @@ -1,6 +1,7 @@ #include -#include "thneed.h" -#include "../runners/snpemodel.h" + +#include "selfdrive/modeld/runners/snpemodel.h" +#include "selfdrive/modeld/thneed/thneed.h" #define TEMPORAL_SIZE 512 #define DESIRE_LEN 8 diff --git a/selfdrive/modeld/thneed/serialize.cc b/selfdrive/modeld/thneed/serialize.cc index 7f22d631f..e3aa099d1 100644 --- a/selfdrive/modeld/thneed/serialize.cc +++ b/selfdrive/modeld/thneed/serialize.cc @@ -1,7 +1,9 @@ -#include #include -#include "thneed.h" + +#include + #include "json11.hpp" +#include "selfdrive/modeld/thneed/thneed.h" using namespace json11; extern map g_program_source; diff --git a/selfdrive/modeld/thneed/thneed.cc b/selfdrive/modeld/thneed/thneed.cc index e11fcb8a9..3b0138a14 100644 --- a/selfdrive/modeld/thneed/thneed.cc +++ b/selfdrive/modeld/thneed/thneed.cc @@ -1,13 +1,16 @@ -#include -#include +#include "selfdrive/modeld/thneed/thneed.h" + #include +#include +#include +#include + +#include #include #include -#include -#include -#include "common/timing.h" -#include "common/clutil.h" -#include "thneed.h" + +#include "selfdrive/common/clutil.h" +#include "selfdrive/common/timing.h" //#define RUN_DISASSEMBLER //#define RUN_OPTIMIZER diff --git a/selfdrive/modeld/thneed/thneed.h b/selfdrive/modeld/thneed/thneed.h index c36aaff70..eaea22e41 100644 --- a/selfdrive/modeld/thneed/thneed.h +++ b/selfdrive/modeld/thneed/thneed.h @@ -1,16 +1,18 @@ #pragma once #ifndef __user - #define __user __attribute__(()) +#define __user __attribute__(()) #endif -#include +#include #include -#include "include/msm_kgsl.h" -#include +#include + #include #include -#include +#include + +#include "selfdrive/modeld/thneed/include/msm_kgsl.h" #define THNEED_RECORD 1 #define THNEED_DEBUG 2 diff --git a/selfdrive/modeld/transforms/loadyuv.cc b/selfdrive/modeld/transforms/loadyuv.cc index fe84e6d27..d3686a667 100644 --- a/selfdrive/modeld/transforms/loadyuv.cc +++ b/selfdrive/modeld/transforms/loadyuv.cc @@ -1,7 +1,8 @@ -#include -#include #include "loadyuv.h" +#include +#include + void loadyuv_init(LoadYUVState* s, cl_context ctx, cl_device_id device_id, int width, int height) { memset(s, 0, sizeof(*s)); diff --git a/selfdrive/modeld/transforms/loadyuv.h b/selfdrive/modeld/transforms/loadyuv.h index dbef46149..0153815cc 100644 --- a/selfdrive/modeld/transforms/loadyuv.h +++ b/selfdrive/modeld/transforms/loadyuv.h @@ -2,7 +2,8 @@ #include #include -#include "clutil.h" + +#include "selfdrive/common/clutil.h" typedef struct { int width, height; diff --git a/selfdrive/modeld/transforms/transform.cc b/selfdrive/modeld/transforms/transform.cc index 056267aca..6cf48220a 100644 --- a/selfdrive/modeld/transforms/transform.cc +++ b/selfdrive/modeld/transforms/transform.cc @@ -1,10 +1,10 @@ -#include -#include - -#include "clutil.h" - #include "transform.h" +#include +#include + +#include "selfdrive/common/clutil.h" + void transform_init(Transform* s, cl_context ctx, cl_device_id device_id) { memset(s, 0, sizeof(*s)); diff --git a/selfdrive/modeld/transforms/transform.h b/selfdrive/modeld/transforms/transform.h index 3bce6f8a7..f46096bb0 100644 --- a/selfdrive/modeld/transforms/transform.h +++ b/selfdrive/modeld/transforms/transform.h @@ -10,7 +10,7 @@ #include #endif -#include "common/mat.h" +#include "selfdrive/common/mat.h" typedef struct { cl_kernel krnl; diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py index 83313b820..8321d3734 100755 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -14,7 +14,7 @@ def dmonitoringd_thread(sm=None, pm=None): if sm is None: sm = messaging.SubMaster(['driverState', 'liveCalibration', 'carState', 'controlsState', 'modelV2'], poll=['driverState']) - driver_status = DriverStatus(rhd=Params().get("IsRHD") == b"1") + driver_status = DriverStatus(rhd=Params().get_bool("IsRHD")) sm['liveCalibration'].calStatus = Calibration.INVALID sm['liveCalibration'].rpyCalib = [0, 0, 0] diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index 1e7c01203..ff7bdefb9 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -10,7 +10,7 @@ EventName = car.CarEvent.EventName # ****************************************************************************************** # NOTE: To fork maintainers. -# Disabling or nerfing safety features may get you and your users banned from our servers. +# Disabling or nerfing safety features will get you and your users banned from our servers. # We recommend that you do not change these numbers from the defaults. # ****************************************************************************************** @@ -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/pandad.py b/selfdrive/pandad.py index d4cc98474..fd9d89fdb 100755 --- a/selfdrive/pandad.py +++ b/selfdrive/pandad.py @@ -5,29 +5,11 @@ import time from panda import BASEDIR as PANDA_BASEDIR, Panda, PandaDFU from common.basedir import BASEDIR -from common.gpio import gpio_init, gpio_set -from selfdrive.hardware import TICI -from selfdrive.hardware.tici.pins import GPIO_HUB_RST_N, GPIO_STM_BOOT0, GPIO_STM_RST_N from selfdrive.swaglog import cloudlog PANDA_FW_FN = os.path.join(PANDA_BASEDIR, "board", "obj", "panda.bin.signed") -def set_panda_power(power=True): - if not TICI: - return - - gpio_init(GPIO_STM_RST_N, True) - gpio_init(GPIO_STM_BOOT0, True) - - gpio_set(GPIO_STM_RST_N, True) - gpio_set(GPIO_HUB_RST_N, True) - - time.sleep(0.1) - - gpio_set(GPIO_STM_RST_N, not power) - - def get_expected_signature(): try: return Panda.get_signature_from_firmware(PANDA_FW_FN) @@ -100,7 +82,6 @@ def update_panda(): def main(): - set_panda_power() update_panda() os.chdir(os.path.join(BASEDIR, "selfdrive/boardd")) diff --git a/selfdrive/proclogd/SConscript b/selfdrive/proclogd/SConscript index b80d17200..f95f2597e 100644 --- a/selfdrive/proclogd/SConscript +++ b/selfdrive/proclogd/SConscript @@ -1,2 +1,2 @@ -Import('env', 'cereal', 'messaging') -env.Program('proclogd.cc', LIBS=[cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']) +Import('env', 'cereal', 'messaging', 'common') +env.Program('proclogd.cc', LIBS=[cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj', 'common']) diff --git a/selfdrive/proclogd/proclogd.cc b/selfdrive/proclogd/proclogd.cc index 66f2f5025..af7a6e3f2 100644 --- a/selfdrive/proclogd/proclogd.cc +++ b/selfdrive/proclogd/proclogd.cc @@ -1,22 +1,22 @@ -#include #include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include #include -#include #include +#include +#include #include +#include -#include "messaging.hpp" - -#include "common/timing.h" -#include "common/util.h" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" ExitHandler do_exit; @@ -30,6 +30,8 @@ struct ProcCache { } int main() { + setpriority(PRIO_PROCESS, 0, -15); + PubMaster publisher({"procLog"}); double jiffy = sysconf(_SC_CLK_TCK); diff --git a/selfdrive/sensord/libdiag.h b/selfdrive/sensord/libdiag.h index ab3ee91b1..03a59464e 100644 --- a/selfdrive/sensord/libdiag.h +++ b/selfdrive/sensord/libdiag.h @@ -1,5 +1,4 @@ -#ifndef LIBDIAG_H -#define LIBDIAG_H +#pragma once #include #include @@ -36,5 +35,3 @@ int diag_send_dci_async_req(int client_id, unsigned char buf[], int bytes, unsig #ifdef __cplusplus } #endif - -#endif diff --git a/selfdrive/sensord/sensors/bmx055_accel.cc b/selfdrive/sensord/sensors/bmx055_accel.cc index 23e6d071e..590fa51e8 100644 --- a/selfdrive/sensord/sensors/bmx055_accel.cc +++ b/selfdrive/sensord/sensors/bmx055_accel.cc @@ -1,9 +1,9 @@ +#include "bmx055_accel.h" + #include -#include "common/swaglog.h" -#include "common/timing.h" - -#include "bmx055_accel.hpp" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" BMX055_Accel::BMX055_Accel(I2CBus *bus) : I2CSensor(bus) {} diff --git a/selfdrive/sensord/sensors/bmx055_accel.hpp b/selfdrive/sensord/sensors/bmx055_accel.h similarity index 95% rename from selfdrive/sensord/sensors/bmx055_accel.hpp rename to selfdrive/sensord/sensors/bmx055_accel.h index 2c9173f98..86ec419cd 100644 --- a/selfdrive/sensord/sensors/bmx055_accel.hpp +++ b/selfdrive/sensord/sensors/bmx055_accel.h @@ -1,6 +1,6 @@ #pragma once -#include "sensors/i2c_sensor.hpp" +#include "selfdrive/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define BMX055_ACCEL_I2C_ADDR 0x18 diff --git a/selfdrive/sensord/sensors/bmx055_gyro.cc b/selfdrive/sensord/sensors/bmx055_gyro.cc index d7bf00401..c8e9e3565 100644 --- a/selfdrive/sensord/sensors/bmx055_gyro.cc +++ b/selfdrive/sensord/sensors/bmx055_gyro.cc @@ -1,8 +1,9 @@ +#include "bmx055_gyro.h" + #include #include -#include "common/swaglog.h" -#include "bmx055_gyro.hpp" +#include "selfdrive/common/swaglog.h" #define DEG2RAD(x) ((x) * M_PI / 180.0) diff --git a/selfdrive/sensord/sensors/bmx055_gyro.hpp b/selfdrive/sensord/sensors/bmx055_gyro.h similarity index 95% rename from selfdrive/sensord/sensors/bmx055_gyro.hpp rename to selfdrive/sensord/sensors/bmx055_gyro.h index f808139fd..ed0c16ff0 100644 --- a/selfdrive/sensord/sensors/bmx055_gyro.hpp +++ b/selfdrive/sensord/sensors/bmx055_gyro.h @@ -1,6 +1,6 @@ #pragma once -#include "sensors/i2c_sensor.hpp" +#include "selfdrive/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define BMX055_GYRO_I2C_ADDR 0x68 diff --git a/selfdrive/sensord/sensors/bmx055_magn.cc b/selfdrive/sensord/sensors/bmx055_magn.cc index 41b41467b..438e5b494 100644 --- a/selfdrive/sensord/sensors/bmx055_magn.cc +++ b/selfdrive/sensord/sensors/bmx055_magn.cc @@ -1,12 +1,13 @@ -#include -#include -#include +#include "bmx055_magn.h" + #include -#include "common/swaglog.h" -#include "common/util.h" +#include +#include +#include -#include "bmx055_magn.hpp" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" static int16_t compensate_x(trim_data_t trim_data, int16_t mag_data_x, uint16_t data_rhall) { uint16_t process_comp_x0 = data_rhall; diff --git a/selfdrive/sensord/sensors/bmx055_magn.hpp b/selfdrive/sensord/sensors/bmx055_magn.h similarity index 97% rename from selfdrive/sensord/sensors/bmx055_magn.hpp rename to selfdrive/sensord/sensors/bmx055_magn.h index 0e11934e6..d60fd5515 100644 --- a/selfdrive/sensord/sensors/bmx055_magn.hpp +++ b/selfdrive/sensord/sensors/bmx055_magn.h @@ -1,7 +1,7 @@ #pragma once #include -#include "sensors/i2c_sensor.hpp" +#include "selfdrive/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define BMX055_MAGN_I2C_ADDR 0x10 diff --git a/selfdrive/sensord/sensors/bmx055_temp.cc b/selfdrive/sensord/sensors/bmx055_temp.cc index 86f7d4f0c..b5cb893a0 100644 --- a/selfdrive/sensord/sensors/bmx055_temp.cc +++ b/selfdrive/sensord/sensors/bmx055_temp.cc @@ -1,10 +1,10 @@ +#include "bmx055_temp.h" + #include -#include "common/swaglog.h" -#include "common/timing.h" - -#include "bmx055_temp.hpp" -#include "bmx055_accel.hpp" +#include "selfdrive/sensord/sensors/bmx055_accel.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" BMX055_Temp::BMX055_Temp(I2CBus *bus) : I2CSensor(bus) {} diff --git a/selfdrive/sensord/sensors/bmx055_temp.hpp b/selfdrive/sensord/sensors/bmx055_temp.h similarity index 69% rename from selfdrive/sensord/sensors/bmx055_temp.hpp rename to selfdrive/sensord/sensors/bmx055_temp.h index 8b7119a60..5ffaa8fb6 100644 --- a/selfdrive/sensord/sensors/bmx055_temp.hpp +++ b/selfdrive/sensord/sensors/bmx055_temp.h @@ -1,8 +1,7 @@ #pragma once -#include "sensors/i2c_sensor.hpp" -#include "sensors/bmx055_accel.hpp" - +#include "selfdrive/sensord/sensors/bmx055_accel.h" +#include "selfdrive/sensord/sensors/i2c_sensor.h" class BMX055_Temp : public I2CSensor { uint8_t get_device_address() {return BMX055_ACCEL_I2C_ADDR;} diff --git a/selfdrive/sensord/sensors/constants.hpp b/selfdrive/sensord/sensors/constants.h similarity index 100% rename from selfdrive/sensord/sensors/constants.hpp rename to selfdrive/sensord/sensors/constants.h diff --git a/selfdrive/sensord/sensors/file_sensor.cc b/selfdrive/sensord/sensors/file_sensor.cc index 6d03ef1b1..a0ec1d71d 100644 --- a/selfdrive/sensord/sensors/file_sensor.cc +++ b/selfdrive/sensord/sensors/file_sensor.cc @@ -1,8 +1,8 @@ +#include "file_sensor.h" + #include #include -#include "file_sensor.hpp" - FileSensor::FileSensor(std::string filename) : file(filename) { } diff --git a/selfdrive/sensord/sensors/file_sensor.hpp b/selfdrive/sensord/sensors/file_sensor.h similarity index 87% rename from selfdrive/sensord/sensors/file_sensor.hpp rename to selfdrive/sensord/sensors/file_sensor.h index 25a6f203c..c5b4643e1 100644 --- a/selfdrive/sensord/sensors/file_sensor.hpp +++ b/selfdrive/sensord/sensors/file_sensor.h @@ -4,8 +4,7 @@ #include #include "cereal/gen/cpp/log.capnp.h" -#include "sensors/sensor.hpp" - +#include "selfdrive/sensord/sensors/sensor.h" class FileSensor : public Sensor { protected: diff --git a/selfdrive/sensord/sensors/i2c_sensor.cc b/selfdrive/sensord/sensors/i2c_sensor.cc index e3000c8b0..64a970c59 100644 --- a/selfdrive/sensord/sensors/i2c_sensor.cc +++ b/selfdrive/sensord/sensors/i2c_sensor.cc @@ -1,5 +1,6 @@ +#include "i2c_sensor.h" + #include -#include "i2c_sensor.hpp" int16_t read_12_bit(uint8_t lsb, uint8_t msb){ uint16_t combined = (uint16_t(msb) << 8) | uint16_t(lsb & 0xF0); diff --git a/selfdrive/sensord/sensors/i2c_sensor.hpp b/selfdrive/sensord/sensors/i2c_sensor.h similarity index 80% rename from selfdrive/sensord/sensors/i2c_sensor.hpp rename to selfdrive/sensord/sensors/i2c_sensor.h index 39ef79cf8..98e2e2f85 100644 --- a/selfdrive/sensord/sensors/i2c_sensor.hpp +++ b/selfdrive/sensord/sensors/i2c_sensor.h @@ -1,10 +1,11 @@ #pragma once #include + #include "cereal/gen/cpp/log.capnp.h" -#include "common/i2c.h" -#include "sensors/sensor.hpp" -#include "sensors/constants.hpp" +#include "selfdrive/common/i2c.h" +#include "selfdrive/sensord/sensors/constants.h" +#include "selfdrive/sensord/sensors/sensor.h" int16_t read_12_bit(uint8_t lsb, uint8_t msb); int16_t read_16_bit(uint8_t lsb, uint8_t msb); diff --git a/selfdrive/sensord/sensors/light_sensor.cc b/selfdrive/sensord/sensors/light_sensor.cc index eb3eb05f1..80930e075 100644 --- a/selfdrive/sensord/sensors/light_sensor.cc +++ b/selfdrive/sensord/sensors/light_sensor.cc @@ -1,10 +1,10 @@ +#include "light_sensor.h" + #include #include -#include "common/timing.h" - -#include "light_sensor.hpp" -#include "constants.hpp" +#include "selfdrive/common/timing.h" +#include "selfdrive/sensord/sensors/constants.h" void LightSensor::get_event(cereal::SensorEventData::Builder &event){ uint64_t start_time = nanos_since_boot(); diff --git a/selfdrive/sensord/sensors/light_sensor.hpp b/selfdrive/sensord/sensors/light_sensor.h similarity index 87% rename from selfdrive/sensord/sensors/light_sensor.hpp rename to selfdrive/sensord/sensors/light_sensor.h index 7c98cb29c..faf901d41 100644 --- a/selfdrive/sensord/sensors/light_sensor.hpp +++ b/selfdrive/sensord/sensors/light_sensor.h @@ -1,5 +1,5 @@ #pragma once -#include "file_sensor.hpp" +#include "file_sensor.h" class LightSensor : public FileSensor { public: diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.cc b/selfdrive/sensord/sensors/lsm6ds3_accel.cc index 15a186725..27b882a4f 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_accel.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_accel.cc @@ -1,9 +1,9 @@ +#include "lsm6ds3_accel.h" + #include -#include "common/swaglog.h" -#include "common/timing.h" - -#include "lsm6ds3_accel.hpp" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" LSM6DS3_Accel::LSM6DS3_Accel(I2CBus *bus) : I2CSensor(bus) {} diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.hpp b/selfdrive/sensord/sensors/lsm6ds3_accel.h similarity index 92% rename from selfdrive/sensord/sensors/lsm6ds3_accel.hpp rename to selfdrive/sensord/sensors/lsm6ds3_accel.h index 314dcf8b5..e5a949d4f 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_accel.hpp +++ b/selfdrive/sensord/sensors/lsm6ds3_accel.h @@ -1,6 +1,6 @@ #pragma once -#include "sensors/i2c_sensor.hpp" +#include "selfdrive/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define LSM6DS3_ACCEL_I2C_ADDR 0x6A diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc b/selfdrive/sensord/sensors/lsm6ds3_gyro.cc index 4c983e544..d38335eb6 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_gyro.cc @@ -1,9 +1,10 @@ +#include "lsm6ds3_gyro.h" + #include #include -#include "common/swaglog.h" -#include "common/timing.h" -#include "lsm6ds3_gyro.hpp" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" #define DEG2RAD(x) ((x) * M_PI / 180.0) diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.hpp b/selfdrive/sensord/sensors/lsm6ds3_gyro.h similarity index 91% rename from selfdrive/sensord/sensors/lsm6ds3_gyro.hpp rename to selfdrive/sensord/sensors/lsm6ds3_gyro.h index 13cec204e..cb8595e76 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_gyro.hpp +++ b/selfdrive/sensord/sensors/lsm6ds3_gyro.h @@ -1,6 +1,6 @@ #pragma once -#include "sensors/i2c_sensor.hpp" +#include "selfdrive/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define LSM6DS3_GYRO_I2C_ADDR 0x6A diff --git a/selfdrive/sensord/sensors/lsm6ds3_temp.cc b/selfdrive/sensord/sensors/lsm6ds3_temp.cc index 04b0d3d4f..3b9e90f5e 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_temp.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_temp.cc @@ -1,9 +1,9 @@ +#include "lsm6ds3_temp.h" + #include -#include "common/swaglog.h" -#include "common/timing.h" - -#include "lsm6ds3_temp.hpp" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" LSM6DS3_Temp::LSM6DS3_Temp(I2CBus *bus) : I2CSensor(bus) {} diff --git a/selfdrive/sensord/sensors/lsm6ds3_temp.hpp b/selfdrive/sensord/sensors/lsm6ds3_temp.h similarity index 90% rename from selfdrive/sensord/sensors/lsm6ds3_temp.hpp rename to selfdrive/sensord/sensors/lsm6ds3_temp.h index eea5ff4a6..c556631de 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_temp.hpp +++ b/selfdrive/sensord/sensors/lsm6ds3_temp.h @@ -1,6 +1,6 @@ #pragma once -#include "sensors/i2c_sensor.hpp" +#include "selfdrive/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define LSM6DS3_TEMP_I2C_ADDR 0x6A diff --git a/selfdrive/sensord/sensors/sensor.hpp b/selfdrive/sensord/sensors/sensor.h similarity index 100% rename from selfdrive/sensord/sensors/sensor.hpp rename to selfdrive/sensord/sensors/sensor.h diff --git a/selfdrive/sensord/sensors_qcom.cc b/selfdrive/sensord/sensors_qcom.cc index 77e670d3f..81bb78e85 100644 --- a/selfdrive/sensord/sensors_qcom.cc +++ b/selfdrive/sensord/sensors_qcom.cc @@ -1,25 +1,24 @@ -#include +#include +#include +#include #include +#include #include #include -#include -#include -#include #include -#include #include +#include +#include +#include +#include #include #include -#include -#include -#include - -#include "messaging.hpp" -#include "common/timing.h" -#include "common/util.h" -#include "common/swaglog.h" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" // ACCELEROMETER_UNCALIBRATED is only in Android O // https://developer.android.com/reference/android/hardware/Sensor.html#STRING_TYPE_ACCELEROMETER_UNCALIBRATED @@ -197,7 +196,8 @@ void sensor_loop() { } // Check whether to go into low power mode at 5Hz - if (frame % 20 == 0 && sm.update(0) > 0) { + if (frame % 20 == 0) { + sm.update(0); bool offroad = !sm["deviceState"].getDeviceState().getStarted(); if (low_power_mode != offroad) { for (auto &s : sensors) { @@ -219,7 +219,7 @@ void sensor_loop() { }// Namespace end int main(int argc, char *argv[]) { - setpriority(PRIO_PROCESS, 0, -13); + setpriority(PRIO_PROCESS, 0, -18); signal(SIGPIPE, (sighandler_t)sigpipe_handler); sensor_loop(); diff --git a/selfdrive/sensord/sensors_qcom2.cc b/selfdrive/sensord/sensors_qcom2.cc index 1cc685fe3..d0f8cf00e 100644 --- a/selfdrive/sensord/sensors_qcom2.cc +++ b/selfdrive/sensord/sensors_qcom2.cc @@ -1,27 +1,24 @@ -#include -#include -#include #include -#include "messaging.hpp" -#include "common/i2c.h" -#include "common/timing.h" -#include "common/util.h" -#include "common/swaglog.h" +#include +#include +#include -#include "sensors/sensor.hpp" -#include "sensors/constants.hpp" - -#include "sensors/bmx055_accel.hpp" -#include "sensors/bmx055_gyro.hpp" -#include "sensors/bmx055_magn.hpp" -#include "sensors/bmx055_temp.hpp" - -#include "sensors/lsm6ds3_accel.hpp" -#include "sensors/lsm6ds3_gyro.hpp" -#include "sensors/lsm6ds3_temp.hpp" - -#include "sensors/light_sensor.hpp" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/i2c.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" +#include "selfdrive/sensord/sensors/bmx055_accel.h" +#include "selfdrive/sensord/sensors/bmx055_gyro.h" +#include "selfdrive/sensord/sensors/bmx055_magn.h" +#include "selfdrive/sensord/sensors/bmx055_temp.h" +#include "selfdrive/sensord/sensors/constants.h" +#include "selfdrive/sensord/sensors/light_sensor.h" +#include "selfdrive/sensord/sensors/lsm6ds3_accel.h" +#include "selfdrive/sensord/sensors/lsm6ds3_gyro.h" +#include "selfdrive/sensord/sensors/lsm6ds3_temp.h" +#include "selfdrive/sensord/sensors/sensor.h" #define I2C_BUS_IMU 1 @@ -93,6 +90,6 @@ int sensor_loop() { } int main(int argc, char *argv[]) { - setpriority(PRIO_PROCESS, 0, -13); + setpriority(PRIO_PROCESS, 0, -18); return sensor_loop(); } diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py index fda1a3175..6a7c1a837 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -11,11 +11,10 @@ def set_params_enabled(): from common.params import Params params = Params() params.put("HasAcceptedTerms", terms_version) - params.put("HasCompletedSetup", "1") - params.put("OpenpilotEnabledToggle", "1") - params.put("CommunityFeaturesToggle", "1") - params.put("Passive", "0") params.put("CompletedTrainingVersion", training_version) + params.put_bool("OpenpilotEnabledToggle", True) + params.put_bool("CommunityFeaturesToggle", True) + params.put_bool("Passive", False) def phone_only(x): @@ -25,7 +24,9 @@ def phone_only(x): return x -def with_processes(processes, init_time=0): +def with_processes(processes, init_time=0, ignore_stopped=None): + ignore_stopped = [] if ignore_stopped is None else ignore_stopped + def wrapper(func): @wraps(func) def wrap(*args, **kwargs): @@ -40,7 +41,7 @@ def with_processes(processes, init_time=0): try: func(*args, **kwargs) # assert processes are still started - assert all(managed_processes[name].proc.exitcode is None for name in processes) + assert all(managed_processes[name].proc.exitcode is None for name in processes if name not in ignore_stopped) finally: for p in processes: managed_processes[p].stop() diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh index 435a6af43..cc04504ad 100755 --- a/selfdrive/test/setup_device_ci.sh +++ b/selfdrive/test/setup_device_ci.sh @@ -26,8 +26,8 @@ if [ ! -d "$SOURCE_DIR" ]; then git clone --depth 1 https://github.com/commaai/openpilot.git "$SOURCE_DIR" fi -# clear scons cache dirs that haven't been written to in one day -#cd /tmp && find -name 'scons_cache_*' -type d -maxdepth 1 -mtime +1 -exec rm -rf '{}' \; +# clear stale build cache +find /tmp/scons_cache*/* -mtime +1 -exec rm -rf '{}' \; || true # this can get really big on the CI devices rm -rf /data/core diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py new file mode 100755 index 000000000..078b1cb4b --- /dev/null +++ b/selfdrive/test/test_onroad.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +import json +import os +import subprocess +import time +import unittest +from collections import Counter +from pathlib import Path + +import cereal.messaging as messaging +from cereal.services import service_list +from common.basedir import BASEDIR +from common.timeout import Timeout +from selfdrive.hardware import TICI +from selfdrive.loggerd.config import ROOT +from selfdrive.test.helpers import set_params_enabled +from tools.lib.logreader import LogReader + +# Baseline CPU usage by process +PROCS = { + "selfdrive.controls.controlsd": 50.0, + "./loggerd": 45.0, + "./locationd": 9.1, + "selfdrive.controls.plannerd": 20.0, + "./_ui": 15.0, + "selfdrive.locationd.paramsd": 9.1, + "./camerad": 7.07, + "./_sensord": 6.17, + "selfdrive.controls.radard": 5.67, + "./_modeld": 4.48, + "./boardd": 3.63, + "./_dmonitoringmodeld": 2.67, + "selfdrive.thermald.thermald": 2.41, + "selfdrive.locationd.calibrationd": 2.0, + "selfdrive.monitoring.dmonitoringd": 1.90, + "./proclogd": 1.54, + "selfdrive.logmessaged": 0.2, + "./clocksd": 0.02, + "./ubloxd": 0.02, + "selfdrive.tombstoned": 0, + "./logcatd": 0, +} + +if TICI: + PROCS.update({ + "./loggerd": 60.0, + "selfdrive.controls.controlsd": 26.0, + "./camerad": 25.0, + "selfdrive.controls.plannerd": 12.0, + "selfdrive.locationd.paramsd": 5.0, + "./_dmonitoringmodeld": 10.0, + "selfdrive.thermald.thermald": 1.5, + }) + + +def cputime_total(ct): + return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem + + +def check_cpu_usage(first_proc, last_proc): + result = "------------------------------------------------\n" + result += "------------------ CPU Usage -------------------\n" + result += "------------------------------------------------\n" + + r = True + dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9 + for proc_name, normal_cpu_usage in PROCS.items(): + first, last = None, None + try: + first = [p for p in first_proc.procLog.procs if proc_name in p.cmdline][0] + last = [p for p in last_proc.procLog.procs if proc_name in p.cmdline][0] + 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 < 50.: + 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)): + result += f"Warning {proc_name} using less CPU than normal\n" + r = False + result += f"{proc_name.ljust(35)} {cpu_usage:.2f}%\n" + except IndexError: + result += f"{proc_name.ljust(35)} NO METRICS FOUND {first=} {last=}\n" + r = False + result += "------------------------------------------------\n" + print(result) + return r + + +class TestOnroad(unittest.TestCase): + + @classmethod + def setUpClass(cls): + os.environ['SKIP_FW_QUERY'] = "1" + os.environ['FINGERPRINT'] = "TOYOTA COROLLA TSS2 2019" + set_params_enabled() + + logger_root = Path(ROOT) + initial_segments = set() + if logger_root.exists(): + initial_segments = set(Path(ROOT).iterdir()) + + # start manager and run openpilot for a minute + try: + manager_path = os.path.join(BASEDIR, "selfdrive/manager/manager.py") + proc = subprocess.Popen(["python", manager_path]) + + sm = messaging.SubMaster(['carState']) + with Timeout(150, "controls didn't start"): + while sm.rcv_frame['carState'] < 0: + sm.update(1000) + + # make sure we get at least two full segments + cls.segments = [] + with Timeout(300, "timed out waiting for logs"): + while len(cls.segments) < 3: + new_paths = set() + if logger_root.exists(): + new_paths = set(logger_root.iterdir()) - initial_segments + segs = [p for p in new_paths if "--" in str(p)] + cls.segments = sorted(segs, key=lambda s: int(str(s).rsplit('--')[-1])) + time.sleep(5) + + finally: + proc.terminate() + if proc.wait(60) is None: + proc.kill() + + cls.lr = list(LogReader(os.path.join(str(cls.segments[1]), "rlog.bz2"))) + + def test_cloudlog_size(self): + msgs = [m for m in self.lr if m.which() == 'logMessage'] + + total_size = sum(len(m.as_builder().to_bytes()) for m in msgs) + self.assertLess(total_size, 2.5e5) + + cnt = Counter([json.loads(m.logMessage)['filename'] for m in msgs]) + big_logs = [f for f, n in cnt.most_common(3) if n / sum(cnt.values()) > 30.] + self.assertEqual(len(big_logs), 0, f"Log spam: {big_logs}") + + def test_cpu_usage(self): + proclogs = [m for m in self.lr if m.which() == 'procLog'] + self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples") + cpu_ok = check_cpu_usage(proclogs[0], proclogs[-1]) + self.assertTrue(cpu_ok) + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index 485ebd2de..f8980eda3 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -16,7 +16,8 @@ CAR_VOLTAGE_LOW_PASS_K = 0.091 # LPF gain for 5s tau (dt/tau / (dt/tau + 1)) CAR_BATTERY_CAPACITY_uWh = 30e6 CAR_CHARGING_RATE_W = 45 -VBATT_PAUSE_CHARGING = 11.0 +VBATT_PAUSE_CHARGING = 11.0 # Lower limit on the LPF car battery voltage +VBATT_INSTANT_PAUSE_CHARGING = 7.0 # Lower limit on the instant car battery voltage measurements to avoid triggering on instant power loss MAX_TIME_OFFROAD_S = 30*3600 class PowerMonitoring: @@ -27,6 +28,7 @@ class PowerMonitoring: self.power_used_uWh = 0 # Integrated power usage in uWh since going into offroad self.next_pulsed_measurement_time = None self.car_voltage_mV = 12e3 # Low-passed version of pandaState voltage + self.car_voltage_instant_mV = 12e3 # Last value of pandaState voltage self.integration_lock = threading.Lock() car_battery_capacity_uWh = self.params.get("CarBatteryCapacity") @@ -51,6 +53,7 @@ class PowerMonitoring: return # Low-pass battery voltage + self.car_voltage_instant_mV = pandaState.pandaState.voltage self.car_voltage_mV = ((pandaState.pandaState.voltage * CAR_VOLTAGE_LOW_PASS_K) + (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K))) # Cap the car battery power and save it in a param every 10-ish seconds @@ -161,11 +164,11 @@ class PowerMonitoring: now = sec_since_boot() disable_charging = False disable_charging |= (now - offroad_timestamp) > MAX_TIME_OFFROAD_S - disable_charging |= (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3)) + disable_charging |= (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3)) and (self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3)) disable_charging |= (self.car_battery_capacity_uWh <= 0) disable_charging &= (not pandaState.pandaState.ignitionLine and not pandaState.pandaState.ignitionCan) - disable_charging &= (self.params.get("DisablePowerDown") != b"1") - disable_charging |= (self.params.get("ForcePowerDown") == b"1") + disable_charging &= (not self.params.get_bool("DisablePowerDown")) + disable_charging |= self.params.get_bool("ForcePowerDown") return disable_charging # See if we need to shutdown diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 78a535083..b7480a9ce 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -12,7 +12,7 @@ import cereal.messaging as messaging from cereal import log from common.filter_simple import FirstOrderFilter from common.numpy_fast import clip, interp -from common.params import Params +from common.params import Params, ParamKeyType from common.realtime import DT_TRML, sec_since_boot from common.dict_helpers import strip_deprecated_keys from selfdrive.controls.lib.alertmanager import set_offroad_alert @@ -25,8 +25,6 @@ from selfdrive.version import get_git_branch, terms_version, training_version FW_SIGNATURE = get_expected_signature() -DISABLE_LTE_ONROAD = os.path.exists("/persist/disable_lte_onroad") or TICI - ThermalStatus = log.DeviceState.ThermalStatus NetworkType = log.DeviceState.NetworkType NetworkStrength = log.DeviceState.NetworkStrength @@ -176,6 +174,7 @@ def thermald_thread(): if EON: base_path = "/sys/kernel/debug/cpr3-regulator/" cpr_files = [p for p in Path(base_path).glob("**/*") if p.is_file()] + cpr_files = ["/sys/kernel/debug/regulator/pm8994_s11/voltage"] + cpr_files cpr_data = {} for cf in cpr_files: with open(cf, "r") as f: @@ -223,7 +222,7 @@ def thermald_thread(): if pandaState_prev is not None: if pandaState.pandaState.pandaType == log.PandaState.PandaType.unknown and \ pandaState_prev.pandaState.pandaType != log.PandaState.PandaType.unknown: - params.panda_disconnect() + params.clear_all(ParamKeyType.CLEAR_ON_PANDA_DISCONNECT) pandaState_prev = pandaState # get_network_type is an expensive call. update every 10s @@ -327,8 +326,8 @@ def thermald_thread(): set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False) set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False) - startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get("DisableUpdates") == b"1" - startup_conditions["not_uninstalling"] = not params.get("DoUninstall") == b"1" + startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") + startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall") startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version panda_signature = params.get("PandaFirmware") @@ -339,8 +338,8 @@ def thermald_thread(): startup_conditions["free_space"] = msg.deviceState.freeSpacePercent > 2 startup_conditions["completed_training"] = params.get("CompletedTrainingVersion") == training_version or \ (current_branch in ['dashcam', 'dashcam-staging']) - startup_conditions["not_driver_view"] = not params.get("IsDriverViewEnabled") == b"1" - startup_conditions["not_taking_snapshot"] = not params.get("IsTakingSnapshot") == b"1" + startup_conditions["not_driver_view"] = not params.get_bool("IsDriverViewEnabled") + startup_conditions["not_taking_snapshot"] = not params.get_bool("IsTakingSnapshot") # if any CPU gets above 107 or the battery gets above 63, kill all processes # controls will warn with CPU above 95 or battery above 60 startup_conditions["device_temp_good"] = thermal_status < ThermalStatus.danger @@ -348,12 +347,14 @@ def thermald_thread(): # Handle offroad/onroad transition should_start = all(startup_conditions.values()) - if should_start: - if not should_start_prev: - params.delete("IsOffroad") - if TICI and DISABLE_LTE_ONROAD: - os.system("sudo systemctl stop --no-block lte") + if should_start != should_start_prev or (count == 0): + params.put_bool("IsOffroad", not should_start) + HARDWARE.set_power_save(not should_start) + if TICI and not params.get_bool("EnableLteOnroad"): + fxn = "off" if should_start else "on" + os.system(f"nmcli radio wwan {fxn}") + if should_start: off_ts = None if started_ts is None: started_ts = sec_since_boot() @@ -362,11 +363,6 @@ def thermald_thread(): if startup_conditions["ignition"] and (startup_conditions != startup_conditions_prev): cloudlog.event("Startup blocked", startup_conditions=startup_conditions) - if should_start_prev or (count == 0): - params.put("IsOffroad", "1") - if TICI and DISABLE_LTE_ONROAD: - os.system("sudo systemctl start --no-block lte") - started_ts = None if off_ts is None: off_ts = sec_since_boot() @@ -409,6 +405,9 @@ def thermald_thread(): # report to server once every 10 minutes if (count % int(600. / DT_TRML)) == 0: + if EON and started_ts is None and msg.deviceState.memoryUsagePercent > 40: + cloudlog.event("High offroad memory usage", mem=msg.deviceState.memoryUsagePercent) + location = messaging.recv_sock(location_sock) cloudlog.event("STATUS_PACKET", count=count, diff --git a/selfdrive/tombstoned.py b/selfdrive/tombstoned.py index 404d71416..fb7a1a2c9 100755 --- a/selfdrive/tombstoned.py +++ b/selfdrive/tombstoned.py @@ -8,11 +8,11 @@ import subprocess import time import glob -from raven import Client -from raven.transport.http import HTTPTransport +import sentry_sdk +from common.params import Params from common.file_helpers import mkdirs_exists_ok -from selfdrive.hardware import TICI +from selfdrive.hardware import TICI, HARDWARE from selfdrive.loggerd.config import ROOT from selfdrive.swaglog import cloudlog from selfdrive.version import branch, commit, dirty, origin, version @@ -31,16 +31,15 @@ def safe_fn(s): return "".join(c for c in s if c.isalnum() or c in extra).rstrip() -def sentry_report(client, fn, message, contents): +def sentry_report(fn, message, contents): cloudlog.error({'tombstone': message}) - client.captureMessage( - message=message, - sdk={'name': 'tombstoned', 'version': '0'}, - extra={ - 'tombstone_fn': fn, - 'tombstone': contents - }, - ) + + with sentry_sdk.configure_scope() as scope: + scope.set_extra("tombstone_fn", fn) + scope.set_extra("tombstone", contents) + sentry_sdk.capture_message(message=message) + sentry_sdk.flush() + def clear_apport_folder(): for f in glob.glob(APPORT_DIR + '*'): @@ -77,7 +76,7 @@ def get_tombstones(): return files -def report_tombstone_android(fn, client): +def report_tombstone_android(fn): f_size = os.path.getsize(fn) if f_size > MAX_SIZE: cloudlog.error(f"Tombstone {fn} too big, {f_size}. Skipping...") @@ -104,7 +103,7 @@ def report_tombstone_android(fn, client): if fault_idx >= 0: message = message[:fault_idx] - sentry_report(client, fn, message, contents) + sentry_report(fn, message, contents) # Copy crashlog to upload folder clean_path = executable.replace('./', '').replace('/', '_') @@ -118,7 +117,7 @@ def report_tombstone_android(fn, client): shutil.copy(fn, os.path.join(crashlog_dir, new_fn)) -def report_tombstone_apport(fn, client): +def report_tombstone_apport(fn): f_size = os.path.getsize(fn) if f_size > MAX_SIZE: cloudlog.error(f"Tombstone {fn} too big, {f_size}. Skipping...") @@ -178,7 +177,7 @@ def report_tombstone_apport(fn, client): contents = stacktrace + "\n\n" + contents message = message + " - " + crash_function - sentry_report(client, fn, message, contents) + sentry_report(fn, message, contents) # Copy crashlog to upload folder clean_path = path.replace('/', '_') @@ -202,15 +201,18 @@ def main(): clear_apport_folder() # Clear apport folder on start, otherwise duplicate crashes won't register initial_tombstones = set(get_tombstones()) - tags = { - 'dirty': dirty, - 'origin': origin, - 'branch': branch - } - client = Client('https://d3b175702f62402c91ade04d1c547e68:b20d68c813c74f63a7cdf9c4039d8f56@sentry.io/157615', - install_sys_hook=False, transport=HTTPTransport, release=version, tags=tags, string_max_length=10000) + sentry_sdk.utils.MAX_STRING_LENGTH = 8192 + sentry_sdk.init("https://a40f22e13cbc4261873333c125fc9d38@o33823.ingest.sentry.io/157615", + default_integrations=False, release=version) + + dongle_id = Params().get("DongleId", encoding='utf-8') + sentry_sdk.set_user({"id": dongle_id}) + sentry_sdk.set_tag("dirty", dirty) + sentry_sdk.set_tag("origin", origin) + sentry_sdk.set_tag("branch", branch) + sentry_sdk.set_tag("commit", commit) + sentry_sdk.set_tag("device", HARDWARE.get_device_type()) - client.user_context({'id': os.environ.get('DONGLE_ID')}) while True: now_tombstones = set(get_tombstones()) @@ -218,9 +220,9 @@ def main(): try: cloudlog.info(f"reporting new tombstone {fn}") if fn.endswith(".crash"): - report_tombstone_apport(fn, client) + report_tombstone_apport(fn) else: - report_tombstone_android(fn, client) + report_tombstone_android(fn) except Exception: cloudlog.exception(f"Error reporting tombstone {fn}") diff --git a/selfdrive/ui/.gitignore b/selfdrive/ui/.gitignore index 63f85bac0..2dbc32523 100644 --- a/selfdrive/ui/.gitignore +++ b/selfdrive/ui/.gitignore @@ -1,6 +1,7 @@ moc_* *.moc +replay/replay qt/text qt/spinner qt/setup/setup diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index ebef246ab..325c50b73 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,37 +1,36 @@ import os -Import('env', 'qt_env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', +Import('qt_env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal', 'transformations') -src = ['ui.cc', 'paint.cc', 'sidebar.cc', '#phonelibs/nanovg/nanovg.c'] -libs = [gpucommon, common, 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', - cereal, messaging, visionipc, transformations] - +base_libs = [gpucommon, common, messaging, cereal, visionipc, transformations, 'zmq', + 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] if arch == 'aarch64': - libs += ['log', 'utils', 'gui', 'ui', 'CB', 'gsl', 'adreno_utils', - 'cutils', 'uuid'] + base_libs += ['log', 'utils', 'gui', 'ui', 'CB', 'gsl', 'adreno_utils', 'cutils', 'uuid'] -qt_base_libs = qt_env["LIBS"] + libs + ["pthread"] if arch == "Darwin": - del qt_base_libs[qt_base_libs.index('OpenCL')] + del base_libs[base_libs.index('OpenCL')] 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/sound.cc", + "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/setup.cc", "qt/widgets/keyboard.cc", - "#phonelibs/qrcode/QrCode.cc"] + "qt/widgets/scrollview.cc", "#phonelibs/qrcode/QrCode.cc", "qt/api.cc", + "qt/request_repeater.cc"] if arch != 'aarch64': widgets_src += ["qt/offroad/networking.cc", "qt/offroad/wifiManager.cc"] -widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=qt_base_libs) -qt_libs = qt_base_libs + [widgets] +widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs) +qt_libs = [widgets] + base_libs # spinner and text window -qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_base_libs) -qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_base_libs) +qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs) +qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=base_libs) # build main UI -qt_src = ["qt/ui.cc", "qt/window.cc", "qt/home.cc", "qt/api.cc", "qt/offroad/settings.cc", - "qt/offroad/onboarding.cc"] + src +qt_src = ["main.cc", "ui.cc", "paint.cc", "qt/sidebar.cc", "qt/onroad.cc", + "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", + "qt/offroad/onboarding.cc", "#phonelibs/nanovg/nanovg.c"] + qt_env.Program("_ui", qt_src, LIBS=qt_libs) # setup, factory resetter, and installer @@ -42,10 +41,10 @@ if arch != 'aarch64' and "BUILD_SETUP" in os.environ: installers = [ ("openpilot", "master"), - #("openpilot_test", "release3-staging"), - #("openpilot_internal", "master"), - #("dashcam", "dashcam3-staging"), - #("dashcam_test", "dashcam3-staging"), + ("openpilot_test", "release3-staging"), + ("openpilot_internal", "master"), + ("dashcam", "dashcam3-staging"), + ("dashcam_test", "dashcam3-staging"), ] for name, branch in installers: d = {'BRANCH': f"'\"{branch}\"'"} @@ -56,4 +55,17 @@ if arch != 'aarch64' and "BUILD_SETUP" in os.environ: r = requests.get("https://github.com/commaci2.keys") r.raise_for_status() d['SSH_KEYS'] = f'\\"{r.text.strip()}\\"' - qt_env.Program(f"qt/setup/installer_{name}", ["qt/setup/installer.cc"], LIBS=qt_libs, CPPDEFINES=d) + obj = qt_env.Object(f"qt/setup/installer_{name}.o", ["qt/setup/installer.cc"], CPPDEFINES=d) + qt_env.Program(f"qt/setup/installer_{name}", obj, LIBS=qt_libs, CPPDEFINES=d) + +# build headless replay +if arch == 'x86_64' and os.path.exists(Dir("#tools/").get_abspath()): + qt_env['CPPPATH'] += ["#tools/clib"] + qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] + + replay_lib_src = ["replay/replay.cc", "replay/unlogger.cc", + "replay/filereader.cc", "#tools/clib/framereader.cc"] + + replay_lib = qt_env.Library("qt_replay", replay_lib_src, LIBS=base_libs) + replay_libs = [replay_lib, 'avutil', 'avcodec', 'avformat', 'swscale', 'bz2'] + qt_libs + qt_env.Program("replay/replay", ["replay/main.cc"], LIBS=replay_libs) diff --git a/selfdrive/ui/qt/ui.cc b/selfdrive/ui/main.cc similarity index 51% rename from selfdrive/ui/qt/ui.cc rename to selfdrive/ui/main.cc index 1f33c75aa..dab8d6654 100644 --- a/selfdrive/ui/qt/ui.cc +++ b/selfdrive/ui/main.cc @@ -1,7 +1,9 @@ #include +#include -#include "window.hpp" -#include "qt_window.hpp" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/ui/qt/window.h" int main(int argc, char *argv[]) { QSurfaceFormat fmt; @@ -14,9 +16,12 @@ int main(int argc, char *argv[]) { #endif QSurfaceFormat::setDefaultFormat(fmt); -#ifdef QCOM - QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); -#endif + if (Hardware::EON()) { + QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); + QSslConfiguration ssl = QSslConfiguration::defaultConfiguration(); + ssl.setCaCertificates(QSslCertificate::fromPath("/usr/etc/tls/cert.pem")); + QSslConfiguration::setDefaultConfiguration(ssl); + } QApplication a(argc, argv); MainWindow w; diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc index 563dec36a..e6a868697 100644 --- a/selfdrive/ui/paint.cc +++ b/selfdrive/ui/paint.cc @@ -1,25 +1,33 @@ -#include "ui.hpp" +#include "paint.h" #include -#include "common/util.h" -#include "common/timing.h" + #include +#ifdef __APPLE__ +#include +#define NANOVG_GL3_IMPLEMENTATION +#define nvgCreate nvgCreateGL3 +#else +#include #define NANOVG_GLES3_IMPLEMENTATION -#include "nanovg_gl.h" -#include "nanovg_gl_utils.h" -#include "paint.hpp" -#include "sidebar.hpp" +#define nvgCreate nvgCreateGLES3 +#endif + +#define NANOVG_GLES3_IMPLEMENTATION +#include +#include + +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" + +#include "selfdrive/ui/ui.h" // TODO: this is also hardcoded in common/transformations/camera.py // TODO: choose based on frame input size -#ifdef QCOM2 -const float y_offset = 150.0; -const float zoom = 1.1; -#else -const float y_offset = 0.0; -const float zoom = 2.35; -#endif +const float y_offset = Hardware::TICI() ? 150.0 : 0.0; +const float zoom = Hardware::TICI() ? 2912.8 : 2138.5; static void ui_draw_text(const UIState *s, float x, float y, const char *string, float size, NVGcolor color, const char *font_name) { nvgFontFace(s->vg, font_name); @@ -50,19 +58,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) { @@ -83,7 +91,7 @@ static void draw_lead(UIState *s, int idx) { fillAlpha = (int)(fmin(fillAlpha, 255)); } - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * zoom; + float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * s->zoom; x = std::clamp(x, 0.f, s->viz_rect.right() - sz / 2); y = std::fmin(s->viz_rect.bottom() - sz * .6, y); draw_chevron(s, x, y, sz, nvgRGBA(201, 34, 49, fillAlpha), COLOR_YELLOW); @@ -120,11 +128,11 @@ static void draw_frame(UIState *s) { if (s->last_frame) { glBindTexture(GL_TEXTURE_2D, s->texture[s->last_frame->idx]->frame_tex); -#ifndef QCOM - // this is handled in ion on QCOM - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s->last_frame->width, s->last_frame->height, - 0, GL_RGB, GL_UNSIGNED_BYTE, s->last_frame->addr); -#endif + if (!Hardware::EON()) { + // this is handled in ion on QCOM + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s->last_frame->width, s->last_frame->height, + 0, GL_RGB, GL_UNSIGNED_BYTE, s->last_frame->addr); + } } glUseProgram(s->gl_shader->prog); @@ -215,22 +223,21 @@ 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) { - s->sidebar_collapsed = true; const bool is_rhd = s->scene.is_rhd; const int width = 4 * s->viz_rect.h / 3; const Rect rect = {s->viz_rect.centerX() - width / 2, s->viz_rect.y, width, s->viz_rect.h}; // x, y, w, h @@ -238,13 +245,9 @@ static void ui_draw_driver_view(UIState *s) { // blackout const int blackout_x_r = valid_rect.right(); -#ifndef QCOM2 - const int blackout_w_r = rect.right() - valid_rect.right(); - const int blackout_x_l = rect.x; -#else - const int blackout_w_r = s->viz_rect.right() - valid_rect.right(); - const int blackout_x_l = s->viz_rect.x; -#endif + const Rect &blackout_rect = Hardware::TICI() ? s->viz_rect : rect; + const int blackout_w_r = blackout_rect.right() - valid_rect.right(); + const int blackout_x_l = blackout_rect.x; const int blackout_w_l = valid_rect.x - blackout_x_l; ui_fill_rect(s->vg, {blackout_x_l, rect.y, blackout_w_l, rect.h}, COLOR_BLACK_ALPHA(144)); ui_fill_rect(s->vg, {blackout_x_r, rect.y, blackout_w_r, rect.h}, COLOR_BLACK_ALPHA(144)); @@ -266,10 +269,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) { @@ -285,54 +288,6 @@ static void ui_draw_vision_header(UIState *s) { ui_draw_vision_event(s); } -static void ui_draw_vision_footer(UIState *s) { - ui_draw_vision_face(s); -} - -static float get_alert_alpha(float blink_rate) { - return 0.375 * cos((millis_since_boot() / 1000) * 2 * M_PI * blink_rate) + 0.625; -} - -static void ui_draw_vision_alert(UIState *s) { - static std::map alert_size_map = { - {cereal::ControlsState::AlertSize::SMALL, 241}, - {cereal::ControlsState::AlertSize::MID, 390}, - {cereal::ControlsState::AlertSize::FULL, s->fb_h}}; - const UIScene *scene = &s->scene; - bool longAlert1 = scene->alert_text1.length() > 15; - - NVGcolor color = bg_colors[s->status]; - color.a *= get_alert_alpha(scene->alert_blinking_rate); - const int alr_h = alert_size_map[scene->alert_size] + bdr_s; - const Rect rect = {.x = s->viz_rect.x - bdr_s, - .y = s->fb_h - alr_h, - .w = s->viz_rect.w + (bdr_s * 2), - .h = alr_h}; - - ui_fill_rect(s->vg, rect, color); - ui_fill_rect(s->vg, rect, nvgLinearGradient(s->vg, rect.x, rect.y, rect.x, rect.bottom(), - nvgRGBAf(0.0, 0.0, 0.0, 0.05), nvgRGBAf(0.0, 0.0, 0.0, 0.35))); - - nvgFillColor(s->vg, COLOR_WHITE); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - - if (scene->alert_size == cereal::ControlsState::AlertSize::SMALL) { - ui_draw_text(s, rect.centerX(), rect.centerY() + 15, scene->alert_text1.c_str(), 40*2.5, COLOR_WHITE, "sans-semibold"); - } else if (scene->alert_size == cereal::ControlsState::AlertSize::MID) { - ui_draw_text(s, rect.centerX(), rect.centerY() - 45, scene->alert_text1.c_str(), 48*2.5, COLOR_WHITE, "sans-bold"); - ui_draw_text(s, rect.centerX(), rect.centerY() + 75, scene->alert_text2.c_str(), 36*2.5, COLOR_WHITE, "sans-regular"); - } else if (scene->alert_size == cereal::ControlsState::AlertSize::FULL) { - nvgFontSize(s->vg, (longAlert1?72:96)*2.5); - nvgFontFace(s->vg, "sans-bold"); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgTextBox(s->vg, rect.x, rect.y+(longAlert1?360:420), rect.w-60, scene->alert_text1.c_str(), NULL); - nvgFontSize(s->vg, 48*2.5); - nvgFontFace(s->vg, "sans-regular"); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BOTTOM); - nvgTextBox(s->vg, rect.x, rect.h-(longAlert1?300:360), rect.w-60, scene->alert_text2.c_str(), NULL); - } -} - static void ui_draw_vision_frame(UIState *s) { // Draw video frames glEnable(GL_SCISSOR_TEST); @@ -353,8 +308,8 @@ static void ui_draw_vision(UIState *s) { } // Set Speed, Current Speed, Status/Events ui_draw_vision_header(s); - if (scene->alert_size == cereal::ControlsState::AlertSize::NONE) { - ui_draw_vision_footer(s); + if (s->scene.controls_state.getAlertSize() == cereal::ControlsState::AlertSize::NONE) { + ui_draw_vision_face(s); } } else { ui_draw_driver_view(s); @@ -367,15 +322,10 @@ static void ui_draw_background(UIState *s) { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); } -void ui_draw(UIState *s) { - s->viz_rect = Rect{bdr_s, bdr_s, s->fb_w - 2 * bdr_s, s->fb_h - 2 * bdr_s}; - if (!s->sidebar_collapsed) { - s->viz_rect.x += sbr_w; - s->viz_rect.w -= sbr_w; - } +void ui_draw(UIState *s, int w, int h) { + s->viz_rect = Rect{bdr_s, bdr_s, w - 2 * bdr_s, h - 2 * bdr_s}; - const bool draw_alerts = s->scene.started; - const bool draw_vision = draw_alerts && s->vipc_client->connected; + const bool draw_vision = s->scene.started && s->vipc_client->connected; // GL drawing functions ui_draw_background(s); @@ -388,13 +338,14 @@ void ui_draw(UIState *s) { // NVG drawing functions - should be no GL inside NVG frame nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); - ui_draw_sidebar(s); + if (draw_vision) { ui_draw_vision(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); @@ -457,6 +408,10 @@ static const char frame_fragment_shader[] = "out vec4 colorOut;\n" "void main() {\n" " colorOut = texture(uTexture, vTexCoord.xy);\n" +#ifdef QCOM + " vec3 dz = vec3(0.0627f, 0.0627f, 0.0627f);\n" + " colorOut.rgb = ((vec3(1.0f, 1.0f, 1.0f) - dz) * colorOut.rgb / vec3(1.0f, 1.0f, 1.0f)) + dz;\n" +#endif "}\n"; static const mat4 device_transform = {{ @@ -466,41 +421,42 @@ static const mat4 device_transform = {{ 0.0, 0.0, 0.0, 1.0, }}; -static const float driver_view_ratio = 1.333; -#ifndef QCOM2 -// frame from 4/3 to 16/9 display -static const mat4 driver_view_transform = {{ - driver_view_ratio*(1080-2*bdr_s)/(1920-2*bdr_s), 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; -#else -// from dmonitoring.cc -static const int full_width_tici = 1928; -static const int full_height_tici = 1208; -static const int adapt_width_tici = 668; -static const int crop_x_offset = 32; -static const int crop_y_offset = -196; -static const float yscale = full_height_tici * driver_view_ratio / adapt_width_tici; -static const float xscale = yscale*(1080-2*bdr_s)/(2160-2*bdr_s)*full_width_tici/full_height_tici; - -static const mat4 driver_view_transform = {{ - xscale, 0.0, 0.0, xscale*crop_x_offset/full_width_tici*2, - 0.0, yscale, 0.0, yscale*crop_y_offset/full_height_tici*2, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; -#endif +static mat4 get_driver_view_transform() { + const float driver_view_ratio = 1.333; + mat4 transform; + if (Hardware::TICI()) { + // from dmonitoring.cc + const int full_width_tici = 1928; + const int full_height_tici = 1208; + const int adapt_width_tici = 668; + const int crop_x_offset = 32; + const int crop_y_offset = -196; + const float yscale = full_height_tici * driver_view_ratio / adapt_width_tici; + const float xscale = yscale*(1080-2*bdr_s)/(2160-2*bdr_s)*full_width_tici/full_height_tici; + transform = (mat4){{ + xscale, 0.0, 0.0, xscale*crop_x_offset/full_width_tici*2, + 0.0, yscale, 0.0, yscale*crop_y_offset/full_height_tici*2, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + }}; + + } else { + // frame from 4/3 to 16/9 display + transform = (mat4){{ + driver_view_ratio*(1080-2*bdr_s)/(1920-2*bdr_s), 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + }}; + } + return transform; +} void ui_nvg_init(UIState *s) { // init drawing -#ifdef QCOM - // on QCOM, we enable MSAA - s->vg = nvgCreate(0); -#else - s->vg = nvgCreate(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); -#endif + + // on EON, we enable MSAA + s->vg = Hardware::EON() ? nvgCreate(0) : nvgCreate(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); assert(s->vg); // init fonts @@ -516,19 +472,8 @@ void ui_nvg_init(UIState *s) { // init images std::vector> images = { - {"wheel", "../assets/img_chffr_wheel.png"}, - {"trafficSign_turn", "../assets/img_trafficSign_turn.png"}, - {"driver_face", "../assets/img_driver_face.png"}, - {"button_settings", "../assets/images/button_settings.png"}, - {"button_home", "../assets/images/button_home.png"}, - {"battery", "../assets/images/battery.png"}, - {"battery_charging", "../assets/images/battery_charging.png"}, - {"network_0", "../assets/images/network_0.png"}, - {"network_1", "../assets/images/network_1.png"}, - {"network_2", "../assets/images/network_2.png"}, - {"network_3", "../assets/images/network_3.png"}, - {"network_4", "../assets/images/network_4.png"}, - {"network_5", "../assets/images/network_5.png"}, + {"wheel", "../assets/img_chffr_wheel.png"}, + {"driver_face", "../assets/img_driver_face.png"}, }; for (auto [name, file] : images) { s->images[name] = nvgCreateImage(s->vg, file, 1); @@ -586,9 +531,17 @@ void ui_nvg_init(UIState *s) { glBindVertexArray(0); } + auto intrinsic_matrix = s->wide_camera ? ecam_intrinsic_matrix : fcam_intrinsic_matrix; + + s->zoom = zoom / intrinsic_matrix.v[0]; + + if (s->wide_camera) { + s->zoom *= 0.5; + } + s->video_rect = Rect{bdr_s, bdr_s, s->fb_w - 2 * bdr_s, s->fb_h - 2 * bdr_s}; - float zx = zoom * 2 * fcam_intrinsic_matrix.v[2] / s->video_rect.w; - float zy = zoom * 2 * fcam_intrinsic_matrix.v[5] / s->video_rect.h; + float zx = s->zoom * 2 * intrinsic_matrix.v[2] / s->video_rect.w; + float zy = s->zoom * 2 * intrinsic_matrix.v[5] / s->video_rect.h; const mat4 frame_transform = {{ zx, 0.0, 0.0, 0.0, @@ -597,7 +550,7 @@ void ui_nvg_init(UIState *s) { 0.0, 0.0, 0.0, 1.0, }}; - s->front_frame_mat = matmul(device_transform, driver_view_transform); + s->front_frame_mat = matmul(device_transform, get_driver_view_transform()); s->rear_frame_mat = matmul(device_transform, frame_transform); // Apply transformation such that video pixel coordinates match video @@ -605,10 +558,10 @@ void ui_nvg_init(UIState *s) { nvgTranslate(s->vg, s->video_rect.x + s->video_rect.w / 2, s->video_rect.y + s->video_rect.h / 2 + y_offset); // 2) Apply same scaling as video - nvgScale(s->vg, zoom, zoom); + nvgScale(s->vg, s->zoom, s->zoom); // 3) Put (0, 0) in top left corner of video - nvgTranslate(s->vg, -fcam_intrinsic_matrix.v[2], -fcam_intrinsic_matrix.v[5]); + nvgTranslate(s->vg, -intrinsic_matrix.v[2], -intrinsic_matrix.v[5]); nvgCurrentTransform(s->vg, s->car_space_transform); nvgResetTransform(s->vg); diff --git a/selfdrive/ui/paint.hpp b/selfdrive/ui/paint.h similarity index 85% rename from selfdrive/ui/paint.hpp rename to selfdrive/ui/paint.h index bc0927a71..b955a6163 100644 --- a/selfdrive/ui/paint.hpp +++ b/selfdrive/ui/paint.h @@ -1,7 +1,8 @@ #pragma once -#include "ui.hpp" -void ui_draw(UIState *s); +#include "selfdrive/ui/ui.h" + +void ui_draw(UIState *s, int w, int h); void ui_draw_image(const UIState *s, const Rect &r, const char *name, float alpha); void ui_draw_rect(NVGcontext *vg, const Rect &r, NVGcolor color, int width, float radius = 0); void ui_fill_rect(NVGcontext *vg, const Rect &r, const NVGpaint &paint, float radius = 0); diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc index 5522705c4..771af0fcf 100644 --- a/selfdrive/ui/qt/api.cc +++ b/selfdrive/ui/qt/api.cc @@ -1,3 +1,5 @@ +#include "selfdrive/ui/qt/api.h" + #include #include #include @@ -5,23 +7,20 @@ #include #include #include -#include -#include -#include #include +#include +#include +#include -#include "api.hpp" -#include "home.hpp" -#include "common/params.h" -#include "common/util.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" -#if defined(QCOM) || defined(QCOM2) -const std::string private_key_path = "/persist/comma/id_rsa"; -#else -const std::string private_key_path = util::getenv_default("HOME", "/.comma/persist/comma/id_rsa", "/persist/comma/id_rsa"); -#endif +const std::string private_key_path = + Hardware::PC() ? util::getenv_default("HOME", "/.comma/persist/comma/id_rsa", "/persist/comma/id_rsa") + : "/persist/comma/id_rsa"; -QByteArray CommaApi::rsa_sign(QByteArray data) { +QByteArray CommaApi::rsa_sign(const QByteArray &data) { auto file = QFile(private_key_path.c_str()); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "No RSA private key found, please run manager.py or registration.py"; @@ -45,7 +44,7 @@ QByteArray CommaApi::rsa_sign(QByteArray data) { return sig; } -QString CommaApi::create_jwt(QVector> payloads, int expiry) { +QString CommaApi::create_jwt(const QVector> &payloads, int expiry) { QString dongle_id = QString::fromStdString(Params().get("DongleId")); QJsonObject header; @@ -58,7 +57,7 @@ QString CommaApi::create_jwt(QVector> payloads, int e payload.insert("nbf", t); payload.insert("iat", t); payload.insert("exp", t + expiry); - for (auto load : payloads) { + for (auto &load : payloads) { payload.insert(load.first, load.second); } @@ -72,24 +71,17 @@ QString CommaApi::create_jwt(QVector> payloads, int e return jwt; } -QString CommaApi::create_jwt() { - return create_jwt(*(new QVector>())); -} -RequestRepeater::RequestRepeater(QWidget* parent, QString requestURL, int period_seconds, const QString &cache_key, QVector> payloads, bool disableWithScreen) - : disableWithScreen(disableWithScreen), cache_key(cache_key), QObject(parent) { +HttpRequest::HttpRequest(QObject *parent, const QString &requestURL, const QString &cache_key, bool create_jwt_) : cache_key(cache_key), create_jwt(create_jwt_), QObject(parent) { networkAccessManager = new QNetworkAccessManager(this); - reply = NULL; - QTimer* timer = new QTimer(this); - QObject::connect(timer, &QTimer::timeout, [=](){sendRequest(requestURL, payloads);}); - timer->start(period_seconds * 1000); - networkTimer = new QTimer(this); networkTimer->setSingleShot(true); networkTimer->setInterval(20000); - connect(networkTimer, SIGNAL(timeout()), this, SLOT(requestTimeout())); + connect(networkTimer, &QTimer::timeout, this, &HttpRequest::requestTimeout); + + sendRequest(requestURL); if (!cache_key.isEmpty()) { if (std::string cached_resp = Params().get(cache_key.toStdString()); !cached_resp.empty()) { @@ -98,49 +90,47 @@ RequestRepeater::RequestRepeater(QWidget* parent, QString requestURL, int period } } -void RequestRepeater::sendRequest(QString requestURL, QVector> payloads){ - if (GLWindow::ui_state.scene.started || !active || reply != NULL || - (!GLWindow::ui_state.awake && disableWithScreen)) { - return; +void HttpRequest::sendRequest(const QString &requestURL){ + QString token; + if(create_jwt) { + token = CommaApi::create_jwt(); + } else { + QString token_json = QString::fromStdString(util::read_file(util::getenv_default("HOME", "/.comma/auth.json", "/.comma/auth.json"))); + QJsonDocument json_d = QJsonDocument::fromJson(token_json.toUtf8()); + token = json_d["access_token"].toString(); } - QString token = CommaApi::create_jwt(payloads); QNetworkRequest request; request.setUrl(QUrl(requestURL)); request.setRawHeader(QByteArray("Authorization"), ("JWT " + token).toUtf8()); -#ifdef QCOM - QSslConfiguration ssl = QSslConfiguration::defaultConfiguration(); - ssl.setCaCertificates(QSslCertificate::fromPath("/usr/etc/tls/cert.pem", - QSsl::Pem, QRegExp::Wildcard)); - request.setSslConfiguration(ssl); -#endif - reply = networkAccessManager->get(request); networkTimer->start(); - connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); + connect(reply, &QNetworkReply::finished, this, &HttpRequest::requestFinished); } -void RequestRepeater::requestTimeout(){ +void HttpRequest::requestTimeout(){ reply->abort(); } // This function should always emit something -void RequestRepeater::requestFinished(){ +void HttpRequest::requestFinished(){ if (reply->error() != QNetworkReply::OperationCanceledError) { networkTimer->stop(); QString response = reply->readAll(); + 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()); } + qDebug() << reply->errorString(); emit failedResponse(reply->errorString()); } } else { diff --git a/selfdrive/ui/qt/api.h b/selfdrive/ui/qt/api.h new file mode 100644 index 000000000..71fd9b868 --- /dev/null +++ b/selfdrive/ui/qt/api.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class CommaApi : public QObject { + Q_OBJECT + +public: + static QByteArray rsa_sign(const QByteArray &data); + static QString create_jwt(const QVector> &payloads = {}, int expiry = 3600); +}; + +/** + * Makes a request to the request endpoint. + */ + +class HttpRequest : public QObject { + Q_OBJECT + +public: + explicit HttpRequest(QObject* parent, const QString &requestURL, const QString &cache_key = "", bool create_jwt_ = true); + QNetworkReply *reply; + void sendRequest(const QString &requestURL); + +private: + QNetworkAccessManager *networkAccessManager; + QTimer *networkTimer; + QString cache_key; + bool create_jwt; + +private slots: + void requestTimeout(); + void requestFinished(); + +signals: + void receivedResponse(const QString &response); + void failedResponse(const QString &errorString); + void timeoutResponse(const QString &errorString); +}; diff --git a/selfdrive/ui/qt/api.hpp b/selfdrive/ui/qt/api.hpp deleted file mode 100644 index 3772727be..000000000 --- a/selfdrive/ui/qt/api.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -class CommaApi : public QObject { - Q_OBJECT - -public: - static QByteArray rsa_sign(QByteArray data); - static QString create_jwt(QVector> payloads, int expiry=3600); - static QString create_jwt(); - -private: - QNetworkAccessManager* networkAccessManager; -}; - -/** - * Makes repeated requests to the request endpoint. - */ -class RequestRepeater : public QObject { - Q_OBJECT - -public: - explicit RequestRepeater(QWidget* parent, QString requestURL, int period = 10, const QString &cache_key = "", QVector> payloads = *(new QVector>()), bool disableWithScreen = true); - bool active = true; - -private: - bool disableWithScreen; - QNetworkReply* reply; - QNetworkAccessManager* networkAccessManager; - QTimer* networkTimer; - QString cache_key; - void sendRequest(QString requestURL, QVector> payloads); - -private slots: - void requestTimeout(); - void requestFinished(); - -signals: - void receivedResponse(QString response); - void failedResponse(QString errorString); - void timeoutResponse(QString errorString); -}; diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index fead4ae1b..18070e4e6 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -1,79 +1,73 @@ -#include -#include -#include -#include -#include +#include "selfdrive/ui/qt/home.h" #include #include #include #include -#include "common/util.h" -#include "common/params.h" -#include "common/timing.h" -#include "common/swaglog.h" -#include "common/watchdog.h" -#include "selfdrive/hardware/hw.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/common/util.h" +#include "selfdrive/ui/qt/widgets/drive_stats.h" +#include "selfdrive/ui/qt/widgets/setup.h" -#include "home.hpp" -#include "paint.hpp" -#include "qt_window.hpp" -#include "widgets/drive_stats.hpp" -#include "widgets/setup.hpp" - -#define BACKLIGHT_DT 0.25 -#define BACKLIGHT_TS 2.00 -#define BACKLIGHT_OFFROAD 50 - -// HomeWindow: the container for the offroad (OffroadHome) and onroad (GLWindow) UIs +// HomeWindow: the container for the offroad and onroad UIs HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { - layout = new QStackedLayout(); - layout->setStackingMode(QStackedLayout::StackAll); + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); - // onroad UI - glWindow = new GLWindow(this); - layout->addWidget(glWindow); + sidebar = new Sidebar(this); + layout->addWidget(sidebar); + QObject::connect(this, &HomeWindow::update, sidebar, &Sidebar::update); + QObject::connect(sidebar, &Sidebar::openSettings, this, &HomeWindow::openSettings); + + slayout = new QStackedLayout(); + layout->addLayout(slayout); + + onroad = new OnroadWindow(this); + slayout->addWidget(onroad); + QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::update); + QObject::connect(this, &HomeWindow::offroadTransitionSignal, onroad, &OnroadWindow::offroadTransition); - // draw offroad UI on top of onroad UI home = new OffroadHome(); - layout->addWidget(home); - - QObject::connect(glWindow, SIGNAL(offroadTransition(bool)), home, SLOT(setVisible(bool))); - QObject::connect(glWindow, SIGNAL(offroadTransition(bool)), this, SIGNAL(offroadTransition(bool))); - QObject::connect(glWindow, SIGNAL(screen_shutoff()), this, SIGNAL(closeSettings())); - QObject::connect(this, SIGNAL(openSettings()), home, SLOT(refresh())); + slayout->addWidget(home); + QObject::connect(this, &HomeWindow::openSettings, home, &OffroadHome::refresh); setLayout(layout); } +void HomeWindow::offroadTransition(bool offroad) { + if (offroad) { + slayout->setCurrentWidget(home); + } else { + slayout->setCurrentWidget(onroad); + } + sidebar->setVisible(offroad); + emit offroadTransitionSignal(offroad); +} + 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); + // TODO: make a nice driver view widget + if (QUIState::ui_state.scene.driver_view) { + Params().putBool("IsDriverViewEnabled", false); + QUIState::ui_state.scene.driver_view = false; return; } - glWindow->wake(); - - // Settings button click - if (!ui_state->sidebar_collapsed && settings_btn.ptInRect(e->x(), e->y())) { - emit openSettings(); - } - // Handle sidebar collapsing - if (ui_state->scene.started && (e->x() >= ui_state->viz_rect.x - bdr_s)) { - ui_state->sidebar_collapsed = !ui_state->sidebar_collapsed; + if (onroad->isVisible() && (!sidebar->isVisible() || e->x() > sidebar->width())) { + sidebar->setVisible(!sidebar->isVisible()); } } - // OffroadHome: the offroad home page -OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) { +OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { QVBoxLayout* main_layout = new QVBoxLayout(); - main_layout->setContentsMargins(sbr_w + 50, 50, 50, 50); + main_layout->setMargin(50); // top header QHBoxLayout* header_layout = new QHBoxLayout(); @@ -84,10 +78,10 @@ OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) { alert_notification = new QPushButton(); alert_notification->setVisible(false); - QObject::connect(alert_notification, SIGNAL(released()), this, SLOT(openAlerts())); + QObject::connect(alert_notification, &QPushButton::released, this, &OffroadHome::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); @@ -99,13 +93,13 @@ OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) { center_layout = new QStackedLayout(); QHBoxLayout* statsAndSetup = new QHBoxLayout(); + statsAndSetup->setMargin(0); DriveStats* drive = new DriveStats; drive->setFixedSize(800, 800); statsAndSetup->addWidget(drive); SetupWidget* setup = new SetupWidget; - //setup->setFixedSize(700, 700); statsAndSetup->addWidget(setup); QWidget* statsAndSetupWidget = new QWidget(); @@ -114,7 +108,7 @@ OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) { center_layout->addWidget(statsAndSetupWidget); alerts_widget = new OffroadAlert(); - QObject::connect(alerts_widget, SIGNAL(closeAlerts()), this, SLOT(closeAlerts())); + QObject::connect(alerts_widget, &OffroadAlert::closeAlerts, this, &OffroadHome::closeAlerts); center_layout->addWidget(alerts_widget); center_layout->setAlignment(alerts_widget, Qt::AlignCenter); @@ -122,18 +116,24 @@ OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) { // set up refresh timer timer = new QTimer(this); - QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh())); - refresh(); + QObject::connect(timer, &QTimer::timeout, this, &OffroadHome::refresh); timer->start(10 * 1000); setLayout(main_layout); setStyleSheet(R"( + OffroadHome { + background-color: black; + } * { color: white; } )"); } +void OffroadHome::showEvent(QShowEvent *event) { + refresh(); +} + void OffroadHome::openAlerts() { center_layout->setCurrentIndex(1); } @@ -153,7 +153,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 +162,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")); } @@ -187,148 +187,3 @@ void OffroadHome::refresh() { } alert_notification->setStyleSheet(style); } - - -// GLWindow: the onroad UI - -static void handle_display_state(UIState* s, bool user_input) { - static int awake_timeout = 0; - awake_timeout = std::max(awake_timeout - 1, 0); - - constexpr float accel_samples = 5*UI_FREQ; - static float accel_prev = 0., gyro_prev = 0.; - - bool should_wake = s->scene.started || s->scene.ignition || user_input; - if (!should_wake) { - // tap detection while display is off - bool accel_trigger = abs(s->scene.accel_sensor - accel_prev) > 0.2; - bool gyro_trigger = abs(s->scene.gyro_sensor - gyro_prev) > 0.15; - should_wake = accel_trigger && gyro_trigger; - gyro_prev = s->scene.gyro_sensor; - accel_prev = (accel_prev * (accel_samples - 1) + s->scene.accel_sensor) / accel_samples; - } - - if (should_wake) { - awake_timeout = 30 * UI_FREQ; - } else if (awake_timeout > 0) { - should_wake = true; - } - - // handle state transition - if (s->awake != should_wake) { - s->awake = should_wake; - Hardware::set_display_power(s->awake); - LOGD("setting display power %d", s->awake); - } -} - -GLWindow::GLWindow(QWidget* parent) : 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; -} - -GLWindow::~GLWindow() { - makeCurrent(); - doneCurrent(); -} - -void GLWindow::initializeGL() { - initializeOpenGLFunctions(); - std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; - std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl; - std::cout << "OpenGL renderer: " << glGetString(GL_RENDERER) << std::endl; - std::cout << "OpenGL language version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; - - ui_state.sound = &sound; - ui_state.fb_w = vwp_w; - ui_state.fb_h = vwp_h; - ui_init(&ui_state); - - wake(); - - prev_draw_t = millis_since_boot(); - timer->start(1000 / UI_FREQ); - backlight_timer->start(BACKLIGHT_DT * 1000); -} - -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; - if (!ui_state.awake) { - brightness = 0; - emit screen_shutoff(); - } - - if (brightness != last_brightness) { - std::thread{Hardware::set_brightness, brightness}.detach(); - } - last_brightness = brightness; -} - -void GLWindow::timerUpdate() { - // Connecting to visionIPC requires opengl to be current - if (!ui_state.vipc_client->connected){ - makeCurrent(); - } - - if (ui_state.scene.started != onroad) { - onroad = ui_state.scene.started; - emit offroadTransition(!onroad); - - // Change timeout to 0 when onroad, this will call timerUpdate continously. - // This puts visionIPC in charge of update frequency, reducing video latency - timer->start(onroad ? 0 : 1000 / UI_FREQ); - } - - handle_display_state(&ui_state, false); - - // scale volume with speed - sound.volume = util::map_val(ui_state.scene.car_state.getVEgo(), 0.f, 20.f, - Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); - - ui_update(&ui_state); - repaint(); - watchdog_kick(); -} - -void GLWindow::resizeGL(int w, int h) { - std::cout << "resize " << w << "x" << h << std::endl; -} - -void GLWindow::paintGL() { - if(GLWindow::ui_state.awake){ - ui_draw(&ui_state); - - double cur_draw_t = millis_since_boot(); - double dt = cur_draw_t - prev_draw_t; - if (dt > 66 && onroad && !ui_state.scene.driver_view) { - // warn on sub 15fps - LOGW("slow frame(%llu) time: %.2f", ui_state.sm->frame, dt); - } - prev_draw_t = cur_draw_t; - } -} - -void GLWindow::wake() { - handle_display_state(&ui_state, true); -} diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h new file mode 100644 index 000000000..bac2b2dc5 --- /dev/null +++ b/selfdrive/ui/qt/home.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "selfdrive/ui/qt/onroad.h" +#include "selfdrive/ui/qt/sidebar.h" +#include "selfdrive/ui/qt/widgets/offroad_alerts.h" +#include "selfdrive/ui/ui.h" + +class OffroadHome : public QFrame { + Q_OBJECT + +public: + explicit OffroadHome(QWidget* parent = 0); + +protected: + void showEvent(QShowEvent *event) override; + +private: + QTimer* timer; + + QLabel* date; + QStackedLayout* center_layout; + OffroadAlert* alerts_widget; + QPushButton* alert_notification; + +public slots: + void closeAlerts(); + void openAlerts(); + void refresh(); +}; + +class HomeWindow : public QWidget { + Q_OBJECT + +public: + explicit HomeWindow(QWidget* parent = 0); + +signals: + void openSettings(); + void closeSettings(); + + // forwarded signals + void displayPowerChanged(bool on); + void update(const UIState &s); + void offroadTransitionSignal(bool offroad); + +public slots: + void offroadTransition(bool offroad); + +protected: + void mousePressEvent(QMouseEvent* e) override; + +private: + Sidebar *sidebar; + OffroadHome *home; + OnroadWindow *onroad; + QStackedLayout *slayout; +}; diff --git a/selfdrive/ui/qt/home.hpp b/selfdrive/ui/qt/home.hpp deleted file mode 100644 index f5cf74cb0..000000000 --- a/selfdrive/ui/qt/home.hpp +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sound.hpp" -#include "ui/ui.hpp" -#include "widgets/offroad_alerts.hpp" - -// container window for onroad NVG UI -class GLWindow : public QOpenGLWidget, protected QOpenGLFunctions { - Q_OBJECT - -public: - using QOpenGLWidget::QOpenGLWidget; - explicit GLWindow(QWidget* parent = 0); - void wake(); - ~GLWindow(); - - inline static UIState ui_state = {0}; - -signals: - void offroadTransition(bool offroad); - void screen_shutoff(); - -protected: - void initializeGL() override; - void resizeGL(int w, int h) override; - void paintGL() override; - -private: - QTimer* timer; - QTimer* backlight_timer; - - Sound sound; - - bool onroad = true; - double prev_draw_t = 0; - - // 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; - -public slots: - void timerUpdate(); - void backlightUpdate(); -}; - -// offroad home screen -class OffroadHome : public QWidget { - Q_OBJECT - -public: - explicit OffroadHome(QWidget* parent = 0); - -private: - QTimer* timer; - - QLabel* date; - QStackedLayout* center_layout; - OffroadAlert* alerts_widget; - QPushButton* alert_notification; - -public slots: - void closeAlerts(); - void openAlerts(); - void refresh(); -}; - -class HomeWindow : public QWidget { - Q_OBJECT - -public: - explicit HomeWindow(QWidget* parent = 0); - GLWindow* glWindow; - -signals: - void openSettings(); - void closeSettings(); - void offroadTransition(bool offroad); - -protected: - void mousePressEvent(QMouseEvent* e) override; - -private: - OffroadHome* home; - QStackedLayout* layout; -}; diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index 2c9390634..dd3cd5ba5 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -1,15 +1,11 @@ +#include "networking.h" + #include #include #include #include -#include -#include -#include -#include "common/params.h" -#include "hardware/hw.h" -#include "networking.hpp" -#include "util.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" void clearLayout(QLayout* layout) { while (QLayoutItem* item = layout->takeAt(0)) { @@ -23,12 +19,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){ @@ -42,7 +32,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), s setLayout(s); QTimer* timer = new QTimer(this); - QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh())); + QObject::connect(timer, &QTimer::timeout, this, &Networking::refresh); timer->start(5000); attemptInitialization(); } @@ -55,25 +45,26 @@ void Networking::attemptInitialization(){ return; } - connect(wifi, SIGNAL(wrongPassword(QString)), this, SLOT(wrongPassword(QString))); + connect(wifi, &WifiManager::wrongPassword, this, &Networking::wrongPassword); QVBoxLayout* vlayout = new QVBoxLayout; 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); } - wifiWidget = new WifiUI(0, wifi); - connect(wifiWidget, SIGNAL(connectToNetwork(Network)), this, SLOT(connectToNetwork(Network))); - vlayout->addWidget(wifiWidget, 1); + wifiWidget = new WifiUI(this, wifi); + connect(wifiWidget, &WifiUI::connectToNetwork, this, &Networking::connectToNetwork); + vlayout->addWidget(new ScrollView(wifiWidget, this), 1); - wifiScreen = layoutToWidget(vlayout, this); + QWidget* wifiScreen = new QWidget(this); + wifiScreen->setLayout(vlayout); s->addWidget(wifiScreen); an = new AdvancedNetworking(this, wifi); @@ -138,6 +129,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 +138,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, &ToggleControl::toggleFlipped, this, &AdvancedNetworking::toggleTethering); 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 +163,7 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid vlayout->addWidget(horizontal_line(), 0); vlayout->addWidget(new SshControl()); + vlayout->addStretch(1); setLayout(vlayout); } @@ -218,7 +194,6 @@ WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) vlayout->setSpacing(25); setLayout(vlayout); - page = 0; } void WifiUI::refresh() { @@ -227,72 +202,42 @@ void WifiUI::refresh() { clearLayout(vlayout); 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; + QObject::connect(connectButtons, qOverload(&QButtonGroup::buttonClicked), this, &WifiUI::handleButton); 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) + "…"; - } + hlayout->addSpacing(50); - 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); + 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); + // 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); + // 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); + 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); - } + 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 +245,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.h similarity index 80% rename from selfdrive/ui/qt/offroad/networking.hpp rename to selfdrive/ui/qt/offroad/networking.h index fba770507..9fa1cfe88 100644 --- a/selfdrive/ui/qt/offroad/networking.hpp +++ b/selfdrive/ui/qt/offroad/networking.h @@ -1,21 +1,20 @@ #pragma once -#include #include -#include -#include #include +#include +#include +#include -#include "wifiManager.hpp" -#include "widgets/input.hpp" -#include "widgets/ssh_keys.hpp" -#include "widgets/toggle.hpp" +#include "selfdrive/ui/qt/offroad/wifiManager.h" +#include "selfdrive/ui/qt/widgets/input.h" +#include "selfdrive/ui/qt/widgets/ssh_keys.h" +#include "selfdrive/ui/qt/widgets/toggle.h" 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 f9f8972b8..8ce48becd 100644 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ b/selfdrive/ui/qt/offroad/onboarding.cc @@ -1,15 +1,15 @@ +#include "onboarding.h" + +#include #include #include -#include -#include #include -#include - -#include "common/params.h" -#include "onboarding.hpp" -#include "home.hpp" -#include "util.h" +#include +#include +#include "selfdrive/common/params.h" +#include "selfdrive/common/util.h" +#include "selfdrive/ui/qt/home.h" void TrainingGuide::mouseReleaseEvent(QMouseEvent *e) { QPoint touch = QPoint(e->x(), e->y()) - imageCorner; @@ -50,7 +50,12 @@ void TrainingGuide::paintEvent(QPaintEvent *event) { imageCorner = rect.topLeft(); } -TermsPage::TermsPage(QWidget *parent) : QFrame(parent){ +void TermsPage::showEvent(QShowEvent *event) { + // late init, building QML widget takes 200ms + if (layout()) { + return; + } + QVBoxLayout *main_layout = new QVBoxLayout; main_layout->setMargin(40); main_layout->setSpacing(40); @@ -61,15 +66,17 @@ TermsPage::TermsPage(QWidget *parent) : QFrame(parent){ text->setAttribute(Qt::WA_AlwaysStackOnTop); text->setClearColor(Qt::transparent); - text->rootContext()->setContextProperty("font_size", 55); - QString text_view = util::read_file("../assets/offroad/tc.html").c_str(); text->rootContext()->setContextProperty("text_view", text_view); + text->rootContext()->setContextProperty("font_size", 55); text->setSource(QUrl::fromLocalFile("qt/offroad/text_view.qml")); main_layout->addWidget(text); + QObject *obj = (QObject*)text->rootObject(); + QObject::connect(obj, SIGNAL(qmlSignal()), SLOT(enableAccept())); + // TODO: add decline page QHBoxLayout* buttons = new QHBoxLayout; main_layout->addLayout(buttons); @@ -80,19 +87,13 @@ TermsPage::TermsPage(QWidget *parent) : QFrame(parent){ accept_btn = new QPushButton("Scroll to accept"); accept_btn->setEnabled(false); buttons->addWidget(accept_btn); - QObject::connect(accept_btn, &QPushButton::released, [=]() { - emit acceptedTerms(); - }); + QObject::connect(accept_btn, &QPushButton::released, this, &TermsPage::acceptedTerms); - QObject *obj = (QObject*)text->rootObject(); - QObject::connect(obj, SIGNAL(qmlSignal()), SLOT(enableAccept())); setLayout(main_layout); setStyleSheet(R"( - * { - font-size: 50px; - } QPushButton { padding: 50px; + font-size: 50px; border-radius: 10px; background-color: #292929; } @@ -127,18 +128,17 @@ 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); - setStyleSheet(R"( * { color: white; diff --git a/selfdrive/ui/qt/offroad/onboarding.hpp b/selfdrive/ui/qt/offroad/onboarding.h similarity index 93% rename from selfdrive/ui/qt/offroad/onboarding.hpp rename to selfdrive/ui/qt/offroad/onboarding.h index 227090fd3..987fad336 100644 --- a/selfdrive/ui/qt/offroad/onboarding.hpp +++ b/selfdrive/ui/qt/offroad/onboarding.h @@ -1,11 +1,11 @@ #pragma once -#include -#include -#include +#include #include #include -#include +#include +#include +#include #include "selfdrive/common/params.h" @@ -57,7 +57,10 @@ class TermsPage : public QFrame { Q_OBJECT public: - explicit TermsPage(QWidget *parent = 0); + explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {}; + +protected: + void showEvent(QShowEvent *event) override; private: QPushButton *accept_btn; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 8abaeb7ba..06c3a3671 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -1,72 +1,99 @@ -#include +#include "settings.h" + +#include #include #include -#include +#include #ifndef QCOM -#include "networking.hpp" +#include "selfdrive/ui/qt/offroad/networking.h" #endif -#include "settings.hpp" -#include "widgets/input.hpp" -#include "widgets/toggle.hpp" -#include "widgets/offroad_alerts.hpp" -#include "widgets/controls.hpp" -#include "widgets/ssh_keys.hpp" -#include "common/params.h" -#include "common/util.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/util.h" #include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/qt/widgets/controls.h" +#include "selfdrive/ui/qt/widgets/input.h" +#include "selfdrive/ui/qt/widgets/offroad_alerts.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" +#include "selfdrive/ui/qt/widgets/ssh_keys.h" +#include "selfdrive/ui/qt/widgets/toggle.h" +#include "selfdrive/ui/ui.h" - -QWidget * toggles_panel() { +TogglesPanel::TogglesPanel(QWidget *parent) : QWidget(parent) { QVBoxLayout *toggles_list = new QVBoxLayout(); - 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.", - "../assets/offroad/icon_openpilot.png" - )); - toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamControl("IsLdwEnabled", - "Enable Lane Departure Warnings", - "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31mph (50kph).", - "../assets/offroad/icon_warning.png" - )); - toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamControl("IsRHD", - "Enable Right-Hand Drive", - "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", - "../assets/offroad/icon_openpilot_mirrored.png" - )); - toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamControl("IsMetric", - "Use Metric System", - "Display speed in km/h instead of mp/h.", - "../assets/offroad/icon_metric.png" - )); - toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamControl("CommunityFeaturesToggle", - "Enable Community Features", - "Use features from the open source community that are not maintained or supported by comma.ai and have not been confirmed to meet the standard safety model. These features include community supported cars and community supported hardware. Be extra cautious when using these features", - "../assets/offroad/icon_shell.png" - )); - toggles_list->addWidget(horizontal_line()); - ParamControl *record_toggle = new ParamControl("RecordFront", - "Record and Upload Driver Camera", - "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", - "../assets/offroad/icon_network.png"); - toggles_list->addWidget(record_toggle); - toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ParamControl("EndToEndToggle", - "\U0001f96c Disable use of lanelines (Alpha) \U0001f96c", - "In this mode openpilot will ignore lanelines and just drive how it thinks a human would.", - "../assets/offroad/icon_road.png")); + QList toggles; - bool record_lock = Params().read_db_bool("RecordFrontLock"); + toggles.append(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.", + "../assets/offroad/icon_openpilot.png", + this)); + toggles.append(new ParamControl("IsLdwEnabled", + "Enable Lane Departure Warnings", + "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31mph (50kph).", + "../assets/offroad/icon_warning.png", + this)); + toggles.append(new ParamControl("IsRHD", + "Enable Right-Hand Drive", + "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", + "../assets/offroad/icon_openpilot_mirrored.png", + this)); + toggles.append(new ParamControl("IsMetric", + "Use Metric System", + "Display speed in km/h instead of mp/h.", + "../assets/offroad/icon_metric.png", + this)); + toggles.append(new ParamControl("CommunityFeaturesToggle", + "Enable Community Features", + "Use features from the open source community that are not maintained or supported by comma.ai and have not been confirmed to meet the standard safety model. These features include community supported cars and community supported hardware. Be extra cautious when using these features", + "../assets/offroad/icon_shell.png", + this)); + + if (!Hardware::TICI()) { + toggles.append(new ParamControl("IsUploadRawEnabled", + "Upload Raw Logs", + "Upload full logs and full resolution video by default while on WiFi. If not enabled, individual logs can be marked for upload at my.comma.ai/useradmin.", + "../assets/offroad/icon_network.png", + this)); + } + + ParamControl *record_toggle = new ParamControl("RecordFront", + "Record and Upload Driver Camera", + "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", + "../assets/offroad/icon_monitoring.png", + this); + toggles.append(record_toggle); + toggles.append(new ParamControl("EndToEndToggle", + "\U0001f96c Disable use of lanelines (Alpha) \U0001f96c", + "In this mode openpilot will ignore lanelines and just drive how it thinks a human would.", + "../assets/offroad/icon_road.png", + this)); + + if (Hardware::TICI()) { + toggles.append(new ParamControl("EnableWideCamera", + "Enable use of Wide Angle Camera", + "Use wide angle camera for driving and ui. Only takes effect after reboot.", + "../assets/offroad/icon_openpilot.png", + this)); + toggles.append(new ParamControl("EnableLteOnroad", + "Enable LTE while onroad", + "", + "../assets/offroad/icon_network.png", + this)); + } + + bool record_lock = Params().getBool("RecordFrontLock"); record_toggle->setEnabled(!record_lock); - QWidget *widget = new QWidget; - widget->setLayout(toggles_list); - return widget; + for(ParamControl *toggle : toggles){ + if(toggles_list->count() != 0){ + toggles_list->addWidget(horizontal_line()); + } + toggles_list->addWidget(toggle); + } + + setLayout(toggles_list); } DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { @@ -85,30 +112,55 @@ DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { QList offroad_btns; 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().write_db_value("IsDriverViewEnabled", "1", 1); })); + "Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off)", + [=]() { + Params().putBool("IsDriverViewEnabled", true); + QUIState::ui_state.scene.driver_view = true; + }, "", this)); - 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().delete_db_value("CalibrationParams"); + QString resetCalibDesc = "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."; + ButtonControl *resetCalibBtn = new ButtonControl("Reset Calibration", "RESET", resetCalibDesc, [=]() { + if (ConfirmationDialog::confirm("Are you sure you want to reset calibration?", this)) { + Params().remove("CalibrationParams"); } - })); + }, "", this); + connect(resetCalibBtn, &ButtonControl::showDescription, [=]() { + QString desc = resetCalibDesc; + std::string calib_bytes = Params().get("CalibrationParams"); + if (!calib_bytes.empty()) { + try { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(calib_bytes.data(), calib_bytes.size())); + auto calib = cmsg.getRoot().getLiveCalibration(); + if (calib.getCalStatus() != 0) { + double pitch = calib.getRpyCalib()[1] * (180 / M_PI); + double yaw = calib.getRpyCalib()[2] * (180 / M_PI); + desc += QString(" Your device is pointed %1° %2 and %3° %4.") + .arg(QString::number(std::abs(pitch), 'g', 1), pitch > 0 ? "up" : "down", + QString::number(std::abs(yaw), 'g', 1), yaw > 0 ? "right" : "left"); + } + } catch (kj::Exception) { + qInfo() << "invalid CalibrationParams"; + } + } + resetCalibBtn->setDescription(desc); + }); + offroad_btns.append(resetCalibBtn); 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().delete_db_value("CompletedTrainingVersion"); + if (ConfirmationDialog::confirm("Are you sure you want to review the training guide?", this)) { + Params().remove("CompletedTrainingVersion"); emit reviewTrainingGuide(); } - })); + }, "", this)); - QString brand = params.read_db_bool("Passive") ? "dashcam" : "openpilot"; + 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().write_db_value("DoUninstall", "1"); + if (ConfirmationDialog::confirm("Are you sure you want to uninstall?", this)) { + Params().putBool("DoUninstall", true); } - })); + }, "", this)); for(auto &btn : offroad_btns){ device_layout->addWidget(horizontal_line()); @@ -123,7 +175,7 @@ DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { QPushButton *reboot_btn = new QPushButton("Reboot"); power_layout->addWidget(reboot_btn); QObject::connect(reboot_btn, &QPushButton::released, [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to reboot?")) { + if (ConfirmationDialog::confirm("Are you sure you want to reboot?", this)) { Hardware::reboot(); } }); @@ -132,7 +184,7 @@ DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) { poweroff_btn->setStyleSheet("background-color: #E22C2C;"); power_layout->addWidget(poweroff_btn); QObject::connect(poweroff_btn, &QPushButton::released, [=]() { - if (ConfirmationDialog::confirm("Are you sure you want to power off?")) { + if (ConfirmationDialog::confirm("Are you sure you want to power off?", this)) { Hardware::poweroff(); } }); @@ -158,7 +210,7 @@ DeveloperPanel::DeveloperPanel(QWidget* parent) : QFrame(parent) { 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).substr(0, 14)}, {"Git Branch", params.get("GitBranch", false)}, @@ -211,7 +263,13 @@ QWidget * network_panel(QWidget * parent) { return w; } -SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { +void SettingsWindow::showEvent(QShowEvent *event) { + if (layout()) { + panel_widget->setCurrentIndex(0); + nav_btns->buttons()[0]->setChecked(true); + return; + } + // setup two main layouts QVBoxLayout *sidebar_layout = new QVBoxLayout(); sidebar_layout->setMargin(0); @@ -233,16 +291,16 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { close_btn->setFixedSize(200, 200); sidebar_layout->addSpacing(45); sidebar_layout->addWidget(close_btn, 0, Qt::AlignCenter); - QObject::connect(close_btn, SIGNAL(released()), this, SIGNAL(closeSettings())); + QObject::connect(close_btn, &QPushButton::released, this, &SettingsWindow::closeSettings); // setup panels DevicePanel *device = new DevicePanel(this); - QObject::connect(device, SIGNAL(reviewTrainingGuide()), this, SIGNAL(reviewTrainingGuide())); + QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); QPair panels[] = { {"Device", device}, {"Network", network_panel(this)}, - {"Toggles", toggles_panel()}, + {"Toggles", new TogglesPanel(this)}, {"Developer", new DeveloperPanel()}, }; @@ -251,6 +309,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { for (auto &[name, panel] : panels) { QPushButton *btn = new QPushButton(name); btn->setCheckable(true); + btn->setChecked(nav_btns->buttons().size() == 0); btn->setStyleSheet(R"( QPushButton { color: grey; @@ -270,28 +329,14 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { sidebar_layout->addWidget(btn, 0, Qt::AlignRight); 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); + ScrollView *panel_frame = new ScrollView(panel, this); panel_widget->addWidget(panel_frame); QObject::connect(btn, &QPushButton::released, [=, w = panel_frame]() { panel_widget->setCurrentWidget(w); }); } - qobject_cast(nav_btns->buttons()[0])->setChecked(true); sidebar_layout->setContentsMargins(50, 50, 100, 50); // main settings layout, sidebar + main panel @@ -314,3 +359,17 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { } )"); } + +void SettingsWindow::hideEvent(QHideEvent *event){ +#ifdef QCOM + HardwareEon::close_activities(); +#endif + + // TODO: this should be handled by the Dialog classes + QList children = findChildren(); + for(auto &w : children){ + if(w->metaObject()->superClass()->className() == QString("QDialog")){ + w->close(); + } + } +} diff --git a/selfdrive/ui/qt/offroad/settings.hpp b/selfdrive/ui/qt/offroad/settings.h similarity index 74% rename from selfdrive/ui/qt/offroad/settings.hpp rename to selfdrive/ui/qt/offroad/settings.h index 2dee5b62d..09a907c8e 100644 --- a/selfdrive/ui/qt/offroad/settings.hpp +++ b/selfdrive/ui/qt/offroad/settings.h @@ -1,15 +1,15 @@ #pragma once -#include +#include #include -#include #include #include -#include #include #include +#include +#include -#include "selfdrive/ui/qt/widgets/controls.hpp" +#include "selfdrive/ui/qt/widgets/controls.h" // ********** settings window + top-level panels ********** @@ -21,6 +21,12 @@ signals: void reviewTrainingGuide(); }; +class TogglesPanel : public QWidget { + Q_OBJECT +public: + explicit TogglesPanel(QWidget *parent = nullptr); +}; + class DeveloperPanel : public QFrame { Q_OBJECT public: @@ -35,7 +41,11 @@ class SettingsWindow : public QFrame { Q_OBJECT public: - explicit SettingsWindow(QWidget *parent = 0); + explicit SettingsWindow(QWidget *parent = 0) : QFrame(parent) {}; + +protected: + void hideEvent(QHideEvent *event); + void showEvent(QShowEvent *event); signals: void closeSettings(); diff --git a/selfdrive/ui/qt/offroad/wifiManager.cc b/selfdrive/ui/qt/offroad/wifiManager.cc index 8caf6f6d7..d7ff5bddb 100644 --- a/selfdrive/ui/qt/offroad/wifiManager.cc +++ b/selfdrive/ui/qt/offroad/wifiManager.cc @@ -1,11 +1,13 @@ -#include -#include -#include -#include +#include "wifiManager.h" -#include "common/params.h" -#include "common/swaglog.h" -#include "wifiManager.hpp" +#include + +#include +#include +#include + +#include "selfdrive/common/params.h" +#include "selfdrive/common/swaglog.h" /** * We are using a NetworkManager DBUS API : https://developer.gnome.org/NetworkManager/1.26/spec.html diff --git a/selfdrive/ui/qt/offroad/wifiManager.hpp b/selfdrive/ui/qt/offroad/wifiManager.h similarity index 100% rename from selfdrive/ui/qt/offroad/wifiManager.hpp rename to selfdrive/ui/qt/offroad/wifiManager.h diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc new file mode 100644 index 000000000..c285c0728 --- /dev/null +++ b/selfdrive/ui/qt/onroad.cc @@ -0,0 +1,206 @@ +#include "selfdrive/ui/qt/onroad.h" + +#include + +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/timing.h" +#include "selfdrive/ui/paint.h" +#include "selfdrive/ui/qt/util.h" + +OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { + layout = new QStackedLayout(); + layout->setStackingMode(QStackedLayout::StackAll); + + // old UI on bottom + nvg = new NvgWindow(this); + layout->addWidget(nvg); + QObject::connect(this, &OnroadWindow::update, nvg, &NvgWindow::update); + + alerts = new OnroadAlerts(this); + QObject::connect(this, &OnroadWindow::update, alerts, &OnroadAlerts::updateState); + QObject::connect(this, &OnroadWindow::offroadTransition, alerts, &OnroadAlerts::offroadTransition); + layout->addWidget(alerts); + + // setup stacking order + alerts->raise(); + + setLayout(layout); + setAttribute(Qt::WA_OpaquePaintEvent); +} + +// ***** onroad widgets ***** + +OnroadAlerts::OnroadAlerts(QWidget *parent) : QWidget(parent) { + for (auto &kv : sound_map) { + auto path = QUrl::fromLocalFile(kv.second.first); + sounds[kv.first].setSource(path); + } +} + +void OnroadAlerts::updateState(const UIState &s) { + SubMaster &sm = *(s.sm); + if (sm.updated("carState")) { + // scale volume with speed + volume = util::map_val(sm["carState"].getCarState().getVEgo(), 0.f, 20.f, + Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); + } + if (s.scene.deviceState.getStarted()) { + if (sm.updated("controlsState")) { + const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState(); + updateAlert(QString::fromStdString(cs.getAlertText1()), QString::fromStdString(cs.getAlertText2()), + cs.getAlertBlinkingRate(), cs.getAlertType(), cs.getAlertSize(), cs.getAlertSound()); + } else if ((sm.frame - s.scene.started_frame) > 10 * UI_FREQ) { + // Handle controls timeout + if (sm.rcv_frame("controlsState") < s.scene.started_frame) { + // car is started, but controlsState hasn't been seen at all + updateAlert("openpilot Unavailable", "Waiting for controls to start", 0, + "controlsWaiting", cereal::ControlsState::AlertSize::MID, AudibleAlert::NONE); + } else if ((sm.frame - sm.rcv_frame("controlsState")) > 5 * UI_FREQ) { + // car is started, but controls is lagging or died + updateAlert("TAKE CONTROL IMMEDIATELY", "Controls Unresponsive", 0, + "controlsUnresponsive", cereal::ControlsState::AlertSize::FULL, AudibleAlert::CHIME_WARNING_REPEAT); + + // TODO: clean this up once Qt handles the border + QUIState::ui_state.status = STATUS_ALERT; + } + } + } + + // TODO: add blinking back if performant + //float alpha = 0.375 * cos((millis_since_boot() / 1000) * 2 * M_PI * blinking_rate) + 0.625; + auto c = bg_colors[s.status]; + bg.setRgbF(c.r, c.g, c.b, c.a); +} + +void OnroadAlerts::offroadTransition(bool offroad) { + updateAlert("", "", 0, "", cereal::ControlsState::AlertSize::NONE, AudibleAlert::NONE); +} + +void OnroadAlerts::updateAlert(const QString &t1, const QString &t2, float blink_rate, + const std::string &type, cereal::ControlsState::AlertSize size, AudibleAlert sound) { + if (alert_type.compare(type) == 0 && text1.compare(t1) == 0) { + return; + } + + stopSounds(); + if (sound != AudibleAlert::NONE) { + playSound(sound); + } + + text1 = t1; + text2 = t2; + alert_type = type; + alert_size = size; + blinking_rate = blink_rate; + + update(); +} + +void OnroadAlerts::playSound(AudibleAlert alert) { + int loops = sound_map[alert].second ? QSoundEffect::Infinite : 0; + sounds[alert].setLoopCount(loops); + sounds[alert].setVolume(volume); + sounds[alert].play(); +} + +void OnroadAlerts::stopSounds() { + for (auto &kv : sounds) { + // Only stop repeating sounds + if (kv.second.loopsRemaining() == QSoundEffect::Infinite) { + kv.second.stop(); + } + } +} + +void OnroadAlerts::paintEvent(QPaintEvent *event) { + QPainter p(this); + + if (alert_size == cereal::ControlsState::AlertSize::NONE) { + return; + } + static std::map alert_sizes = { + {cereal::ControlsState::AlertSize::SMALL, 271}, + {cereal::ControlsState::AlertSize::MID, 420}, + {cereal::ControlsState::AlertSize::FULL, height()}, + }; + int h = alert_sizes[alert_size]; + QRect r = QRect(0, height() - h, width(), h); + + // draw background + gradient + p.setPen(Qt::NoPen); + p.setCompositionMode(QPainter::CompositionMode_DestinationOver); + + p.setBrush(QBrush(bg)); + p.drawRect(r); + + QLinearGradient g(0, r.y(), 0, r.bottom()); + g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); + g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); + p.setBrush(QBrush(g)); + p.fillRect(r, g); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + + // remove bottom border + r = QRect(0, height() - h, width(), h - 30); + + // text + const QPoint c = r.center(); + p.setPen(QColor(0xff, 0xff, 0xff)); + p.setRenderHint(QPainter::TextAntialiasing); + if (alert_size == cereal::ControlsState::AlertSize::SMALL) { + configFont(p, "Open Sans", 74, "SemiBold"); + p.drawText(r, Qt::AlignCenter, text1); + } else if (alert_size == cereal::ControlsState::AlertSize::MID) { + configFont(p, "Open Sans", 88, "Bold"); + p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, text1); + configFont(p, "Open Sans", 66, "Regular"); + p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, text2); + } else if (alert_size == cereal::ControlsState::AlertSize::FULL) { + bool l = text1.length() > 15; + configFont(p, "Open Sans", l ? 132 : 177, "Bold"); + p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, text1); + configFont(p, "Open Sans", 88, "Regular"); + p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, text2); + } +} + + +NvgWindow::NvgWindow(QWidget *parent) : QOpenGLWidget(parent) { + setAttribute(Qt::WA_OpaquePaintEvent); +} + +NvgWindow::~NvgWindow() { + makeCurrent(); + doneCurrent(); +} + +void NvgWindow::initializeGL() { + initializeOpenGLFunctions(); + std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; + std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl; + std::cout << "OpenGL renderer: " << glGetString(GL_RENDERER) << std::endl; + std::cout << "OpenGL language version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; + + ui_nvg_init(&QUIState::ui_state); + prev_draw_t = millis_since_boot(); +} + +void NvgWindow::update(const UIState &s) { + // Connecting to visionIPC requires opengl to be current + if (s.vipc_client->connected){ + makeCurrent(); + } + repaint(); +} + +void NvgWindow::paintGL() { + ui_draw(&QUIState::ui_state, width(), height()); + + double cur_draw_t = millis_since_boot(); + double dt = cur_draw_t - prev_draw_t; + if (dt > 66 && !QUIState::ui_state.scene.driver_view) { + // warn on sub 15fps + LOGW("slow frame time: %.2f", dt); + } + prev_draw_t = cur_draw_t; +} diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h new file mode 100644 index 000000000..9e93164e5 --- /dev/null +++ b/selfdrive/ui/qt/onroad.h @@ -0,0 +1,92 @@ +#pragma once + +#include + +#include +#include + +#include "cereal/gen/cpp/log.capnp.h" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/qt_window.h" + +typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; + +// ***** onroad widgets ***** + +class OnroadAlerts : public QWidget { + Q_OBJECT + +public: + OnroadAlerts(QWidget *parent = 0); + +protected: + void paintEvent(QPaintEvent*) override; + +private: + void stopSounds(); + void playSound(AudibleAlert alert); + void updateAlert(const QString &t1, const QString &t2, float blink_rate, + const std::string &type, cereal::ControlsState::AlertSize size, AudibleAlert sound); + + std::map> sound_map { + // AudibleAlert, (file path, inf loop) + {AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", false}}, + {AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", false}}, + {AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", false}}, + {AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", false}}, + {AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", true}}, + {AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", true}}, + {AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", false}}, + {AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", false}} + }; + + QColor bg; + float volume = Hardware::MIN_VOLUME; + std::map sounds; + float blinking_rate = 0; + QString text1, text2; + std::string alert_type; + cereal::ControlsState::AlertSize alert_size; + +public slots: + void updateState(const UIState &s); + void offroadTransition(bool offroad); +}; + +// container window for the NVG UI +class NvgWindow : public QOpenGLWidget, protected QOpenGLFunctions { + Q_OBJECT + +public: + using QOpenGLWidget::QOpenGLWidget; + explicit NvgWindow(QWidget* parent = 0); + ~NvgWindow(); + +protected: + void paintGL() override; + void initializeGL() override; + +private: + double prev_draw_t = 0; + +public slots: + void update(const UIState &s); +}; + +// container for all onroad widgets +class OnroadWindow : public QWidget { + Q_OBJECT + +public: + OnroadWindow(QWidget* parent = 0); + +private: + OnroadAlerts *alerts; + NvgWindow *nvg; + QStackedLayout *layout; + +signals: + void update(const UIState &s); + void offroadTransition(bool offroad); +}; diff --git a/selfdrive/ui/qt/qt_window.hpp b/selfdrive/ui/qt/qt_window.h similarity index 85% rename from selfdrive/ui/qt/qt_window.hpp rename to selfdrive/ui/qt/qt_window.h index 2e02ec30c..295ab083f 100644 --- a/selfdrive/ui/qt/qt_window.hpp +++ b/selfdrive/ui/qt/qt_window.h @@ -1,20 +1,20 @@ +#pragma once + #include -#include #include +#include #ifdef QCOM2 #include -#include #include +#include #endif +#include "selfdrive/hardware/hw.h" -#ifdef QCOM2 - const int vwp_w = 2160, vwp_h = 1080; -#else - const int vwp_w = 1920, vwp_h = 1080; -#endif +const int vwp_w = Hardware::TICI() ? 2160 : 1920; +const int vwp_h = 1080; inline void setMainWindow(QWidget *w) { const float scale = getenv("SCALE") != NULL ? std::stof(getenv("SCALE")) : 1.0; diff --git a/selfdrive/ui/qt/request_repeater.cc b/selfdrive/ui/qt/request_repeater.cc new file mode 100644 index 000000000..ee6680cc7 --- /dev/null +++ b/selfdrive/ui/qt/request_repeater.cc @@ -0,0 +1,13 @@ +#include "request_repeater.h" + +RequestRepeater::RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey, + int period) : HttpRequest(parent, requestURL, cacheKey) { + timer = new QTimer(this); + timer->setTimerType(Qt::VeryCoarseTimer); + QObject::connect(timer, &QTimer::timeout, [=](){ + if (!QUIState::ui_state.scene.started && QUIState::ui_state.awake && reply == NULL) { + sendRequest(requestURL); + } + }); + timer->start(period * 1000); +} diff --git a/selfdrive/ui/qt/request_repeater.h b/selfdrive/ui/qt/request_repeater.h new file mode 100644 index 000000000..c23bbbcf1 --- /dev/null +++ b/selfdrive/ui/qt/request_repeater.h @@ -0,0 +1,12 @@ +#pragma once + +#include "selfdrive/ui/qt/api.h" +#include "selfdrive/ui/ui.h" + +class RequestRepeater : public HttpRequest { +public: + RequestRepeater(QObject *parent, const QString &requestURL, const QString &cacheKey = "", int period = 0); + +private: + QTimer *timer; +}; diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc new file mode 100644 index 000000000..cf1319a70 --- /dev/null +++ b/selfdrive/ui/qt/sidebar.cc @@ -0,0 +1,113 @@ +#include "selfdrive/ui/qt/sidebar.h" + +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/common/util.h" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/qt/util.h" + +void Sidebar::drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y) { + const QRect rect = {30, y, 240, val.isEmpty() ? (label.contains("\n") ? 124 : 100) : 148}; + + p.setPen(Qt::NoPen); + p.setBrush(QBrush(c)); + p.setClipRect(rect.x() + 6, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip); + p.drawRoundedRect(QRect(rect.x() + 6, rect.y() + 6, 100, rect.height() - 12), 10, 10); + p.setClipping(false); + + QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55)); + pen.setWidth(2); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawRoundedRect(rect, 20, 20); + + p.setPen(QColor(0xff, 0xff, 0xff)); + if (val.isEmpty()) { + configFont(p, "Open Sans", 35, "Bold"); + const QRect r = QRect(rect.x() + 35, rect.y(), rect.width() - 50, rect.height()); + p.drawText(r, Qt::AlignCenter, label); + } else { + configFont(p, "Open Sans", 58, "Bold"); + p.drawText(rect.x() + 50, rect.y() + 71, val); + configFont(p, "Open Sans", 35, "Regular"); + p.drawText(rect.x() + 50, rect.y() + 50 + 77, label); + } +} + +Sidebar::Sidebar(QWidget *parent) : QFrame(parent) { + home_img = QImage("../assets/images/button_home.png").scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation); + settings_img = QImage("../assets/images/button_settings.png").scaled(settings_btn.width(), settings_btn.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);; + + setFixedWidth(300); + setMinimumHeight(vwp_h); + setStyleSheet("background-color: rgb(57, 57, 57);"); +} + +void Sidebar::mousePressEvent(QMouseEvent *event) { + if (settings_btn.contains(event->pos())) { + emit openSettings(); + } +} + +void Sidebar::update(const UIState &s) { + if (s.sm->frame % (6*UI_FREQ) == 0) { + connect_str = "OFFLINE"; + connect_status = warning_color; + auto last_ping = params.get("LastAthenaPingTime"); + if (last_ping) { + bool online = nanos_since_boot() - *last_ping < 70e9; + connect_str = online ? "ONLINE" : "ERROR"; + connect_status = online ? good_color : danger_color; + } + repaint(); + } + + net_type = s.scene.deviceState.getNetworkType(); + strength = s.scene.deviceState.getNetworkStrength(); + + temp_status = danger_color; + auto ts = s.scene.deviceState.getThermalStatus(); + if (ts == cereal::DeviceState::ThermalStatus::GREEN) { + temp_status = good_color; + } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { + temp_status = warning_color; + } + temp_val = (int)s.scene.deviceState.getAmbientTempC(); + + panda_str = "VEHICLE\nONLINE"; + panda_status = good_color; + if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) { + panda_status = danger_color; + panda_str = "NO\nPANDA"; + } else if (Hardware::TICI() && s.scene.started) { + panda_str = QString("SAT CNT\n%1").arg(s.scene.satelliteCount); + panda_status = s.scene.gpsOK ? good_color : warning_color; + } + + if (s.sm->updated("deviceState") || s.sm->updated("pandaState")) { + repaint(); + } +} + +void Sidebar::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.setPen(Qt::NoPen); + p.setRenderHint(QPainter::Antialiasing); + + // static imgs + p.setOpacity(0.65); + p.drawImage(settings_btn.x(), settings_btn.y(), settings_img); + p.setOpacity(1.0); + p.drawImage(60, 1080 - 180 - 40, home_img); + + // network + p.drawImage(58, 196, signal_imgs[strength]); + configFont(p, "Open Sans", 35, "Regular"); + p.setPen(QColor(0xff, 0xff, 0xff)); + const QRect r = QRect(50, 247, 100, 50); + p.drawText(r, Qt::AlignCenter, network_type[net_type]); + + // metrics + drawMetric(p, "TEMP", QString("%1°C").arg(temp_val), temp_status, 338); + drawMetric(p, panda_str, "", panda_status, 518); + drawMetric(p, "CONNECT\n" + connect_str, "", connect_status, 676); +} diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h new file mode 100644 index 000000000..e108a6a5f --- /dev/null +++ b/selfdrive/ui/qt/sidebar.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "selfdrive/ui/ui.h" + +class Sidebar : public QFrame { + Q_OBJECT + +public: + explicit Sidebar(QWidget* parent = 0); + +signals: + void openSettings(); + +public slots: + void update(const UIState &s); + +protected: + void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + +private: + void drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y); + + QImage home_img, settings_img; + const QMap network_type = { + {cereal::DeviceState::NetworkType::NONE, "--"}, + {cereal::DeviceState::NetworkType::WIFI, "WiFi"}, + {cereal::DeviceState::NetworkType::CELL2_G, "2G"}, + {cereal::DeviceState::NetworkType::CELL3_G, "3G"}, + {cereal::DeviceState::NetworkType::CELL4_G, "4G"}, + {cereal::DeviceState::NetworkType::CELL5_G, "5G"} + }; + const QMap signal_imgs = { + {cereal::DeviceState::NetworkStrength::UNKNOWN, QImage("../assets/images/network_0.png")}, + {cereal::DeviceState::NetworkStrength::POOR, QImage("../assets/images/network_1.png")}, + {cereal::DeviceState::NetworkStrength::MODERATE, QImage("../assets/images/network_2.png")}, + {cereal::DeviceState::NetworkStrength::GOOD, QImage("../assets/images/network_3.png")}, + {cereal::DeviceState::NetworkStrength::GREAT, QImage("../assets/images/network_4.png")}, + }; + + const QRect settings_btn = QRect(50, 35, 200, 117); + const QColor good_color = QColor(255, 255, 255); + const QColor warning_color = QColor(218, 202, 37); + const QColor danger_color = QColor(201, 34, 49); + + Params params; + QString connect_str = "OFFLINE"; + QColor connect_status = warning_color; + QString panda_str = "NO\nPANDA"; + QColor panda_status = warning_color; + int temp_val = 0; + QColor temp_status = warning_color; + cereal::DeviceState::NetworkType net_type; + cereal::DeviceState::NetworkStrength strength; +}; diff --git a/selfdrive/ui/qt/sound.cc b/selfdrive/ui/qt/sound.cc deleted file mode 100644 index 641ffb22a..000000000 --- a/selfdrive/ui/qt/sound.cc +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "sound.hpp" - -Sound::Sound() { - for (auto &kv : sound_map) { - auto path = QUrl::fromLocalFile(kv.second.first); - sounds[kv.first].setSource(path); - } -} - -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(); -} - -void Sound::stop() { - for (auto &kv : sounds) { - // Only stop repeating sounds - if (sound_map[kv.first].second != 0) { - kv.second.stop(); - } - } -} diff --git a/selfdrive/ui/qt/sound.hpp b/selfdrive/ui/qt/sound.hpp deleted file mode 100644 index cee1ea51a..000000000 --- a/selfdrive/ui/qt/sound.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include -#include "cereal/gen/cpp/log.capnp.h" - -typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; - -static std::map> sound_map { - // AudibleAlert, (file path, loop count) - {AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", 0}}, - {AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", 0}}, - {AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", 0}}, - {AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", 0}}, - {AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", 3}}, - {AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", -1}}, - {AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", 0}}, - {AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", 0}} -}; - -class Sound { -public: - Sound(); - void play(AudibleAlert alert); - void stop(); - float volume = 0; - -private: - std::map sounds; -}; diff --git a/selfdrive/ui/qt/spinner.cc b/selfdrive/ui/qt/spinner.cc index c3bf5a3f3..b91bd7bc4 100644 --- a/selfdrive/ui/qt/spinner.cc +++ b/selfdrive/ui/qt/spinner.cc @@ -1,39 +1,63 @@ -#include -#include -#include +#include "spinner.h" +#include +#include +#include + +#include +#include +#include #include #include -#include -#include -#include "spinner.hpp" -#include "qt_window.hpp" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/qt/qt_window.h" + +TrackWidget::TrackWidget(QWidget *parent) : QWidget(parent) { + setFixedSize(spinner_size); + setAutoFillBackground(false); + + comma_img = QPixmap("../assets/img_spinner_comma.png").scaled(spinner_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + // pre-compute all the track imgs. make this a gif instead? + QTransform transform; + QPixmap track_img = QPixmap("../assets/img_spinner_track.png").scaled(spinner_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + for (auto &img : track_imgs) { + img = track_img.transformed(transform.rotate(360/spinner_fps), Qt::SmoothTransformation); + } + + m_anim.setDuration(1000); + m_anim.setStartValue(0); + m_anim.setEndValue(int(track_imgs.size() -1)); + m_anim.setLoopCount(-1); + m_anim.start(); + connect(&m_anim, SIGNAL(valueChanged(QVariant)), SLOT(update())); +} + +void TrackWidget::paintEvent(QPaintEvent *event) { + QPainter painter(this); + QRect bg(0, 0, painter.device()->width(), painter.device()->height()); + QBrush bgBrush("#000000"); + painter.fillRect(bg, bgBrush); + + int track_idx = m_anim.currentValue().toInt(); + QRect rect(track_imgs[track_idx].rect()); + rect.moveCenter(bg.center()); + painter.drawPixmap(rect.topLeft(), track_imgs[track_idx]); + + rect = comma_img.rect(); + rect.moveCenter(bg.center()); + painter.drawPixmap(rect.topLeft(), comma_img); +} + +// Spinner Spinner::Spinner(QWidget *parent) { QGridLayout *main_layout = new QGridLayout(); main_layout->setSpacing(0); - main_layout->setContentsMargins(200, 200, 200, 200); + main_layout->setMargin(200); - comma = new QLabel(); - comma->setPixmap(QPixmap("../assets/img_spinner_comma.png").scaled(spinner_size, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - comma->setFixedSize(spinner_size); - main_layout->addWidget(comma, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter); - - track = new QLabel(); - track->setFixedSize(spinner_size); - main_layout->addWidget(track, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter); - - // pre-compute all the track imgs. make this a gif instead? - track_idx = 0; - QTransform transform; - QPixmap track_img = QPixmap("../assets/img_spinner_track.png").scaled(spinner_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - for (auto &img : track_imgs) { - QPixmap r = track_img.transformed(transform.rotate(360/spinner_fps), Qt::SmoothTransformation); - int x = (r.width() - track->width()) / 2; - int y = (r.height() - track->height()) / 2; - img = r.copy(x, y, track->width(), track->height()); - } + main_layout->addWidget(new TrackWidget(this), 0, 0, Qt::AlignHCenter | Qt::AlignVCenter); text = new QLabel(); text->setVisible(false); @@ -51,6 +75,9 @@ Spinner::Spinner(QWidget *parent) { Spinner { background-color: black; } + * { + background-color: transparent; + } QLabel { color: white; font-size: 80px; @@ -67,17 +94,8 @@ Spinner::Spinner(QWidget *parent) { } )"); - rotate_timer = new QTimer(this); - rotate_timer->start(1000./spinner_fps); - QObject::connect(rotate_timer, SIGNAL(timeout()), this, SLOT(rotate())); - notifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read); - QObject::connect(notifier, SIGNAL(activated(int)), this, SLOT(update(int))); -}; - -void Spinner::rotate() { - track_idx = (track_idx+1) % track_imgs.size(); - track->setPixmap(track_imgs[track_idx]); + QObject::connect(notifier, &QSocketNotifier::activated, this, &Spinner::update); }; void Spinner::update(int n) { @@ -96,6 +114,19 @@ void Spinner::update(int n) { } int main(int argc, char *argv[]) { + QSurfaceFormat fmt; +#ifdef __APPLE__ + fmt.setVersion(3, 2); + fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + fmt.setRenderableType(QSurfaceFormat::OpenGL); +#else + fmt.setRenderableType(QSurfaceFormat::OpenGLES); +#endif + QSurfaceFormat::setDefaultFormat(fmt); + + Hardware::set_display_power(true); + Hardware::set_brightness(65); + QApplication a(argc, argv); Spinner spinner; setMainWindow(&spinner); diff --git a/selfdrive/ui/qt/spinner.hpp b/selfdrive/ui/qt/spinner.h similarity index 64% rename from selfdrive/ui/qt/spinner.hpp rename to selfdrive/ui/qt/spinner.h index 8bdd13a3d..c54aea103 100644 --- a/selfdrive/ui/qt/spinner.hpp +++ b/selfdrive/ui/qt/spinner.h @@ -1,15 +1,28 @@ #include -#include #include -#include +#include #include #include #include +#include +#include constexpr int spinner_fps = 30; constexpr QSize spinner_size = QSize(360, 360); +class TrackWidget : public QWidget { + Q_OBJECT +public: + TrackWidget(QWidget *parent = nullptr); + +private: + void paintEvent(QPaintEvent *event) override; + std::array track_imgs; + QPixmap comma_img; + QVariantAnimation m_anim; +}; + class Spinner : public QWidget { Q_OBJECT @@ -17,16 +30,10 @@ public: explicit Spinner(QWidget *parent = 0); private: - int track_idx; - QLabel *comma, *track; QLabel *text; QProgressBar *progress_bar; - std::array track_imgs; - - QTimer *rotate_timer; QSocketNotifier *notifier; public slots: - void rotate(); void update(int n); }; diff --git a/selfdrive/ui/qt/spinner_aarch64 b/selfdrive/ui/qt/spinner_aarch64 index be45fb51cd937705326132faabe836dcfbfcae02..a1fa6956628e24f504b2753f9500b69554d365c2 100755 GIT binary patch literal 820976 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

EQ}gl47J+N1(4PLrxCDIkhzCR zn>&sj;wXoLY-ZQvsDyZ?wi|MkL&0VUWgo&M?>R6ML{}zyGFFONC&+d|NpTGm8xwK+ zI3A%zYB#G)5aKMT%k5TBxByo{8MYX+2y)t>iX!CcnuJ_lQl@GiL0CCp_Fe@afI?x| zkVSAK;z5c2jF9JDCjLOkDThosQVw+mGaqEjpoC0p8V%N;goGSQ^zxXOT+&3=K)X)C zD7>W9D(9v?W+4ewzF1%td=QflC!moPj#XB{hb}2E0v1>Wx;_eF|E54=1^RUqirrB` zhW}5**tIF?Gy|-joxk#Ehw7qHl5L!U z3Zp%AbU09cNLAAJksJ8HVw<`UDfkIfNiY9RFyLj7l754+9(;Mqb~yG)rgY8I=UMu zzlpkJX!P9F2dDfeTxys`$(INM{_*fB-~*K4b3Iah;?c^O6UcTse6vS5^T@KULGkOZORm=_mFg3h z8mUn#)p<}mxr2?;D3vOG0va6uC8Oi0Qo#KB?2^e^RjE|HT)z3r2Y*5bl|I*o6RlY_S$tocnT`HHLkeN zgW_-6mMo2Lky&)C!GKsqFc9T+GK>sZlCbEl@n&mE0Cb zH2}pkc*!d5(p9P2fimz{az`B1-=$V-lq$w}Q2aLbk~=j@WjN2J?$Rig>K;(ow`Y{B z(I}PbDNyV!l-wOhZ3o3Whf16kVQxX6O7$@)-jh)x-)eNO0!4ifY7ji@#Lc9VXh-J$drZv^5%(>N8}1KO7j3*jsKF3>XMVkRB}yj#{&(cbR@Xjn18{? zlL6+PmONFkusPr0aG;)RAQHXoGbcAFtGjhN4}r-XZE%U1(hetKB>#CG+;)7bPGYTu z!>8&vruw2X$5-kE`fV|%5vyhnlqA^*)WU(ds+CKiOfe&sXXxu3wa45fIL{$Yu9#K? z>dsdFMARNn1r6HvK|F>^cd7OoB^d?sK=D-20JDr_#ukRZC17rj2Ax!M3}7@c76=b~ z4X`sUT1YkUEpj<*Q4>y$UXKIjfv-U~u3s~SGtvjXcU-=^#;c?!K=A<4pr;xjR2kBM z6fufV$3-(M|Kt~zEnR~?>Z@+$Mn<3usB1Vaeh3g-e${?~ajpS2!$l3GIDwVmPV$*t zp>xtgfsHPQT|&`x(gj(}#nQ+wm>k1@1N^F>f{DuG7uR55oIy-Rl`uX_M%ZLjAtUiG zq&fU~uo{N{21C@qE49EUqWlm4Sa3Y6G#IAUyL1WvB2YYaG#DO7JqC*BhXy0!sQrL> z5@>Lhc0kDxSJeqzIPRXb7K_xLw6@R{_N4vFS4{byG>$pfmFypbw^R-}UxgGLE|cKu zdV6R#7U!@hP4e;|@2@V3j1HDu6q=#CCru!^F#QPw9P7@SwNQatpxixal7cOwd(s42 z!tT4jA1rzNbN8eLxW`M`{5OKq_oQjmDo{0WXXoxoW6JP93zR)FcTbw2fqg*TJ!x`a z)#N_|*7u|-;|m5x_oPLQ0|kKpMmpY;#;_6S3dG%$CWwC&5PeUY%5VixcTbvR$n9N@v=4()d(u9_k=&*^@1ipg3o5z$LxbEsX&M@6474L}Gn?(E?gK>aN#jm! zrpVz`J&XsX_N4X4dY?+5`jLOJOU2{aHp0p?@iIu@iFmU&z zMGX}9IXHJuS~+I~{%~RJNh^n)Q89f;bWa*{M&L3a?w&M3{6m1KJ!xvxRp>0BYEPPu zt^=y}q-mEKm(FRW?cnu2Y0|bDe+<07C#@oX!O++}Y2`d_aX|HJhK}UyNsCf}zM$Ma zY2`Iw_-_KN?@1F%s?vWiD1A?wMr{YB?@8n182+z-sy%7Z>Tv4#A5iX|wDO}n^-+D8 zy4T8huj<_L>nC*$#!qKYS|itBPl*`F(Ng~(W9I=NMbUNb8g|$)JtM8S!;F$dRLp|1 z3D(^uNKlZZVn$F=P{D`+Bnc=>n8hq&LP5ox17gl%{?EC$YPxn7-|ttp zru#X!ZdX@VSJ$1X?tTjf48|}g?JyYVoHWlMI0sbcr1|tJP@R+JZ7sOh(e=LVI#8XH z=F@LMbxxX3n+(%%uEhs$d3(_b;hde5))NLgC(Sbmj(6EU3a4=Ab>C`j6o@%#H@Ivc zdj`Q1pgJebryqgpoHU>Q3o7T~XVD%fxG42+8DIQoNcI|5Yar1^9v=<+)FwR6%~GFx9OAvNm)$<9ghq_-gHoHUNIy}sMF_g|sw zoHRX6BrCf&6Ks2;l{V)|y47qs^xT}Z=zPo`0ASPeKwkSO^0*CoL~?%SWO4 zbJFB|*`IsXiY-Uyq`it$tt|cu#>3H^v=#UUQ|F{{BPDOMC>0wVT*u9qd@ArSK%JAu z%Z^wkxMWJ1)6PlT>2SSrBwx!jsyGOWWPhC(CGnZyk}2gj?3}bQF8hW&qlzU^bWU2n zvJQ&QNy}IMg`#uPzQrc|IcfcmaC6c`$&<_Pfn0A++E)NNCrwP{pm=lA4nURKIce0Z z&cM2zlP2qnv2N$2aosy4JUA(aL8&Xav0z z4$0T((S1k4-(c?CeMjOe*l>=E@jikYEAb3nj3?-G<_&&y)_pu{k&>w~QH&=!Xc5JD zg62w$*ANd2qZto^Q3W*{1}gt39bb7V?3eB2S8nnCmYu5-|N7BjHkxG zfV%sRBI9J!bE6oK*d*J7xEN1J&=2lj4!hw)9#?zN$OChz2hB;|! zey-$LNG`^c9JDaWYaB+5C-{4*tW^#p#uF?DIQc%XyYI-e{?}o|c%JVa&W~a|!7OA# zH_*jti18v#%XGZc5aUIfWLAS|FmN$mWT4t@&|Hj{(@gSNhY{oDuvTdDGidI;v z)nV&+6(kqq<+g6?<1J{sLbiD6x4F6Vr}RSfpEkz(#Tl&4%yTD$DP08v8{=&=&c%41 zL9h>~#&|v*2&yrjx3%C@N7wtd7lUey=hGWNHOBMl)1Z3a(JCn<_tKP}c7HC$`x6El z<9P-_`a+xSqo2KfbHDT<#@i1DlI>&9Am|6GF`iFHfohEB)0vP@i%3K6g@4h2BVwt7DHpcTRJhRH-Cb2iJaP?tIe}Q)!<8fbY zjQ2K-ZHyP6Ph;6)>Ax_xG2SoEVr$=BcI!!AjHksc12P)pc^$D_$ua|=*%;3|NUDu; z`7$vtAKQh=%z$QNyaw9MPHXPxQ=d;cpDle&4pQcQm#=k0?RRK4#*1H-tGrCx$+;L$ zik~QfXfg)_+Za!AQ^9M2ZH#v&`XhVRwD}R(#dxeS4eun-)BBEUE{g6u${Cn8LxEk4 zCzwNC(`Es%i}3_=G?ZXs+B^fz#dxC0kJyr^!7ngyFzO>+;wPMTB z81H_ZYGv`qFv5*uygTt@y2g0iNXertO2w-VuH)uQo)WkjP-8q^cEmElB~!|rHpXjx zmW%Q7j4BR*qA?yXO5!uYC6k*Kg8Pm}yX+hCj4BpF(HJjZSp!95ynN*sC>rCvgcABO z-T`O37*CWux%_6x^~aosy4JUA(a zL8&zm3S>zVw$1drWU|CWraYv`#xq;`52_!dyGS!>+YC)Ly%i350ndVThD&V9={8*A z6{RrF$)RCc^gNfcDt)Z(-`AmK^ui^ZRmqqeaj42yfbi)q zW&iPX7y2)|%~}`B+A>{}CtOE8y!}aAEN-_JW3h?ERBlIeF88=8{sEgVyTiIpZpIpa zZ!5dY8f|kE@&&;xgi!b^yGI|!-i$Q4Ge~#RmDX4uavdBDbRzM6zVT>~%Si99XS@XH ze&Ppt6^fOp=O;kkA$`ai>m}+7pxA8ShxPFsYMcbwh4c|?EKef|IszR;{HX8wP>|82 zkJa-$4rnehqr6-(7J}SC`eZ%h2Y{X@ep-KX)ndF1@(JlP)>wkK7x=aXCJEjNRWx7FZde{ zW&mAB{E}~cJIHF%we^f&1=>XXif{ZQNH7OKj*p3?O~2p7F6j=Mr!5 zjVFU#OZrAV+KuF2JrRP1&0Sh1bM6jT#7lXM59 zcvq&RyC7{8?k#B*(t@zNq*YCjFYJfq#^EQUIV=8fEEk2tkQSR@BtE9$uk5|H*Vf@nTdI&YtBnRb`i8kn2m#fUd!wo7oG)sm%K=xg>I`V^C?jIt+>u5>fv92 z`KFh$WIY@#K=_HjvXp(sfVY8i@WIrYXcoKOVL(%e!K=G8=T(H~8w^p8g2rHix z;8_8B4V8;m_II!j3&EQ@F3-`=9so9)d|S)$sYo97?rt$4?yLywb#-PlSPG=UTo=NrD}T+C`ZQam-uuls62Fb=`o()XF#hF z6|}$3^PBt!lx1yygWXcH@)EphuTk8zzsYU;Opum%NN@W)v_0##mx1zRYJXQm6DLVw zKZnGVsr`xu(hk#YuDd;n#WcZDkR;bV`BL#hNbT>nY4Ix)*tP;`BrEq^61;|6}0LOQ6nQRwOxe9k>*lr5Rw9piBpmc z<0^$Tg*4fC5!k-d6RC13H3LhXuACg#-v7!4aT7nFGW>IX9Q|_~Yq)+QEeNwz!kv&d z4m%(%3_Bq$3cDgL4i7|H5*~>(5spL}gyWGWP4LDSakChAxgOA0FOnI2ae*H!Ks#*0 z{agoo)TE_AEZTT36~^bJ;k&$6p5A!lU3drPE2fyN98(gj?nb3`lQqmf=&mhL%|jCnM`+X$2%0Pf8O{UY1VKhBC`(R_mH} zLxJQeP8*eV*U-cH`pln!a^RMOtRo$3^Rfa> z@-2tQ{STMP&9G{{6qzrqmw9&}!Q=l|=DyBqg0+$=@{a9!Ft~xM;L*> za!eS^H7vPC>4iA?gEN@iVDl2D%0)QY`i25igTL~Ntd*Q2$sRzb5l^vL=CCKv1zJfw z&Ei};)1&@4@BB$V<*e{))BoK{5}N4`WZL;gxW=zbl1W^%L(tz3lKVmwgW3PXt7m_N zv&ZjC^&R3ob=utj!xu)`Fnt++<#=43xY17J9U%TXQ$Alib2cMw(?O$~thB(Bq&)@g zAaM$D`NDiD*&h;To|j*hUnI;*ciJMWv5nv%iNKtBUVhCEGL)4vL@g(H(COEDx@P?Z z5@(*5FX@AZ9xIWvASk>U@d5tIm-=*nkfTVi=Z#&~HhBWbWuzDxNWI8iU%_Ia1t?tk zP0=2j;1SUGXnadl5)*s@lD!4=)@N6`LL^?qq6wPbUSR6*SAJUqsUPq-O3Q|#&b2r; z*9>5Bc)OSDkq7DUnU&Vz@&?jxki_8~o5A32=Sn~W zJXHIB@JxB{(H-uK8y<@CgG_AnPirx;o-2KdW25ys;pnT}z9)b*@wzy_7ZS%&<%1*VD(OZ4 zF>E|u-Zh+vPZM5>6z>*C+9N;%N$46^N6;gg z?cRv$WhEF1JcrVKQJ-w3#lTNfy1zlLSAjQEdZ2++^ng9j9@2f3Gs9l}A<2pRa0BTe zNW5d9{E?`YCN$SbNW5d9d{qN!4kX?&Q2uBGX(gl&@mKy>1L-H=Rb5d>Pec+X|2=3A z+fxk+w-+QiZ1$TlZmw?>6r2t8%TdbYEJ2;e5rifhj2#|{>s-&4`a$} zuyP{7s}`J#6^19}uUT*z00+qBuUl{*z^lx%L4bZ~TmCLc;lrSBXwO%^9aef0ys4mK z2v)`ty!|!~g+h!$zq$r-TGJt;FL({-0J@*1D@>zq@8f9zO)(JMiq`;AQ~VwghI~XO zD7i`_xu&Nz#d@qHBlHkZMsiKhVjf4Af-*{IYHu}E+iyVY7U97S7wxwqXIt6^`S>oT zrbC14ATrczI^B2n1L%DvpqKiz=4!p)wdv*B%48GCIiL*enqKMeN$@c+iZU5<$nFz&v7wht>*`Cp#-zV3Az( z6)m(#?iW&odX|hbo>PSDyPyZ;BKQ!B#JcNv^(w5_lh!)vT2B&3$xk5h&~#jEbI=0U z6kxgEZK-}2^(1LBeVx7E?Rsm>u2j3;WP7LK3NNM7p~E0xx!>(3y_c*8<8*Fs`YOYq zS8n=R;cZ;%CFl=HZu+{rfpi8Wx#{bk2GTr8a?{tnQQ;Ee5O38$s~XQF%_PN^)^>M{ zXVU9XB?TLh6vp|)k$oyEi#mg|ekv|8MRmF5;-UlG^7OFiz}#}CsGnP&(Yk0*Zn<4I z`m5+1E4c-unnV))rYRPLyEKXH+WyuccQm5|6fK!xFdVaiRdijByf)9>GF}?tr0$+1 zV>8_z?#z@Th_xczr6x$MlH=gu=&j?X;=upEvRnoGYW!97Wuapw_e(LBgLEN1*r$(! z^dRl$(^o+bBJJ901I%qoOFz~dU2@dN^qO4h-39c6-n=% zZ0DpQoHA=2>K)GAoOB$!Un}X@;6zB%@mFDQ#uSHA8_5O0yzW%s3Mx%FSO&71#wX}G zM`IJL17UzvG2CmBJbF_9CioKiY(8Q0q%G_JLf>{7yq>&eeLHA-Qy-D15B@>n8D${Gx5fgip;+E1( z#xqH=t4lwD15~gYNnxDNRvKJcS@byiDH>EhVv3%{GW}Gp+NbD6xBO^D(K@&MSna4c z--yc-F)N>lH{QPIs11<#1$yO^@y6+%^0hd>5w3iuU)!HQXk@x^GnL&@yMVSE6ohVx z$P~*O?xz)lXea*fC7TsDi~rwQZ8;9Iwp#P=qv-5ZEBifyl33{p7ApAJNdr7dB26vt zK;K#s`xx${#-qV<{Qi!=O8d@|)#7#^5S}lU_H`vn4+dqUtvs4Wu@a@DL1)p!F+N=Y zav$ljK79h@6HehY)d8F z6KQeS5ou_G0r=qAQ+Yg(i7Vb2pqJpU(!K;mH#rN0*M`dBzU>X5yf##xi*VDtv zKHUJqD@NrApMC?%D@Nr=pT_URBv$-Yp5oJ1AZ4WXY}b-if%GRm&9^-SU2f$CUVF`L5Z5^9>~br|ZdpGBI=kG;aa-0;gU&9u^1^)m zZGMp$Tn~LM{wl|BS$`K=Vg>Yx(rjg1mY}H#ngMsGG^v3!0C*y$$)3dPp3OQF8oTMr zX`)L5x98stkl0OEUfe)>1QNUH%IRKN^{jmr61(Zj8Byh0hhITrH(fbPyJ=}v$&$PE zl30mp^U|FKJAiOxQaMM*1+=rbA=Wx+u8s>t(s98MC(YAwfk-+oxX?+L>9{~79T!~V zq|0?&Ad-#?9&^$aIxY}N#|0lcX}*pNMAC7AxyKfMfsPAA(s9AgkT@==T z96(iGsRJmT2zQsWy4qUh8nr)!dkI#X@K<>) zdv@1F{RkoldWm&us_m7cskM`oPsnNUWGIj-h*_j z@Oh+7!jF-L;qOSd4!3@a4-DM{Y18lkq}zr=kd}t$BTa`_AZ-@ji8K?wh%_61i4+eE zeHz!#a1W%-!-J8w2uCAr8BRvpD!c({>+l(*JA|JhZ4)+rhOd`vg|uy0j&vuyc@Q6? z@mF;(E5OzL1duC8@8=I#t}3qrd4Lo@@=KlRjGf1U-XnhKX;iIqarTS2V&Sjq;ohI* zXmZqA42tkqwaU7v`HW3$!TT0JYVmEq5dRg#)f)2}WrI)0dGfbP#?AL9qGdczGgrEO zK}RLxrV8^K#klY9^fA!kr!4L!J}v<6L+ht$=6uWreH4FHnAa#i&MM>ve+1eFk4LRq z!*#cZJAmv@`n+B#^la%3GJ+Hn7sW-cTQte@oc5yCB;HIearh;R<(iUQ1N<#Ly=<}U zQ1BN}W-H)Vypjhyf^;HX&koYhN$%9dYM8?)`^t-k)sAx7J66lpgBRXl6Q?q(1^w!G?dbzzbZ zgRH0BMn~Sp8b^p#U)s&^8l_)v2Y*AGf(WVVE4^@OO>PV84$SejN0T)mN0NTyJP*g( zKP2B-&m6^A&-1_^!)a0VJ)vuJw}ZaK96xw8`5wq$q(3^(!8UQTAO5O-Zdm57;6teW z;+O6ekgG|5Ygm>$z}HgS>}@r859DvsKNxs=4k znLzW1?F2okzU&f^)uaY9yyT#Zb>>|#vn_bcPMuTpra&AUR~0z(+!(`TcZJA-aTQ-I zB)&Yc1|mnrRgHboWDf!7XuOJV7m`eJMrOx2UhKG>z}bb4^X{L#jb!eI_#FPKf|w4k zwA8NveNT+{k7ynlab^E-JmvTnP8^d-m!jzSt7=luYX#7e#G%WrUWYrrwc}gznw<)> zJD4341+`FG^Q*zWCf~MR&Brh&s0040nmKbhJEil^RzoOo(6WAK^?H$*eU+;Kx$F=5va=eA(x&1QPR5KJ0e^srVcmRG(&>tDH)lO{fL>YKz zhdI83<8qTe-J0w)Cvxtg9B3JmXKx385r0)}9hU)q_I1a1a$I79?9Yzx?0Bx&QSWH7 zO)}Q)F3ya5Z68n4!HMmh$g0wr5!pi_o{PV#-JE#!wiuD?{39CohZM|WP3Qim*cy)$!+N*C+_XUeIT0b;nmjJK8|~pe1Q|&J5e6%k-Z6g zHU6shbzB0G?8}bt=lB*Y^Gj#e(V6L~QL=yB?2f;xa>pOqJGTQJomk<-#~_;QvVJyG zrQ>p&kJj&tPDDqgtwiow%l-%gMdoL{B#a~rdXWQ0kS#ZNvtb%wV{;K*oF}HP- zJ=ckSov8bHqvHoVp4+C$zT(7wPSpMU3%tc3Y-xbwGH~+hd?%=4G0<7?u>0qKcV{uk zS>&=uX3>(#9)}E*xY0vhhWw3AcNT{^i~qyrO)kS=mm$BDt6{N;8$H5V1VoCvqL=8iKjU+=R2Vm z7dnek&O$mN6_-PNkG{`vVzgIWGTASj#hK0`Dj%2dLdU_@$63xIDnhhWf4`#&G1;yz z|2Ylw|97raU9NLoE~ypCpe4V-S)AuAWXHuqOa7L#INw?1e3)#};dZw!aAGdI$?oUG zu}-YNrzU%Zvl!ob5myd96U%m+b2>D{Ooz zZ2DE5keioRHQbw*S9KER_gW=X+~A+-`J+Gs~6DWcxaCrW11|GTAXsoaMw^IZXCC zC(d?aZtEudq7yH5V$@=!e9>yOq&uHJDQ^1WuWFvlx)^oHu_^>l~^l)c(gENz3 z9GS^e0kYGa*^SODDpuZ-IM-Y&U9Ov5E-8apl(L>PSDlL+P)NIu(}+7Rd>1_kvd<0 zAggex6Yp|jv=Oy;T2k9*o$Z6pR<@$zcTRlRiBa}w2|o*<+L~WrckK~p zD~?p`alv>Wbmt6Gm6O!>o${Qjd~U}P#FjG*{hOn&!K19?Pc_H6K*sJ(78n(PBu zeV6DBTY8iI9;@421oWmuE#${0_m%SlD2i#>78aZ)QuR)36@UgHBH?$kk!Xu^mC=s?&^p`Yh-LI2qkEW7$M<+ef2m#?hVxLxFXgvAU2w zO5P6YrWuRzJnoX4W-Md@NyYClWNkKGNsE$5X*C+_GR^pEEa)_2qPCZ#T2lPoG0oM~ zMMw&`dOo)=ToUpQ-EcTkpQ3%ImeEWy+{-0lk8z1NP8P<$#1BrzovLKM5^t~Ubdl*s z)~OmV3&jskdJl22Ak5LsA^QWQ@EXh8!`>8cV(wZ+Cio3&+|5p1I?2yh;y?_8aJ7}X zc~UKXB-=q^Eq1~TP02wEya5CFSp0Q5kmr1?q`S})L8g!%f+A-jh84W1W72r)$<*A+2ZD zlRU}G`Ytq%n>vlup9Z{Yia&3qQ$2}UO|XxXPV*$WQgJJKkw+0q}F ze&mgJgXyqZPRnz-4R@+M1oAHFc|QFDB*0J1o#efC&Nc&5PI`fFTL;3aMxDlatxnJ9 zBO!6BQKt*@C6nSW+UYVh-U3--GM-6_tT4V1S&KV&$n`><2jHG}u+AN0B|GDnZQBb8 zDzj*J{^DJ{fL7&-OmH36*xPij>Qa~)%3+;%2@2Z8b#J)OH~6)8Ohl+W|& z+*P0FqjWMTpE}gJo9}lKC?7A>xx4RS1t=fq)A<0Oz6i?a_H^#y)6YTqfS%4heHvS< zPvYs^%cm_t`4pYbz4a+NTCz$|KGUT0LB8z(P(Hk*^T8f9Db89*?}NQBkR>K5uBN+@ z^+Hk@=gU&V>e`~q@p%kL^^ZD(}Zh!~jzZaWkw_s&6-QiW=;_uJM-(RL^xwHMdQPB#w{7<}y4^tE${}wjO z`NMrYrr9H~>h(Ds7RSsbEMTKpvs?)a@Jz54t|;+Xqh@W~O5<3(*=}y7Fjm;?+d;OJ zMfCb4ye_6!^fThM#Pf=IoXv6t4d69b(j>e->x!L%*IZe*qStj_#LbK!;T5mNHpM(v z)tI!r0K~3g(lXZ)5{{?=uG@mxbfa!buMuj|%UWC=`N0fk$#ipsFi}~MbbsAs+kGwi z{PJ9J4tBoqMtEDMeinVpU$k|L{Vie(vuKb-60WHgrZ3AD7jfoH@W^`YP^u4GB2#2M z=_Mx};Ys2s_`pd=dy>>n@Gqp5sFZ3uZ}~>qOzEo_R4j>`>Y>`-C~fEHu!ttcet~jH z%yKy7cy+h1H$F|+A1NNObUZ#T!C&=>c0Z)%k_#Nh9e%P8QhUkA9L7T(1WR>w-vr#~ zH8>e5&&df=SiXYC{Z!UntVD~~8kB9edbD;>LX-P}p7jcB@k9o3Nznwofse&s^_kiq zs_}^+<4DhP+ec?4iSs7o-R2c#kIgfD9#_;O}2@1kgm{iS_Ud zpryokK!P3()<*I+py!A$(wdK^g+@yz`3fvH(hAQ%$kluPsh9i~7F%tA)imoXcmIz! zjWn5t#a^_!*egi>_q;(FEDogAbe^!bRU`+1j3%97^UB#AoDZ~tO=uQRcxOBd^g0^j z2?ei;qFs!Bt=G)4xEsegpIhpJqTh zlFs*OR}gmK)eC%j80ZMvUg;g@U=+x7(yM$rALMq@MLt~#vYzy6pMC`LE9o^JP5uqi z{7q2Y8Oeqn9q?$$BzJ^G6|I)oieZ5p9Qry~97n6`{@0;D85R?1b-ne);xst)m%xHo zsOlU2y15#Zm#XTUe0n!1uUXYM`}A2*Uc9Pr@##CD-{G(NHm??fUqF&?fiClDDah`m zxBGNoke;N=J(@fiid1#6Z9C`KIqj! za3aV>q!0P@GLYq@_NkfLeLev41}UbO{&%~39~QsR3bRfBtEw>h6c)|jfz{*xtKGGQ zMQ2()@!u6>f^M)FOsl6ja8!RLI0obl(x-iTF32p>XMB1&$StI+eR>DTTGBNUO~^PQ zcoX;=O3#aw&>rd+kn)#7U+`&wQK{Izq?89G|2zzKgi&YwRj*Ye9*qVkSa%rw!UOw? z8gUevsGpeNIA^p@jkKqo2zn*`zxqE4u@nXm(df1RQHZBt@E(me{HG^96N1lS6~kb> z`i=i|XIpmws~u_i)_?lM^R8gfjYe<(r#ln$fx%o1|Eu2>BWdO5xPmXkdX0N(A&{3mCEp}{7lf9^zf~mcE+5|mT^v3jL#dJ6boPa zCQ7sp?Pve?g^ka{!6~lUr-+x|)A1_yn)c=lvYM_XGv%5BW{QR2{zM`ZyaQXdznY$M zZBH;C?zuvX7urYZz<1Fq>nC`iK8$#3)C^LieQ8ubF+nX1j-b&|Y9x;y3{C(UM|zxA z^IR#*RFE4;Pw?s8ARHssj9>v`C2IQ&D94C3BYpZdD94C3r}*?+P>x?~PW5QA0OLT8 z9Bc4kGN~SlCfN#zBgdLi^>7UkM~*e4>*1q;I0&x6AUJXoj02iWeCEDhndgJtPI{J4 z?*UmudbUs3f_zGPj!(Y=DOd+OhV|&`A_=l1=>=>aj_wXJl5~R9ysfuhASaW~^67aX zGf3z2_&X0bgYZk1nnh|GHKNM8MFdTX%c=QjE(Kf~&vPKnB*kwT(sxo=iKH-o z2hN+~+RpM#Qw{D|sJ+k>lhxu&>|R*6Yqh$Tc$zmks6m}Y8Y@bkE*9}OMeV|ApJ;^% z42kZX#h^L6Su>f>TimrcZfX%g%hrNkSYu_@_B?M}^r1o%YABmPOiaVXg;4PxTW5Wc zXDw3lBuM;zs}{kqO%eBG0wAm@{wVU1ZB6HEo- z<*W9rsBqfIf(4Lx`Kmp;fpiNbUcPG2(aV?a(qo`}IaTesnt^4)vx-3ZSfko;Qb;^0 z4d69AwWfB`0%=NOR?0K(?*X6_ab{w4biY|;>wMWM#!lgeH4~vKOd3%DSLv zg3-Xd7pLwRy{|=$XM*tVow{SKF+~&H4$RwY>W@ z`1tAAb61Q6$R4C8SYxT(pd4r*@$h>+;~^kZN%2LN?6%ZL;Y55{ZmrcXQFH|X%2J;9gPrb#W0-9G*6H*JMnJM=DJpsbi27aP@o^TDT8oPJ&F&g&On+v)F&6IGxLw_%ShGD*qT`9K zl^-!$*IgZJHWwE}js@zj!H*a>L@UM3?vGZ&X3s|}8PjY(I9g6eOT|&Uy2Y_(oxsG= z5;z(+D7RAFZ2w3Jn~fN$(_ibB#4^q5BBixy)(dO=zwQR{nyI_a^LoAS^?K~zlEHQp z*T-;EQM3NY+#6w9-A%EIg4us_mdcr4OXcrwzh!ZVOI3CAK0!zoC&4(B4>CR~cNX}BEew&A@R-}7}E0FFJu0q;Ad=_bk za2?Wp!}pNx7j8t_G5i5(S@;*y^04S{baml2NGrpZNUOqKk#-8pkaiBcBCQS&M!J7^ z1k#%DM5MLhnMmuxiAcMIGm&-;=OgVFUWc@MxB}?`;Uh?UhO3eG3SUNgVE7KwgTjqS z`-DFs?Hm4!^x!b~2hXbvvq<}gJ0l$swnsWJ?1Xes*c0g?;bBM*4Ub29Sa>?p!QpvG z4-cmzJtCZg^vG~2(xbxLkscjBfb^K~X{5)7FCiTgzK!&_@H3=C!=I223;#uWe3<$d z{b-m*dSciX>F}@v(v!mdk&Xy^AsrbGMtVv(4C$%isYp)?&qF#ooQ(AJ@KU5_gjXXy zGrSe)S>e4%&ki3#dQSKZ(sRSLNY4x3LVA9<3F!slk4VRce<2+g7U5f+3&T>RC@i8$Lmf>S^EbNMpi(+A4d`yXjN8n>>EIa`p7stXg@No$qG=Pukv2Z3nX5a-N z_?Q_Bm*8VIIwE{r8Vm2k$DCOBBtGWG!WZ!|FBWdV$7QkbV|-j53%|j~6|wMle9Vu9 zg|WC<5DPPHmjS(y#pp9Ityaya1mj zoQ5`(huKW#ZZH}3&9*Z)Sz8Gi(`VK|lVRVb4K!0)h8=8)Ubk*}Vf>%p z(bu-n=;ooV(f@TZrH|n=@14v)HpLcm?_}nhe%G3NCvy%Zexs>!1TMn=5_IDvyu1`K zi}(uGe6E9;7QG8m?0SYb(GX#a`TsJM zI3AX)uoi=Kq#Clmq-?PU9xGukytf#10oGgC`EEj!u`lp@ z70g=TD+JlF2Kw!Q`L?bWM|&=k13=w7nIq%m`N03s7@-ZZNnQuSfqD!4E-oZ^4#a;a zvu^!YQ1?z|amal!!H%0y)78jsCrNp`eJCW3bX$z?gDpAl7dSfMEup%{OF{LW%pOg? z2znr$Pjb0`1kragvn6PK*)QhPU!q&3@syWyo3m1dlcwh9N*)R6_io6AUx{V6q=hA? zI(&)6r93dnyBx+ZzG5v0IQb6na5|Y;&${p{i}BQa&vyr4c^52x2^P%bme36x?X*jM zP0MtN)8_b^WLAUwVBp@#9646)6KL+8%sI^@6JJ|=S-ww`>;TQZlbKme@>r1l2V+04 zP-_#+0MU0c56D%z3GM~ecQX6*eb6Ordslj=8B1r6Qt>w!@!+ZbEf#T~?6LLqGU)z0 znWd?D`pMA!cQWU6Jd7XG;k9sW-^m+`<$E)$-R?V{K(;Cf(bd$^qtHzg53F2y3IC-6c0gp*90Fs zgSEGdfo!d`KMd?UnM=OIm~aqmU-k@w_MrMsW}hAds_$g>wiZlsbiHqTGpN3k*{3go z>N}Zz`WvXelevE~+KY4V&%Kkm=lAyI${%_L!Kt8Pg>eEi3`cCF(j}u&!W22XvV5BqpJl{wg!&Oe-n6JwT9jt+_ z?_|!`xsIn!I(<`~j_d;UKNUEj&9 zrwRAhN*_9DbDpF}DVzKm2l#MoHI7k?oJUfcY?b4DEt_yTD%s)Sxpy*qe7@r)&R+ej z2G6~dnf5089Z>F_%z`r6U-I6`EJrL;3vA!X>{WQ?M2DNiMmBNvVM@2#w!poUc>p$K z-^n}+#`c}e3&mKrSlSlG_MOakJBzJ-ciA_A`^`knY-9JxWQu-8`SGtsY0T@0 z6PkS|vv-hG8|3n3{CrYDne(C9cQSiERa@e;=6*i)x!U<`>1%S3GGDoTts83LZ-~uj zVIOvk?TR|E4L)-ya9`q`Vp9CXUJ&udXkhzJX2lhPJ8s5_FdNpp#wMX-u}<0y19tCZ zW;Hi>C-XzjU@zOK@U5FMZ8ie0q`SQ>=8)I4*%^ai_fBSU$I(!NiD`2TH1|$s(Kz}^ zNTLP{Vc_1$oR_)fv(Wr^GRyhWg?rX&0Nm)C#}34)Ru*4^5pMKO=Eo6=aA1~vg&Qe( zjYX+w_lbq;xcQP#1Re&c?_}m>M=TRuGNsIE-^qLljCkcpzLsZH@u188IxkA%Gr=WO z%5Cr>g?BQ4`{s)4CE<;Sw#$-&sFzs?&agT3tkh+wWJPu={D^;?Rcm_n{&GMgN z!!LKc3|5KVi)lq~FQsCp6~B93hXs@3CezO&DWI6U}a<{enxvB;k3IrkakS zMHR>@lkrSaWaGtYE2`(9OG-0oTY)nzy)PM0%XBrDcy6V8aEX_=6u*p3@oU-ikz@>r z)BKWmJd+fE8&ma0eo4&V%f>TF@rUiU>+$<+dLFa!SKIWyG~T=o+}}jD3`t@9i{0>( znhiSlZmmJ*e)!A_I^Wp=b(IS`xu(~eT+o?A33)J6F6b1#6q_=|H`<_6dAG&swBp3rIYy3_2wTEux@P&>{&s4}qm0bbiU*kg^45 zLh^%7PnrwK4>~EC;119Q=*L{pDKxnj)CHZgVI7-(4eSS4adHn}7jzPv zTnjQ3p&N22AwN_{h*V^cDLVwq(SGCfLedJHP6ure5O^bM7#&v zw#0Wx41FhhG+74ff=(^lKoAW&*%CCj9hjU3NrTSsa+|Z#G$&2X&y`#X$pxLVThhXk zPdSXBQ}EAHS)V$Lpi{6M;ACN|crNJltlK$^pwshxAg~KM1xuiz8#vWz2s$H8%QVMn z2s$H8GONK#7`UJ_GEnVJXfEi?X(sur!w5QaSZgg=+8SLjL(I!nGs#L27j)7ZFB=8X zpi>`@taKcx2Aw{=22_Ji?=)lS>`{6Yx*v2(Q}Xmrp!-2*zMk3v-8X~QYjnJu(@oF; z(&4p`Y|t4=$w81@(3z_N6PyL?2c05GRR&i=dY56UeYc7yJqpPWI=LMaya%d5XH*@w zj{k(@g3jF5ZGB|g;O(&t8DBEn<<6hdY3M&~(Am)$tldEjWNW3XVPJ#KfiTdZ(=!Op z0M($=r}IHI==8Q0tZ;O_Z~GFc2Aw|r5>$gup9VYPOHu}WAFTHG0vDn?7(G58bc4Yj zH2Ban2!^<9AN}p^+e~D$LFW>e?PJd%SOuyGX~Hx}4C#sn9j(%-6Y&SJ^v#Q=V>uyC6xU{hH^v>nYcQYS0;VbNG(L z(QjESXIrupj_F~j+V6b2C#VLUzK33p{@~l52>K2^{OHq*LH(dJI-P>MAo)S3C%q0y zgHDbPyuRDE_aC8a(5a`1WaX~oC&8Vqv^h`Gqmcf=&4(~tBK#l)f%6+v#=P(%CpflAn>I@3n-cKGrB2>9Htp;qp+=Dwyr2SJmvwDdJONSVNXfG-O2v8y z*KzYDFACfYs6i($J7SsOk|||Q8+7iF)hkExwLGJWo=_zF>%1t5&jgoDDYs#R&NE&1 z4S7ZtS3}{2D)~mf@)8scI`fr3p=i*#0VVW<&OY1WiMA4SijpUn-wC;1(76#ngHAD( zgW?69T~MVq=%ikC8rE&lDeH@{Zi7y)dxwMvC&e%*wGKjoEJ?z)nPxJcNs56~n#SXq zr2nDuSLi9yOxi9(n@(?oqg}ugAl;lxY{luFxx|Y}YC0x=q&sr83Q1wScXbqwJ-Vlc zV^85TFB}`OH;zy)9OIgH(7A9dhZ6EU+*~*&Tpkgd3&+G)@Zer992*61m?uY{YUsi- zL1%Hx!RyYtk7q4X@_R@w9FrWhh{7>JOC%iIdGGq+*m=2423;Zf;g}~4f#io{luR%d zbOHJR7mf){E&_Gom~2=tRSy9B;g}k~3F>|WjEs}N0=saG*d({zCkn@e1noima7-Nz z0(Ie-IMi@#46q-L(O7FbSOQ7IvHpO15KQo}qZ9bx-&l!w58eRPaLl90&7dwE)3R;b z-i2dq37Xqp&G&+&;n;<_%~|OHCr!=Il{^;G@BH}=zX8f_NefF(a2Vm3;K@>1OB_Zx zCRo~3@(JMKbb{XiJ?oDhMmXmAj(3Q{F~K~J3EjX>PD3~rX*@ zW08Ssv!J%uX8k&V(lK{Xun=|P|x zj(MjUOJ|SLDbW3JOq!CX&w=iTWBK}n(EV^Mrz0SOba*WekPXKoDftg17mnp>06)O& zS3evRNvblagXD)}o^%2vKOEzBOfVT#!?CD3Y#lFw9Jp=|e9Qy?Z8jg7eLDP;d9P?=zsD@+S)`EVHuJ>(6f@(PC(`ld@ zj`{RvPz}cpX&3Fqd|WteIQBjaG#v8`g5O=Xk7i0X-M2-^X2Y@aGMnvV&mb5Gs^OSV z&j8hM%%_)vYB(0{ae|9d|9Ytj?sZ0==NoBbc-!e4^L06)gMXlFIF_$--2|=6t-dKw zH$e>~X|y&R)5dfZsD@)vH)n!#9sQQYa=q#mpc;<(^Z`%}$9xa3I{Jfe`yHr;V?GTl z>W5=2nXRvKNPalxNk>A`aEzk^ukW_)eGGIB$MiIjtnA)QaJiE<=SjNN?0wL4;aGG& zX5V(a5aE?@IV#z|!E@o5$J%2@3&#X=G?ZXs+N^=*!ZFe0WeAd}!Dbk^ za4au#%N7`2`{9_JFL%*zE4CaB#}3A+Ru;bw!`LVso430Q$GDM_Lz$)GJ_pxv^Cd?L zdt|ryhGSg!4hauVieXS{2!sMzl7wwD&15{26a%R=jmI-d&!X}9IQi2|+HQwd znqErA6Ck~eOKipId%47mNvbEFDVlzotIr`Rj4$dJg=2j>X*f0jpLyZf@11dka^V=) zw1dutV>u*`?2V>m3YQmNZxETKEGCT+pGBwkTe`? z*OHPHQmd%SNmKK4B?m$J-G*b5L!OJ9JjY>#V}esWFv$fDBODVf2RQj4unWgL>vtSR zIOh5O2iW~OCYXgx=muJMw;IB+NYgTPbsEC4NR!NJFdPOh9E%K8n*q&*V>!(vZ*>^q zSPpB2Cf7i7;TSc{RseC~n2?~!0WKWV=V~k62UNo`pY{XQaLhZ+SUP(EPlxV@W73p7 zeLi$Q9Lv`qhwg`CIo$-GK{~uP3dbTTS=1v6$8t4bf?a_9U&lm}stgW-xApM?G!4gEcFdhWr8lDgw7-sh;SAQ+h=FXa^ivqv zaICPW3&%WzU?))hbs zseirH1g|@z&-0D6G5qQDjrqEq&_V0oE*#6(xsFHgI(<`~j(htdNu#ylm^P+~pc;-v z-JA)ob@W>n%k`>{fND7A(+@#49P>T=<>(K-ZT3JHj`_3`sQ>F&bUFpYAo<~#CtVCl z!!eEyyuRDE_Zy*WIHsqGWM%hef~TCcIZx7~l>HofE*y)_$82zrzEWju`@g1%tBxrjw#+p@OB61!m&Hiu~;W~1amZ`uf=GS#sJxcW1?~NlaNH-o6)8R3|u&tm$~Js(EM;r&X+3g zSu3_24aeSx!?O5z3}d5kY{>pD9OFhxK4W{XnBw3%ZocG8fy)3j9OGq2EE8NZrOau= zvDaXvQ!?|6D*klYU*|+kUzum)L;QHC*C# zB;AWkeUY@SI}ES*8q8I`WT>$5qsQXLye3B$9oxQaT8_sCeT;nXdO+utQ zjznLSMXrh4*YcbdYwh6QchV$J`T*00O|aEbHrHfNl9C0rkZz;Hi#&;MNy1CfoixRh zG}jG~;@IORQ$0y@ZE(^wPtsh)N5{>xtei_&Yq65n*aZ_*fj+(`=nOhgnowV-I%%dS zsjnrFI_!m9vph+2z3Qado}{@7kHMX-%yp?JY4w#mX^tmp^_}FTxt^pB7eVT_HyqB3 zBs{Pjl#iNda=A`2(;fXA^cm9m5!Ln)l%quz?*nN;UZv@KKq^KCrgTNs~NDkH)o5n(RqZ zvfu?s+L%3QH`7XEbDT8CleGFCanf8*Qioqc(#9M~ zCP<@!_>Eb2vV#7&&!c{J%X_oqtt6WO|#idwRblDG`g#JCiQbEYozqq;`S6d+|j30U)-j>s~ zeAJq65!miGU$G0`3es!xe+F^kX@k1Y$ZZgdTgOX6B$f4rC4 z;3ax6IINz*;nqOj$Q5h_13m$!>k;quWLuNGA|-c*G>rN2_@u~XFdFF3Wxz*s6S0zy zkd!eO{%bUjNpF%ygN zuBU{r!xGOMK-wrQJOggSJ&+cMosfp%0HhP}UomE7oP#eP@d&oA=g^6ZU;)rd;)#!9 z-FaRGvWaxEHGWErOU{j(Hu&p$(Mz83E+7Y!PPNAR<>4@(ONgiGMMa8XQiW(o9YQp{ zlr;Fp8%Lp%?2u(AX#dg6-;C-`^pfT$qZrhWphMY6OK*p|rCwf4>i6=3KIKUr+;fWS z<<}y=b*SCcn@*bKN!m^Q?WD<`Bqa;lp6YsePYPMW;6Nu$@g&W41|%J_c#`J2(n-@i zNpn38Nqc$LTCC(%>;fK#2dce19Vo?fX(%;0%}O&pNqv<=(jki{X|7|PG~1Ij*EC4l z%X^Ym-*P9-@g%LjSDiH1lhom#khGVNBopj_2IBYfx}!Zn{a&6_+edH?B<MrXTb?MYgF z?VL2nleGH!I%%#asl#(1X|s+byxIuVZ`Qh_PlEc*npE3I@B<`m)_Ij?n{_L+IBnLf zxx_Y&(5#u5RxE}#YZgG7bp_g2YA&1?P)xDmq?T}%OKF;=?&K<$(tMIx!J|mpUV>{v zdJR{30ciUJSKr|3yIh@)fkR>AvPn_P{}uQ@TK>6xQAl}zU#{f~+T|d&{BcmX)bhoo ze#;lsk~^FO2JC_fwwd5sJ{>4csIO`#&GaPobrK|P`JSY? zE_2dsPtshELedW1leGFaI%$q4Y4wE@ZLYbVqz*el(v}}dc)ks&-|}@wXMy@HpH$mN z@E9a*`FWLQTmJXZwdJ$s5_huYGcm1L3~l)=fVBJ$XkV!ra9%($#fFo*imO~o(=2r> zS7qrQEVcav4LZ&D0H*mKz)lqx;Z@YR2mEy_3wr{X@S&0TYCi0PWrVzi@x{|o=I;CD z9ue5REGC2Oe+J_5W=l=-R2cF(cHkw&gK(tF7lZIQcHPUi_#C@pdhCwJ_=>fzVOY$y z#E}Q{oJnEvY#P-_@phYnR@l8F+yuX|@HZALjFW{Kq{T*E46!cWK9sF(GO}~v-u<{w zvF=O7*U~edOe&jC-hs6@NshNh+DyIzYB~ehzKw1Zy(V`AIhYhr|CREp@$o>jiS7I8 z)OZQV8qyKCG|Y_20DZIRNr_K$THH?>KU&B`jmK- zZ~PNTi&>zf>lyC@G?@5w-}oeu>7-}YGrj_7CGlCl@gpEVlb&OZv;9#?a>#xIj(4vM zabFoO_M4gR{1rMau;9w3uRFSNd1%K4fK9Pi#MyaJylT!u6j z-i@?T_%Ia{Jc*A@`0GBNnViSXAg$(rPOMjDdjkz3p5#~AaUd6yUR2L`AdDSEqt8+J|L1(5Ga?R$50r~d|Ndl~3Ly9w5l3HAdzjQFan&>LA7(g4o|jdvd$ z4#lSl&q9i4J50vM{rKy?$a-NelY9o~d*W+i3F$q$$1X?jfxqt8ZbZKsE8h>xoPE;$ zdf7n?p9|1MwLJ`7QHmCYjr*a$aHHfl(Eekra6@kQb7KWT1Chm)-U@X~V+Ap(KUNU* zFfR?k9#h>|;RR_XB5C~`?W9Sbq!+u{PMYjVdSIS_q+Z(@+EQ zeYGcPt|Oc@&670OEJ!+5V6DYUUcoNlTLMrWCDVb@ge`%SW_ptPYIm_4D|nLTI?742 zJxO!Tfuv&vPtxjp(n)hXNvrQ?C(ZRFTZ~KGSRs;3a0IA7R?r=t3F?m(NbTwIEF>K( z?BisGrk)dgZBx~#JXLp(X|9kEUL9=uAr{SKc<__6ZF6uFXm%~k`87m@vA*Be;+mdvf_*%RrX{AV?K;m4yF~>A;Sn|UbBz3s=mLzp} z45W_x!=ZceU{u13wj`;;+qNXB!?z%vMu$Thlv0st?dKaIY%bu~I=y_y3kI4_u!C81Da&sxgrPLcQfQiuf zMX=kDr1zzXEHNqViPaD8#@F1nrF8fn7u%(1o<5qEl5sef=q&ZX(@3T{-+U%agd=t6x!HEQ`;B1{V#)vXrgwNk#vUv-g0Hs(8D{ z@9f=8*$_dJO;*@INaz8iNyje;h(MB?D4-G$5Co(sD9s8M6cLap#Ry1Kv4N;qup%mU zMO18vC@NUtt71og=R9}r-Puii-~a#J&u8z>oO7OMo+)>3o83JVY4Pt&O|3wBHT9=Y zPaTc)Jxrf5D|I~5Vmowp>LgEp_Wac8NROsw*b*y~&DkmR4??eVdXvFsp(;{7nSHH=lxI6(h1T2MNUzL>rcrP?5<1JEHj0+eKy} z*$T<#eIlnKhL%hgWnM3~6uY*oe7EtA$AzRn2yo1M0w(r$^l)SzI`kg+DQlKl?@jD` z+~jbRxsMu2$)?47z%sDO8NgK09&FS(kTm)TDQcIJ7PBr$El`cI z4ReD(>k=S?05?|VFagF9;Ks^XupP(QUw7lws!rxCAoe>S0A)Ct*D))pvp+$08MED) z;wI;IZtfwrn<>FW()?3M>R@x`kdB}JftGj|qIMtRM7sGBRjH2OkL7$PvESTAEn|vZ zi(kn;fn3j;xt{QF_GIZ<*|0NU(wFc}iLmFcnB0^^4kl+1zCIE5Owt)aN9l42%#5yr zcH@MTk)R_um+%dVu;*?fIr(YTuxWA;;Z?GV#;=QO(&bW6Uwj(0hK-3ggZP#v>aq&- z(|8XnjmJ+K)p~(Wmx|MPSzTTSdV~f;;sz3Um*0Ta`v}bNIHO$^06u#~va1$Ai)k=1 zZlK%X3>wU;1{bh3Pp+vVm1-DGE)^49>KGy;{Zet8W;A{X9$@osk^f+?oXBM3NFmS} zO!kaCfF(8;GubrK73dr$yGOV`UcqFOhy(NnCi_OlVTfJNWUEL3=q*eRh(wWm<7H(v zFOKxY4tsqpU^RDSW>`nT>5(=N+|1;_NM9t^GI@r0*uvxx(LT-Oa7n(#YM@K3*&o0} zoh*Bo-bMT3v~a{_;zlEt)LbFuCeC#-6@{;p!fwP?A8UP))xV0SbKD8suc>R%WevFR zXW`m$nzTAMsN~(WI4FI@4UmmQ4#hQHHUW4X?~ya7U?_y+Or?5^+GqL@HeEbQ_{D1K zrwG60SJj)0cMyJC;CZ{eK9|O>RIiZREu1vk0tgV}F2cK{hSf|yB=@dxVp2(;+TG{m zx{5pLvt{Z_BHi5XiF|dQZ5;t{Mi<$Od*d`=^m&!)S3;A;>T66!DF1IFa#|!2-3NDHZ*!|aXFUuw2?zi+VJAn|*Nc>y&C7{i`^n@ZP$1b1rLgeI~=DGxL%LV+00DxDt#4m@>Ib?t|M}R@80Ua zh`?3Scqn}-b6@)d(SvUzd^i#IJo1}dXIv*9*}HJEp6X3L;yPKb?g9KLslke#D%CU0 zZ1lSuf6ekDkxOWaLmbodeJ`?4yg}?QAM-|8ZNhR3Udj^byTq;)DK~J~hlt#J_o}s* z$l_}5z5sk~FVplpBE3!IXCkMV$X`VIm`LywAbm}w7Lk4?l1=1P6NwS&Zz7F}oMs}e zhzu~1jzk8UNDm@|Or#%?ViPGLQW8fZ9LqxhHtQwlJ|mgzQK=^Iv$^Ps-jP0@Mx=#_ zTuP*siCjbEL=#y^q^*f8Bht=9ZYR>-L^cxXU?N+HxK{`|o^3?j1GGkV5b0!Ey+)+7 ziM&VTWFHCtIZsw+*JIdFgg(sdc<``&y|{FWsR|YC|vGF*~)Hmp&<)dZL%^ z6ie;wr90=R_ClI-#<(ucQwJi=U3Fa7w%9F(A~)XcCE3Aw2$el(A_=#%5{XeH+>tH^ zWSIqhvms>N5$&6KJL*Vs?g&h@^aK}E;O;VVDEGadPr@DX)x2Ir&XHd9jXZ~!k!vTN zLOay=Y9j5Wc-e@Z=58R@LDW3?@TRyWgx%pL1!(mO!tR)pnCJ-wTu!)?S>ysD?#M9R zt|r_sK47%lI|*MU=j2k_f(v-$V62tuesVX+IeDC`R1XtgE$8GW{3PL<G4NfCGBN6sI)ggDU3|}cqD#WbSB?_u5-V+wZgOKylF1>(` zC9^cnNJYC$2D+Hc$~fcNEC;%c%=$Rv+H41UfXqE{M#hMQQK`NKH-4PIhlO>M{zQ0+ z52N~j5Sim6o>1ZHe|%-!w^UI^RHaHIxA|Y1hTH>5b~>ggxyNee8j*WE&Y5*-L2kT+ zD1vyfQ>Jl5W*cCUcNmO-al`7SAria8kM4x3(;(&j`hh=iUoYGUIfn=@i}hP zd$6ulZ!+Ci=Br;=MQ#AUPq?2T#c*O}x;^_D;gba(BQTSdY9Ha=($X>*D%E}>6@n}j zVI{Vd8a+!|&o_^d~LF zlod(CJ^l_?76|;2%ZXL&~#;~V#se* zXCXV_aoj^M%MMx5Cj$(|%A7z~BS7VhL26XH&++H#cn5E?RYM~D?qtOUE;0rAiW%`V z9>(@Lh=;N5R>*2C%G>>j#rjb2S!cV|U(DoF&9AYwG9CrWXPxbCr%t8+B#7{AG-G>wYu*-VK!hzuRuT;kVWoK)ITt-5t85S_NMO{_m)hzfgJPIg#$Zrl^>8wk zcIyJP*dscgv=z)fs&jpXd)&>1SvAX*Z_|()(#>$r$JXs$N=1kX)LS04+n@|b`?R{2 z)D8a;?mGI^P`gxrP+V5f?qIwER;{am^7mlceXae_4$CS4?>rE&+I`QW0&X{VJ_fXC z1jI*Npdp8yd@VPJsmveHQuaEgWOIyJ5;-Jth|S@qO07a(#ZZzvp4%feavH{9yRW5q zF&{Mxz!L=9D&?0{aRI(~1cbVZI#2s)JpaHW%uH_Pa8spj!dA`o%UJG}adCTZXReuz}XPf(|=vcJNYG_A~;c$SrO0I=N$PqpX!Cw*t2_~7v$2= z$_#<8QvEPKRGF{37^#Xbm~ztowppSZ+21;{t%#>ey%T}SH3=qGjvH#vgitFa)J(M) zTG(ab5v6+4x7$fHvj-}$QhjkHsFCvjH{Z!Wy<~nfFo1tDeM>FEg@HQa8+{45;vvL$ z(OXK=Pq=B$R~0*$-lZh{s+;bHGOX@b=Z35_Zq)HAeat18N+)20zerv9HEt>5t+G|1 zPJ<$VF1_t4+GP^RoPteb>$nj9O4XVH6t8!|swqoAOsjo;X2@!b)EacIWpN&@dJ+Es zgL}5ty%X?#;o2-}(0;IMRdL9&_SFqp({eeO#`6ESr{(Y;xYwzk7{S+S_vjL9T2?7% zX6HB<4n+cg);fb-E|i03a25xl6TwQl1xTz{ow3EYN3DxXohx8dLbe?eXCqN^JT{|1 zwri&x{7JOMousrWHtW?zaK41pH_j_y<|A9W6q}OVgO;@&MDP~dISi&9@})ho88;NU z0Z7PeomvS$hji%pk!FU@L0{Goz4o2P^MOY%3_9x(FURD#7m?_Q1pax}kOd*jIK`O* zl7o7kIs`|a50c^W&Tx>w0bZvbOCr+`I9)+<-?9~1e*xAn2}>(r3|84|z_VvEiPd{}vu1}-@^0WPlAYOH^U|5QZf9nImd(`Yo4M5C31j5nG|qS4xbtfA57>oCkl zGcnz0Cge4miJ6VIR=e~X?Gu#jHrn{Dnkq)6H>k?)kNOpEfr=iNQ!2*7D4l*(SR3QZK>OY$*%v6tXWAn~1}i~}4yM=8Mg zeleHmH%>Ev{w}cv7knWEjGcwD@oJ3sv_=ljHZ0Cy&UPgJU?K(c zKnkV>rv(yqk(gjLz!v7*m%h;EZE0={i$faE2hI`q5sYP6977^LEIb(sz0y-g*#z*7<%ON2+2d@Scs-4~r3gCjS9#g&GcM9;L4*NJom) zk;{)Nb>{P^?)SccjWKcx3`=&rk9omeQ?^Q_s3EoCC<4~4>m z2i`#$mA+;xQlja0g3U52Zh#-8=i-2mFFoQUIrAAv8s86iquTEcZ;)!rCm^OZ?t__N zjVjfBDkl?9BXgMN4UKtXvR2i@b;eQVo6zCdV@x((UkgbK%e|(xWRHyvGg(A*t@=2O z9fJ90{6n{ODi3X%c8NQtIHspHbxwy*ju)^U@X4gx1bu zVA-LiE3t8Ghx?aTqm@liU9q>khW%WZ2$G72P+cqC2G9}>xFNEngK zHX~{0YycaN8SX@LJI-)N%GqrvIlJAC`mI&N!RB(1b>0Bp zJqs$k-1R3NKfpZ;x*0m-ENH5hbb)f(fcRO^bdBc&=hWW-Rh6l~Hxluw-;?R7|4%rN zPyHr|ss96z@u}Y=G4($JvWBVuS{;Tt^_!TU`c252`c2F{3tFXJvhP^4u}FBQjywU# zzXAkaJ@7VLq_M{Hfz$4Y*CJV%r{XQ*$#jdn0ad(3OcE_}FUWX{m?T={dXP1=NJkxp z*&-&UTf~IC7BMliMT!lVtXU^i$ZZiGwF+@(Nd0`BH@%;5J^l;!dCZ>$he8dI9y9z3 zTqG8J9gmSrQ&s8!lInWj>UPg+(DmBNm950z%&5)2Y#UNm=0b#q z8wpK7y^=^(sk?}NnvDM19_UdYl?qg;L5+cC%ulFRW_{%KdK}rYbFAGgEt5^y+1E-S zRVueN(2_*-Zgoy5a0xEDEAIS6Snn& z-zMGQ(}l0tNndVy%Vj8FexccO;BPsv?5PurQqZa%UW@ zd2)gDXRLDOEkIVPvQ8|K!>uqo<$DmWL3WA-!ZpZFi6V`|`4&BlPm|g6et4fYwzJHf zXJbI~e2z2c#FvrTb1VpwZMRk(hx3FdCn0~{pZPq96r!h(AnIx7m2%XUe2t->kG;8I zTS_T+gFDsV*bXWKbf?OI0z2K-0!K-=cuE$d=xZO-WxUwu6{HHRKFKQ5@{$ z;R~cu{N@CZ6<+v{oS7M9TI`u9Rt*&I+vSgm0P|6Wp z_Dm99@Q7W?0bjPkAP|>Tu+=W*PJ-8i zpQSC>3I!!;rJSg(vT>Nbh9@%4W>oVM;AI_>$ihg9b0f&pNDjapZdw**q&gEo4h3GW zF2J_zXB1&diiatuA0&SQFIQRg@@}%Eu5t<>`51WF_GGf9a{j^CcnP?Et(Vr=g8fgo zLJ6mx{oEfDYJVuPjz;ajOJtnW@dt-~?M;%kKM|x~`velTuLUxx_NIij{~G<6RQm)8 zYQGZ_zxD|vYQF)bQG4qiWzBV4;sboBDQUQYJx$gqPMm>gPULyIo4pU&j*{gH>w8t8 za>B9Ka4?$AFJG=zpMma5`f6SwtW_uABKXni0c+Y-n{X_%GWqqh%g1M^$yd8VjJ|&j50e zxe}Q^%;c(Cw;?^1>8O5STI*>bcM)l*+;6+~I{@SpB8^#qs+Ian(5ee;W;3n0Uljo= z#d~HO_#c79)y#BIwQj-ZUrcvZVa6gG>wZ-WRcwX#%u`^{1&I;N^i%jccL7|h*=g}= z&kidqUgg;tsNmbE94k0GQ&%vE_*lW&wc)QR60G3tI;vJNK3T!p$9ol=gB&Y3yRKKk z$B|e&k$Y0t?D>(5Oo{p=F-h$Wt=x29Ce2bL(ji}7aFmcS`CWo6$ z+=I1jrdFwsLuY;is~jM%RU@Qa#VWNmkhTkC2cJBERT#sU|AB8=J{n+p%GD`uHmrH)JaoHhInh+9K@DT|ecSg@Un+JTqwsplJDcpye#`vjj5? zy0+J%26&x@V%3y^7<3b7V4z)83ll=rJ&V2%`5_#5C$#&6!z>+*HCCJP&^EK46UON& zM@iW`7*-}%{z=F=0DBHR+QtyXd~J(CZ_TXlw1I6Wz)m?5ryzl`{VjcQY{#58fwFr_ znqo5-Sb3ckCnaK89C+hafbEIIpzUDpR0EN;%66lYZRf!eUbXNpe=bnUikGcPA`0`v zrEJJ@Yb&X{l z>(n(!e4#zH0y49Ka|=}L)^%!xK{f{2be?k|NRAB8wwJC6PsL#Sae}Q!Hg|0w^KH@T zm!i{q<5q{-v)miIpCM&swg9+7)eVHK<49X8Y^#uS%=a)*9o$i#0T9>Z7y&EPZBR}; z3ChL*+Xik^dQad*XvHzyIxlEr%Z=rg>earGjU?9O!w+ydjveS=%H$3JD`4xoj+^}x z`VN|kgYaMQPpGgF1}`rf3%*Tx8tE~^za#Ne3JLCE``W?Jh8p~A5?d%@4yCQf3S;~mPH z_z#8aI2&g+x%2POF43!NubVSVoxqkJdqeT zD{5I+AW?QJHt%Xr+*J#HNO9VNC9b_ce#t`nIhO?ot?ltZL+8)>U#7vjuEH41)DaR$Tj`^Y<|p@P08_$?fL9<%x(G;+;3D8INc@X{1QHhk*MKxG0^AG2Rk{W^Y9zFVhs%IT zXpOrQ>ug*S-Ji%f!TLsPm?T@{GqW`kNVLW?Ad_0dl(02cLXy-P2@fg{9ym|DvBU?%Ck+ME7<#Tj7ylxE~HCBL*Q3oWg?)t{;XPg7m_ zpOjkPRq9wEeJ_L!LAy1P!mCvDIiM%`s1$+4b%7@sQi+d?I+I0Lsm>@{P4KA=NXdD| zrGEv_1y%7YqC%QK5>au?OBV6A3htmK={VZ_)zBT)gI`wcgOa{*xCP@5`BL_mlMTU0B+6D` zbH6SK0&8%JavlZAjwrh{i5xgS;M@X|9f)zZ2_KJ}wrR@w5Hvdrx1@V9l4}~_ZZWPd z2EV2<(VE3~AwQM*H`GJ84^s9bw0pG=9@L<7^7C|=d&?AW*1y&vk~p8nRy73G3@&?CxiBFu>!b7lE$!(Yujye=#VBzxyIT{!*o0d>f)2 zzUUF|zqhIOYDQYf3ev$opA)waswFy_RtoHt)H`gek(!3XK>AzUiRu-)I}r~&>(xvc z?@C91?s3L|V2D=9&Dhon18lFHDxeI}D!B~pQl`;RV^p7mv5eaM8yMR;o7{!9=s5q@xl(4c!_NiNtf8m z;ncgtX4tK?4-{&Z-=>^V;Mq+U2Gm@`zq)YEowjv1-dmL_+lEhcZ6~!ET|1WN9Yov_ z!zmBOOSExwxWXzh&;#zmXxs+>!;mPWtF=Y}gF7qdFi3H2J)*X2jwg5O!Uiz;6m2*7 zu18V4H?yu&^zypt#d4Z7^_(!kFTDU+s1e{JYQHvXD*?^{-JmuLSffsZhjaZ#Cs}xVmB^TH!%x79-)_oQP>rD~Pa99t0WR zVLg%^1TwFgx5J{1MkRPZ1rA4`3Qgy&QD;ELD)7G6dbtC#9mA`spNcz(QPyOL4jLzfrF(w4})H<3w$b}Kvpt8Lkety0YE=)6r%{va{>V4 zQLJ^rPvcQw@2RsGW#Gknt0@I{bMN^Cg}HmrX>j1}JvgS%dI_Q)(8MRLk%LhS=hw+N z;T>5KPmb}EIDYriWgL+*u7-VXa2O`BHR?*k|G=%t%*HfZo~AP3Zupf<*AMcJjZ7P( zv>TZ=>II!+(95(@!f9haYF8c$I+wT5(?wZ32C8jpq3H64LFZJktU$SSs%*<;I~-e_ zXsWh1;e#)kCyVaEeF6KxDiyTy`0-`N5O6j%iNB*mbhVUXJ}KN2VG^qDRIS$ zjJVE2WtCH^}!iigzQwn)x-7AATIZ zY*D_={tLyF-GUN}bqt&+pm836o`JI6j%aQwa%#$$d+`lByRLL_TI+ax6?f8oNYUkE zsvJytio}AE)sZ7>ISk!;%Ym;--AeTSL^P+tZX6R^Vw3X}m@4%Xo9u00#3rjag5fvl zQu{HW6-SxA%%-^F4J|8b-nOjO9dRt}} zKv6NkNIPy?ZoECDMpdGP@WP1%8fqcLyY24MP}7Zu8q}*6I;io9_yP!9?1;@>pm;d) zTvt^7gU#M8e!LxqKW?#?AGWu=iB7r^6}dzEPeU2yKibYu@XA)T#t*((3btnBqxfiB z-PcE@ucd!I0gATDkJ^qxaniryc&auJlKstgmbKB2g`ID*f7(t9j~%~MGhJBhUPLV8 z^O)TU`LbGUPSf-s+ZhQ{b^}&FU|R>#lpnL5X|QDDJ4=!1%|s~@B~0u_UCw5r2*`Oz z&@=Zy>lP;UVY_zFc@3Ur5A5Gw?}3F#$R79)Ox-YArsB7s9vf2m9>HpM%?V zXi85YE%CAKJdGyi5Vgi1(x$^{IsvASviCl-`8Cht2atb;`2#k`Ldi~;Ol9ppx1C1d zIDnnU(dHjB@i!6&nfMrqpP1+i%|A%+g$co^o4WAbO*Ve8^We)UQ6IJCyf5=B;P#7$ zv8NniikDPX>Mi7zwb>i!g-BJj!1p9)ydL-#s*2X}v?U&@)F|#79efiym;1@i&)wZ{ zdg*XpKoz+=esf(?1jo5eTb#xqyqIk&p` z@g3a}@2pU1JJCaJv5wSPuAX}lHv}%%Me;1XxG#h|(YVfP^%Tgmfk!OsTBC`8mj#lr z8Eex^djcyvidviE8MmgFvVHI>j40)f;@?Qf9mPf{UhXKCG>6?< z^s2L7Ij4eVqv5qm^$A}3Hri(P175rHd=$NrflgD4eU!~qQJ8_6q)QW3w2Y^r9>|V( z%2&%QnZqe3bLDRI^6Ox#)MzBtXTB&tQ(a}uR9Cw*)#Y$MNT;uJ(=Wl&oineo>Cl}s zbz0`kYwWjyV-(g|%F5w%4AYaEGHi=&y%gxUi`~8eE#e(6i}Si-!sF0?E3gy2Q#=lN znaFkpPKUbqcI4kD|9XHwT{`?*re6zi(kq#Sl6G-7c`e}l4ySCuN!+_<>#}90D+!id z!;mr|>>n(*Zbhctx`U8a_8>myYqjjOxXN9K`G@W3&Ot{^_ML$99$1-!#-}Zl3R)=H zDsI(H@4|Zm+=a!lClJSb0#1X@rsG=L++)Xs6~{95wKCa{0?rnXwFZqsO^WAvDwr#>mxYg5P;)#>65dIw0Xrz-i0f#*;4k zE#TaUgMduHVeGVW3e*}2PQaxy`AV#Hw2?H~UjgS77)g`CsT|?VzIr3z3^~a=5OGvI zu33y2tNhJ?^B`C$G7WW+B6nc0$(;Ws5^k{^ATOA1-wHT?z%V{QUQS~Bcmu@kN3)(O zw)3tRvK)qbm~5(D^NHtFE$W51)s#CPwykZdR3^|eG?6!fVwc;Zg|jKV@C^tv?Gdue zU8jYdSOy+NMs_hvaTk*?AJ?YRvbAmJlE z#Y;Lg%XY3!)bO~Z6)!-grcB;yTd$}}smDfWy?P8hf{Yvp8mkw0An1CsJ`gmPiT`mm zN2dDMW!f*k8mt@^UK4iw1YJl+6jEI9AFS5Icy~S!QfBPgT2Kc9=R@2#f&-bcw;>@j z_CH9-jLo@uXmAPV=Ilq3=H?eT+qU#keNOr@(Oy0(GqxPWZ1<}_D^*25C`PjRn|w7D zX)E(W$ZeUTCn8m)Hgbx-*7p&gqAxP0=!v{vmV8Bar-J6Mg7p6-o!m{F)}iWl#HU{_j=)x0KO$z z-oobGQarUc?(i_*(#;R=t0(g2HYf6uRFu1fb8<7=c^|&m!eyMOC+qTMHys;vhQcuq zf(bLXyZ30N47p)JCm%}g&^7HwB|JUb&hlE=&O!*~w5+TlN*!*xX=yvn5IK9+4QGqV zwy~WZU>T0H0Ttr0#F>kP98Stkg4K3YkH@*cLC+B}K@Ak2jN>V-30jD!z3sF)#XC*> zz_2dP#Q2cY!cKBph~>-2VNkaPDkqOU+>^&ok(Zgir<{ilDx>IwQ?dWD_50Yb@ucSx zl-;Td#o-mhyS%UMEQcY-nKKCD#Y}vIn%u_3OGwZTj7Mo>)>~cJQlMmEkbI{I>5KxLx5x^Z$*IQbq3NlGjo=7(i|3{u#+iIdA-o-|!CP;eLf2bw zy9qA0u!g1w<_W!=>42;pV!=%g@HBTMmk2dEFc~`nj$Cb8LwNF2UPT!s9~-Ju*#JX* zT-FW_sfFj<$7F=b-K2s4xTCE~?L^nBYkf5vhPNVbX9e)w3U4)K6X@D%*YP3i&kuP? zku}8aTRvNr$6BqloO{UN@rSbOp{_r}#{xDkjOQ zv;gTg;rI`<-2~Vbe*m1Ldhix`I4+M^_a6_3TWt3c>wXmLKVm(kO{LfHi1lVz`z>#h zZ21d88jo0yn6`Mt`Uq(E5v$au&KiV+m$-h|p2WwSCWcDjD2dk2)Q2EOqunpZ4C=-K8f9M9@OlH_i)se^Y)F;&qS?7aWqu$o~kD#BJdbZozm(Q1#h?!OUaN++J^tPn9$z+xfW%gkQ z+y_7%2H?(2UAE)Y@jaZHPH(OLgPpe`ANN#{=Ee4y;YG~!R#QO8S0bmMqW%K|x$!c+ zkEG$AWjv{}`G*Xj?SZFW3RA%Tj6qFN(%F!^CCSu)8yvXDqb^K9-Q|YQdMo_0I7?Rg z3YiR6s>@_Xl9T8|Q<28pGmfsF@P*qr_f)B)?SSq|L|3Vc)9&DOddSCRI_-q|6-3$~S;LeZmFJGD~djPGJ_K+JCr-FhT z)17Ifux|m!!USxao9y-JPIItqb4$MelW(#s)14`Z)cp?7SZMZYmb+!as&r=qSPlqh z5CXnLoN#4hv6gXvDOi#2Y(x>VvT+XTxryubN zcPf8{(6R#QqA)I$7=t%h>>vR#^5Tg%y@7K_#xRA^InRKVOXTxWnp`4(Jl0z#$uDxfUE`X-%C(&C7;t8s&kPrzT;(TxumZWS}y5xe!{3og-7GdUI|*P?W=&6 zYx|sS&>loWzV(%$!Xm#WP`w1weaW)ZwQQ6HX-;R1R9Sl39<38!db&%uMUZ`XLz<%? z-P!7~`d7pFWvR@&G37Td#O;m7y|Kx8 z3|YGct{iNhHQKx>F4sbtyGZbwJM;Nn_>&+WQ><5)C>#p6gmJ$HIUW|z!Hi%vcb}5G z)wL|Hh7FvKT)MsFa~FI!60+iNH^SL^Oeuwt zwyDdJK6H_?3UiLwscVsGaxpTwb%JTzkU66_?l06HmktksI+nt{A1l2j1XkLIVE@Fs zuy(y?g;g%w5o|d4JcMbf2L1fwV0C%-v4Jr%nmf$=Zr|f1+jIKs2%o=!LuSdoq0jS=Zt7532eF^0TUt zkv2XRYXWl0p26O(@H?EURUmgdTwA&GuvNJ?V;jg_i>;lz8QWm)PHaQD`>;*P{Sn*L z+%&jK%dLlPdTtAB!?~TY&B!goww4v$fRE?!R)ZCLFg?O!i_NfaLJ! zZ_ZTQ=L8Ltx1tRJUy4g-b(UgRxD-=Xw3kPnt?GFtgqgCU=Yrw@P{S2_*tKF9#wdu+ zfoL7xYNX<@(6MX=@-ER)Ci*3i^ml=dHqj`MoC?K+@j>I^INcfpjN2!9)iFnND%NL^5kIur1fq%N#REe8B3sj1bdmjI_=T2L3MoM}q;lkB6>pF!1rA66GvqjCUu zA~jvrPqG>Wcmk;zDnE&u19&y5nW{+=^(f#ENX?2{ST;zp{pzk*3S=A6D@^odAkmM2&Q-5qN|wRv&SMFKzc_8LDY)=0lv+LfX@iX4%L;R)$dJYNC5MeWW{c1 zV)jg(4fmlWRsswD@T)p2a2f#DQgau9yNw=41o)$;DqRYRlt6c9N92bG>PrcuJeNbo z*Dl|G`fxey5IyMAakU zPwvUb@n{!_o}{R!h-y68$Igf7HN4e8*_Uirm4efpu(X)$aaIGK4>g#IVRQTpY#PqR z=F; zYGzLgDl08z#&h^%X=XduDHseYfIU3r(!%LT@&q8ID+5Tc&;7peMi1B%Av(fD&jNB8(J=hk-xHar5gY*?{S*i1f{RtwUc{V%F<5|~ zUeEd*nGMWbqS7LFBk?tWg4wDitT#ND|Q4NYg{l-4#zHM6-6LDjq>ZX z+=`uzY|2{PNw`6FZ0$wnyP|8s-Gd)SDp=roml;pU`j61hLKTo=tyU7nVr~8gBC(=7 zq2Pg~V6l21fE%As*ms^n=UjmX4IXF~9Lvw(u;z1tEk#oY$Dq@0u4h?))kbDKcOjL2 z16#Yrqd?!SgR|KQ_{ugAnZK=!j{v9Chj^kXt_$R3qLUKDg8+@M19-9_&X@v}(FUiu zXxw}2MWD7Jw%~=*nXPvsAHwsj;8e+HD2yVucJLy%vuSE&6awY=3SMlWtxJFmr0opX z*Bs>MGe6Vy^)T{Z(rR|x$~{OiEGy$za4qt{Us^NY9o!W1m)FeC0rw#JD{JPT2PfrU zRTCc`E>-&#A_?M}|3OsLKu0p~e-Mp?NW!`P-$ku&f#?;s(E<^*ei`{pJcbP3DEW+k zknhkC`9;ZHmvI{4%Sqi-jj9CvBB{!1)JK4i%LjE!GS#{eu*0&KyRi&K{wC&ExUt-b z{L?h8N;b{d1vt131(K)YH|dDByvlo~=fW0DKdv=c-Zb0l!P? z`D)Zbz@u;vCb%f+{-!)H~Ivmq6W1>b+{zK~O==yTSL9smxSP=zHBs*K%{8m{YI|;cp{klD+jA z1f5YIHZuQyx*GWe>OUT}-=)?=5EiR8EL#5kAwP5{_Cgidd*Th4sX1E*f^tMV@g1Z& zTL(gJz7f)#fdh5j{0O8u0|&C*{A#2*+XT9~`A?DNY!m42=9?hR86Ysk&5uEvGeBUd zxek0Z8igYefC`>eLj@J+{nYMb63u>_lbh=X*yPq3*QypAns_XxIcfn$%= zisvnM?_m0+Y!f%v$IZDt9Ce^)GufvGS@-lgYzwBW=p>IC;8OJAQWDc}7Em|XNecYd zZhtujmeuNenA%6|^hr{n+Uun-dx`}fwWYwRp4V^%JmDzs@xQq|9f_&tQzQ8O zf4uEKYqmebGR zX3h4$dVHOl?Yp3vxzpR(N%rV4kIG3hwW2qJ;+}6ut69D1QT3`>edjrh#jUJpc2q~u zAZ}nqy91RH@=fg+4=pgY3xIN3u^Y#=dU!nKQBC6pn)(nFXB@kEH7kWFMW~k5teS)3 zWMsFhW>w))ZK_#a4T|%W-L{(5BOcYhn$=!VoWksm)vWmI3_^8Ew(@tT4syiDE;S0f zK+wL-&UysX0Cy7m3jFHz6Uem2&S1~Aqi-T@<7C#p)}~Q$q_a?9v4M;+xNQl6?>jh#^(ziRi&qVz*UN; z8kJu_*{v>oZvEeU@)!9;x$S@Rxe-c<^O=A3X+?kYL_7Y~ofSO|oh@bV{2x56^hB@z zyC-*^-sSeXp0)QFV?aY6XlOJV)r$TJ$8xOr&>jcC9WgG|7DHC3k6cQ+La4;yjmOO6 zu_v6%!_t6&JWOCZX!i@`e!)x4+~2WPxyJzvfK769WNvULS*4Z#^tl04L0@g1GC2M7XfJ%Ry z(%AKY`B!6Es{?1@@=n8%TwLiiUuIib3j?tSAmRUxWvvNZW=IMlxdnHDvlazn??b}L zK5JcI2i)p7Vt;$^hQP;YO&4}&$yk$d0hx!h?o2Q#_TY`xO)ds^`xz+Z9?h`|;dHi6 ztOl(H@GmzkD!H3Fv zRJH$rwE<8dz$2>t*BZzaV5@5XhX9>Jf80!yhg99rGX-e!tS^-xNQ9oH`@T^T7AO7m zHPXPPl@2Nlu)QlW);Pe9G(ef|0OM_4e}G9Qae%!K55@pv)_n{Rd#}p!1{m#B`d&(7 z>NflvX9qZ49oU9G(r~0ZE;YRYb{ZslfbBIT{UPxN*fdD=0Q(AVRl39xtMcFtfgWNh z@yKam>^X2e&|`p^CSQB-#_A@=qe1ilbKS8D;fZXW$Qg*n8(`g_(*rE-+SSF*1*ZpC zvX9t};Pe2iX7?~SJ;37ajBmh)s`{h`HGPA#t6Zh z#z@0SsP)=4_&M_(Cj^Vm!cUoJFAKC^i|(}Wy9CPm2R^dD45&zUM|}SYK=ztImsjvC zUWl&(D(gLD{?irf;xlZF>U@0RHkz&MuFt`5wryM8LQ#BV9f0Zxp%A7VF0^Ztk4y?O zToQgcGpRNTtsD9UWHkGuK-NJd=F+P|$ z2(vY`*#M7Vq~g!r7`DaLB?gQ29MUr3cc1c|jx#YG#(cDHHWm%K%@|vb?4N`t+fm$) zQR&(3*pgp%!vgz!z_$frTky$ae)a|S2_SVb(xS0HJ#MDSNdw0EHPUvMn4E+cTkmm~ znOp;w9sAbfE;l)jC@a<;Q+2z+h-H!el7uURA#!6Mta`^WJo}+QY(ir#Sz>=<)MyDL zv)V%Pa3FSBQ)Lapm#(vKF}=iI@Zja9W$d_S%Cd*T@;1ABA)Cl8a~T}+L?Qc;Ky0xm zS#6&q61Np^gXC^X9u34I&G9!t^s?6U5*z8k8%)dCy@1=Yo*NTF`4#Y!gzrs&PicX> z1oXWr!O0T9MTEB`zsK$_@T;ls2@pyrvpw)h5FG1_<6w3b%**f z6E3QYhtXFNe$pFyGSH>-ibi_mQzmH@-3R<4{C!&XGl}?bz{?iG*>-QZ78TuA zYGt7V{-0Z zu)^csH#v7N*ynK{nw-05b;lv)_r56a6O(hxyV2tgCUfx_$BKR8ss3xK7?s<6u~wL( zq=+Ar1y<}*kNe5w;)5Xek|)Rx8ncPSUep3*6rGLObA!4c+<`M2c=utzPtdp(+X-ka zrS*dGZnI*?x7Tp}V7%9@*a*OFsg5P6H+pbhg8E0meek!c+0D%m-6lMxgXW4%&Ykco zJ?=!4qn+8j2Rv05Q)M)7`;NMZuE_!`HrM02nViwQZ+HU76u3j<#FLbDeLu9q873#j zZsq2Bg7Gy9%v!wTNheg38dWLmq)R-%MwJ!2$P-MgCNL_s-BV2p#%KL7XZNtXLlkt@ ztpA>l zVYR46?_swOMtZ6h|E@ASVymZLTeIHijg)RWfOY>awPI&_s`WLij0WB4N$)VF(l4@c zYjk{fUF?>cRYruDdeVpfU24TX_f%VJRv8fv=%LGgwq~i@?=M0%@*MR0^Fi9`V?}#! z#?#YYR!?Oe7eW8M802ZaaYS(iMWZ2@*conK_NFh+a8_(H@IUa*emlszdPgYhWSolg zIQ&imJjjFh1Q~%o-H0s%{0-jO9|hmUsgUR7H$Zk2@F!;I{+wgQPWz7*95e-fo9nu* z@Kj&dsIp>TdV+6E0rx)bp1R18l2;?mY&cXt(?Bh&<5lHhs zS`ak_$$`xERP}09S+Vy$LCh2wfwbzYtY!5PNJCR#1hT*rv@iw9fgJQyMK!9dSf75n zoYtnm2xK(`U&atfTT@^J@`oqrW(tx68G5RA)1yX}6?@PVoNNk=K*Ig8#t5rdvU`Vk zvqSI73MP1QwK#vfVCB8*aVjO=Q|=j5UL%~C%;3pM z#N^^*FfnE2&4Km+^|}9F^kEsodB4M;^b8oq3?nOV1fVAgH`K7~VtH?QaAN}w59osa z%NsOUoAflf7leBWT#q4ecZ%kC6b`%GK;XjlGdb7iv*2PwVdof}mDd)Kz-Jn;4&y$L zJICbQqMDwGb5gvs&viK~Z#{Csvw)1zYS~ld4)^DIxMydbf-hL&hDsaW$I6Eg_n5!@ z2h&q_d7$VdBxd8CJvb0ZKYAj_qD9E=A~eK#{(Dc4b9O+a~FgAk#@T!vIM(&Xj|d- zXfAFiJ(q$ui@b_kKb$loNBA&nmST5=g7K#r?Ba`oM)q`aA7MpO@%PxFF(N#eQvU~> z*F}CyQRzXpRLntt%wV7Vo$>-KReC!6aTk)7|9~R$U5fwUBJx8@>c$qPP83$G4x*P{ zu9Zp?H%hCh6W|Kgb&zQjf3y?f;$j(b-=v@o_MiwnY6!V@b7bHMW+y)!{xf~+S;G`ScZDpDErhl)Jd$^@#Txy~C9x8T3ALd!*d zYEYg{RU+ftiQI~$W6+BG0hFJE{Y*t(x1%3Gn#LV-uYDN%Xt*)@!x$=W+C6da+S`E4nijy6Cu~deNMo z-_6ANQ)F3M`@L{wwI7Sy=2qgvU(O<88MQRLFRh!vD+Rs;@IkyI z2hyqx^$#9=DDBC(x@ZIn>p-ur=@lJ2s0K1 zk%?(oAJa4)g_WkIkECI=CvsbfoF~D$Xk;un-ua9SOp89@DaK3O=@-*3az3^)YYa-0 z!r3b)^JKa`N_G3EGgF9T6xu^YE=UV<((?kCk(Pdi1n?GA62L;Kzl%n$_5zri7R`md zC>Bdoq%V{J`0PUhn3g7$P6)sqxeP#A%|es%u{`4FEhy$rLQ-6|`mwz588dPKl# z$f3-Em-A8<{|fjG;^zd?GK0wEU_s*N0PtUL%zf(S!UqXuGzP?HBRQY{7kQI%)n95z zo)Xcm_VR;)TNz{Eg-Y`v>BfP z<@17^-%Yfjj{CSE=Pwf-4V2F_a{l3u?0Kc}VJn|iUww;>s>x!Xg5&+;oW=%c#TsV0H;QvwCcx(a z=B=8Xwu-%?<0x7U_)ENVI^v5C93yTFMLz-So(;T5B0c~Zcix;n9?nr?#TEb`iGxs% zqwYtwT=%l>L>%gxc}K~dU9s0;z*|u{XDdFb(*|q+R~w6f93A(5bLE4ML9Z}D@@K0SF5IZs%!pTrK|Tiq`d2u zv%qXH2CfBvc!HZv0e5pP=$5NJRG9*QH`S^uJk`1yRaWd-2zb{k=U!7_1d;|)1P_@4 zBai`}V4EpO4rGz1dag#5725>??|S9DY6^@%T7ne8Zc|_cGTjsGF$KwiJm;zQ)u^&! znYiP{yIwg5O@R@}d7j{~DKG-r>+tQDw#Y;f@#YdgTNI#!h7fve6UN zG6hB;M?FE7DM$|FRNT;#a_ZNpvSQ02;9akr#-_js-+jA2KhDRk#@- zckSGd6XkA1g&%^he=2PD)}}Yvh|qNzK(L%ibNAIq7lD>q9*EOYHmhS54hDT0tNT@9 z9|Xh=4#TMKcLZN8yapdzm^>ua7ryXm0ACaQMvPofM*$R|X>-4mHW5bTP1*o$kKg^t z{egM^;@_$>xG_#rMmNP~STk%s#-?uQN!)Kzk-El(BbTF9zYb6lUgF7hKsNrZao&8a zOnZ-;O^bM%+H<*HsdgJ4|6v^ymqO0@9;8E4Nc2jz>kP?%A>o|}E`?kPiC(ET5^hzx#1Z4q z>k7Of@DXmA9(aMP{)ouVO7o`4DNXliU z+8~6lSE`kwHDsll=PN?eTd77+nmTDUW1Wv*#}N6?8`!+In?vTIV|vKE(cd33v*E}e zGLlIgGNCC6Lx$NfWq5A=r$1x}sPr(Uu`Pi0;>P9JsWlvlo)#Z6zd)jg%r-;P7!q&D z6yic%51DMZRp}B(%<%-|z>Z*k+<%+$2F@jRM%iyI~5EpGgWj4W6vS3c*OlpSv+^xwtV&Vz6A?C~V#{ek@$v=wmtze{mxT>`mwSiyMy)8w)@hL0GXJ9yilAIBCFGty%u!MuU^^V&{9@Wu{#-mK}S@<1RNj zjwmbkJ2<_#@s2?ZS85Ttcw&5UWA3H?;>MRm;?`)$&MdXIbGW4fyFKDWd0oIEfjS$@~ zE4f~CMP~T!gtyA$PBgjX=KaA_bum>&^Y)yti|CpxuwplQTsM<5n)d@w;Ftn;Xmq>5 zU)*TaON`yh-RKF%o5sE%eps?%`#kA{YEq*rZ5H^88j}Ow1)QF>hvrM&ySP}~SaTqkc!FO|L2@9kc&guPR9Ug;GF{Feroaf~JP7pS#+n0p z))ShUFK#phMvMH{6LhPw z2tCwFZqsgh)TpvzcYA`9O@R@JTIt?(^%pntoKa7}XLy{qxKTL9E5&QoMo;A}ZmdD& z>S<}kj(K`-aii$j#Q2%WRXQ4PabuD%SGC4dd5arsQ0WHx5z>Ukjg(qNr>-^@H@c@$ zYXBuIZWLwoFkrp7aWG8XtE^~`+cml@#OrPMQZa7Md@Ji}O0K#nng&-dNlihocJtUqbkG>2zJ-=Rm#1jUwiq4J+DX zoxiw|fUe*&58V?|!@QUy|BQ$)ZtS++U)*TeE%ng7hF$b9P`$X((DvEjFK&#Nk#{Rl zZ*e2Tw4z@C(Tf||ByP{P-r`2z$jUqMuK40cfjJ{sd5b(4iyM7duPRL6 z7+>5N=iF6=^T2tF8-?RhSTAn;!{e~HG0wS*8!x;Y19>P05EeK3oR#;w2V-%g59=`c z-=j^ixG~PTVeA0sEp8-d4etWUGpF|_=*5k^k0py6>xQaE;uL_Z z6!9F}TcyZba^c=^8Rl(6E7BZt-lF3wMei0ES1DGEjIUBmsqj}RCYp!85+4ho^;Ri1 z8xGfcm7)|Q7E)Gp3OKz=kwAEm4A#v+^(w{9J{rp$;jdDp2Rk0K6slJ#UgW7ZrPQdB z){MOmm0qRDa`kFMDLvNp9L>Fv;&QUu(B)Qw)2kF2S%O`?|Hs*v2ijDHZ?Aps;NEkN zd)&jd?{)UQm#*l#nMq`fuBn8QP#F?3g;IvhMTUf;kkTZSQi(*f2BkR)rBb4aO0(j7 z-gm8a&U=P_zwi70IBV_wJkJ{T+H3E<_S(N|)jp)KXq=>_+2KBu|}_U6=Ob^;lGS-yu)l zk8mkA158s7>{7I8RE2wDY1VTZnttT!!KK&|Y1r;VE=Aj2(kke3sCem8+yz0@rN|`d zj7#x%kZ~?Ws--IPuu)N$Vl<8J!PFRWF2!)h+uR25@!7^q^zogEPRC8gKE5vKqD~%s zeAEv7{LZE`KEC&@oPB&1(dXF5w*={ok8cYU{&K2otTC;R&*qxo<9nG(jrZ}rf?U|g zM?0B)e6(PFd<7Zj4aP;29Bq#cz;0`F)|_bos+$e z;lBVIN81R7wR-5420oH?YfN3X2XNHUMoRxvluNz&IDfFCjT*{0+O`d#${9x+3E~}X zqbOniF7$lkXrszzGnzLJ9QQdm+S(%B9tKAnf*ozNQ~xJN+ZR+~)X_$3{zC)>hFxVHZO5?gWXGteqm3bcG{BZCjlS#-pdFO#Mj>wO%65avW zINE5hm_1aMHXL^!aIdkWjrS+-;u5`% zk|owbZMj72Xk$HfT;+|noOQG%a>52s0Y{rCN3=*EEBHVPL`5F3f<01@*djk!)q#{M<+U6Wb+o0f$Q&y;CUX!KdCv-t zOF?2qys@U76Dd{78w!DOw56`d7Apw)gg{gzW1PvMvJ@m%TxXnZWo$C`|B34c2P(fFD7LoMO`>{$VsBeRcB}fc(4Td{PPF`~ z;Mv^P*kOkm@hX1}Pb7~dgZ?lp6zXCITa~G4p^yk{Tn=;SKYHy^CjcW=C%?% zmrq-z^3Mm)4!5>WCLSyMDNuP~6vY;|noj;CDA?n6uEPz%iu{LxvdOK3PN#GG5GcFc z%60R^vaGML1K8%)i4#Qc1K})ElW=9M9L}grf7m?_6{zfG=ppS40G0DHBDYbDcQmpa zQlohtCOFz9)G=c_AtgJp>86gnDPR zMS7e0>lPl6K@ZwBY>Z{!f@7D^m2pV|6Ae5vIZ0h`>=GJnII63E)Cg+kPN)sLgz_`I z?$FVb)5>E+)>`L{1II3*iAi~QOTn>AXmWD8E#TNCG)1(N$#Wk#_Uz5hpe8qMcqX^> zZ5iCqej*g#pcp^VP;5V2$>_pOSoF@VGCqt)AUAHJmF!CF;7a``BlrqIIO7;*p4h}l zCjh>$q@>9=K~5gs0a_Dd-dZ$QPkcMAN@=Bn^s`T5yb|v(x)LqR{-SC#;{8QTSbx#j zoABr(-d}VQ87KIQ>W%_r{Y4{a#rli3(nzlaH{Dd(pHk(T^L2@=7Qzlhn>o{wfq{-P*msuA@U5uv=NwnY6!y{@5y zY67>UJ3Hnt`eJ9)Uo-`zsD$$By=l1X(*(y2=uNiVM9FdWyiYARS#mR}Y_Ie!ljn_+ zqaLNa>%bX*QTiCFE^kHNhYMr=qJ37fD6KY2^cH;riT!w5$6Zl>k;uin-NMUcO79E6 zbZZ8G(F9TEXUNd{i-x{!B&*U^iZTyEV*N$GL1I3hCUWu4eaFBL$duk9z{X!BHp2S? zu=#kJgzLSlZvyf0G*P@a4Y2VSN%$SW#$QCe(Cl*0doSuQlJH2t#$P1i=K&jkk$}r8 zy)XPl-1Ug{^Uf<9Xi4%HMM+h*5qQ*JByjbC@E7rpF6#{_>Mvr*dk9dRzlis@_bXuI zFKRr_Zlyj@^A@0=S$|QR52OB~eyodCAa5~r)?YLiI^!=&%+K3xxi`}i^YE&Fgg&kP zMdAqI^N}~&a(iS?*GIuN%Y7_4eH3KwHhJ!qoIbLKf-@gaODgYK%N>^K;?FqB3+*vE z{47;eE8TqFAS?JKQ2>{P<&H}()(O0fk4^4X(nbBa?qwsuML(X#`$2b{=YdE4MS8D? zK8gB^Voi>(q**wU9@|UGdlazo7fJPB7A}lacid|XK4-`(>Rq-e&tv?iWgd?i#DWnUAN5rsu?Z<9@b+p)zq) z5W6fXuj8jCuVG12u_-I9>gtp#jQ5S=IfiRiZ&J`qGsBpp^1{;XrTEOIEcpwMx{m z-a(V$lm9JM-U_SQlv*WfnE92-@P*V;z2E0RMYp8z7g1V$Mf5MTXFPM-+Y6QXcp8oC zjfxASK$X?`TKJ3j^hNs_ACv@c{6(~__JX?;u=#kJgxy01-jhx>Fhd+~Fks^^3XHa; zD{nhs<1Z3bk9HEA&A%~%!*biAZEjELR`qR470&Bc@SPOU>DlCvept_`!C#cRB9~gh zA5xH5kw>lSuaqiuPb>Ia3PeS^AJLO;_;_0Cifpig3K>F>SP}oXCY$V(D&-Baf`Al= zio6Jc@fV45#IEtaGlG1XLt;fHSXH%@D&>7>1)da$ik$g<)L)dkBDY#WsmvjA<<&iAO0@nW)>9KJZ-(WpzbGLut@_xi ztiLFQ$}~{DpA!5PD!kUh@E1j4Q;nZ32Y*qF)77}@R9|tMM1nJeKhno$(}1Ji=cz^O2~(h^FNH^oYt&(}pVV7RcF`0)LU60waIX zwplTM(X0(oe^GpLe>vyz9kkY8^yp*A+W3pO7*4@u<^KxK_=^beFQP5WKkM5RWJoM!DlVVPPy7e~}A?e?HYU)|l2` zWOGgM7j>X);{8P>$c6nyw3FFiL<=#0(NCLk(IkIS&dt~bjh0d9J-Z2|YJX7|08aL| zR1L4r(*{0}HIm_@46g)i{6%jGbr3l-d?f3~n7V8#;HbZd^7a2oxzzg}=Z{?#@x?4^ zDB~~c@f20g_=`vo?=O0i66Rlqvx@N-QDw6k&D#Rb`iu5h#Zazy_G^?bZ#zQkFQUBT z>^<@Rq6ugZ_7_pzgum!LuD~JG()f#L`?DF%+ifcVe^EW8XT?HpitNw10yN=m{Y8{< zTm|C&MfYObI@K4mBDfl`zle6~|Ku+^9m1Huh}Qgd2nu-5SbtFytUK8;D(Wv{h#w8a z`-`Hu3S5p{w7=*bOtw4O%_;BVy;wH>B711VUvw|D+FvBJfzN^JFJ?*fw5`@(B+)B@ zYJXA7IkD0j;fiDYMLQudU(6B;&;P8RTE-W%B-{K% z%4``u_%{BcKas$EF^eA0==un)*YbINj}iT17B!row91=lIqNTCF6J-NsyD65`ioMi zWQkQ?FeO@l5$mbrDzBgAtiLEBFRgmes;s{#g-SPtcN9|NFA@z#6*q!LFB-uT*`joq z8^L%hSS|(8!_=s@S=D_hRmxK@8T-(BDG(Jo&kCND0#T8p2Sei&D49U@Q1Q3PeSou!22OkXRAt6;sZElq%(QhroO>D|JOyS-~-xgQ&>2R&ZPj z5-W1{4pYvFlq%)ThQRoXQdi^?D+v08Kvbmk)u_Kn2oftY#i}AQo2UvOGlRhRi$pe} zkJNb02+ou_h>DE0g2qx1Ey8rx9aeQtN>z%x3sq?iPW9o8xwt+$?tG`P>g&dEbBE(^ zO=pbubbjJT_3SUY)yZ!U34b|jsdmX+itC1-0+oL?DE1fKnMB<2NslHdiWA8DC@CdY(ZJ|K)eNo32Q<5bq(e};w>mMka2f^w8rtOcdzBCMpcpmZXYwV?2dwV)g%hAk*Jqh`q#6o;~83rgxw+%zEmXCM4Y z^lyM)(q{4}Zs;S&sVyi!k|t_F;qCtq3rdGE=&7;)@1s?JXTtL6%gIR=6y`4?K4w9Q zVme{Wg2Ke*F)>+CqL>tu1%-*d*djl*ov@(96aE^p{K$gBET!;MYX}Pp6I4^qPX{6` zSx^!rf+Y(Iv$da()`cu6QOr~$YC$1Fd7}b8`~Q8PET(bI3k2t_SR1pTtSH2nv+)88 z{=aVrNKpxV4#RTSOO6}RYg%N|O_Us0&s%1>$&%a2Rr<K=d3yQ#>1s?tXKHkw~xwWw8@SX$ze;-3$e?V~-6yD$7V}OkX zWiyX;&aNfhA42Fo3nT&xp#FIYj9bWuO9d)et_=&*R#g#W*f_k->@6M#o8D1@Vu zfXpXuV!I8W5joSqk@VPJ!s9}~#)2Z%Pg%GyPVLn7*-zYvD)J@7yV!DNvikajx5jey zC70N|C#>phsS?fGt)3~qd7?mht1Z_;a-w;Ewt@?#KzEJa^?lZYBDRYY>y3NF3WmzW zQ94#*lbmI zrf!kM?v&HS;s;LZYUEGQCw-@<#+sRm|<;}tbW-)xOB^1k$i z7z)`;t_N%^D5C1oPJ$Dq6&y|%f@quDQ+f-N&9^C4IImm5cTzy7XOqM85YTH~u%L)? zL`A~q7{MP>kXVr+R`pj(6}qPt{4E8dBL0>>`-z*>6&Y#;6*7b%u_8OHDm$f0dDUB) zaspByDl!QIV?hz+h!)vn1^F_E#ELX(ZL+DBQl-3Gt-zB4QIT&Tpm`bme_!f~bZlb; zrBaYsk+oJ;mQtm>thOebx>6u2G6Vu+K}lVa*Q}t0%ptKNwc43%TBcOtomDGnEd`TD91!tOX^7${dSFAdUOP4M|m5n-0F11%=K}%3BF2&Vs_q{G)))CvFZxr|+`z zTc2mpr5T+GWo_YYK&=IZPkOw;`QHLIpSU5wh&z<~q81b(UIo}#P=xpop!O3tF>ztn zj=rb`B?jj|0N7YiL>~VDwV$|QG0kkK{Jx!h)`CKS*}%;f-IMY4YFp>LgAc|mC<8nD z?Em+PbkAG#Q;{y;>*BK(6rsJ=q6dYx@GYSB6E{>%m0zu^&stDubM&4qyauSXpz!7- z92&EU;ZShaf)eARCC9q5smSxt+fUs5?|MIX;lf%M zpw%zJi3tDS7fqxJrvkPX6oz@+Q24opVL^$)#`|$aHLYeW&{X032QP5fo$`GF~YC+**I0cuL{}?!9K_S5ZF{+{Re*$Vg zakDszdfn4})`CJgq{ZsYg&GUWW~_%fjp+9zWvbWNH?1M#>w+V~Zg7ONMtp#O`O`|Hzh^4ue)6n#zwV=F# zG}eOhuI(;q6?8dNytJVF2|?6?!X)X81*IlxA7??KTB@?HfTI?aXd2yvQ&>>a(C65K zVjDBjf)YZf;1TBk_Bb)!`N+&3NTlSm*cW9m!mBx zZv%F+8_+TDeQn_bS;rV|%5bl2pS7TLLvpKr&B8~r#xTt4va?ZO)Ph3!`rA-0^+x0T z!4?#1C}TkhRG`Wk3knJ1Ehv9cxu|LT-xeT3i8| z@U|8d$~dk9@fMUmn3_&yK^cTB*n&bk^?$OUjHD8ypSYnl|5$x)kD!c0O9_y$FOsBkyFT=92px8qj7L-2FY72_c29^WW78Hqo z3RHjMMxuokaf3(Sq&fA1DD7!naf}6J76itEA{5>Zz~&P-63)ueQ_J|ojfA@ZjB%pNLR1~_U#;r*#CC|>}Ne&R;pb#nE=%YWL& zIQ1Glc>!)LC<7m{+571%#T#X|OjuB!L;_<$p~o}2K0@pL4gr5~#{Ov=HJqQc_y|eZ zaMpstT+D)^RX16cwV$r9hOdTT*pJ#}2=DsBWnSiurU21&&>!mOe}B^8Buz zqrjiGrLIVCD>x%&=!;l;Msyw#m5#9qE!CB@cfCJeBW}) zkOPtH3Gi$|sg|0r?U~K>1kdH`4Y~+CTTqI8-)=;$DNuR$peVMWWcc!zLctc4>OO7= zR^-0|lr1Qy>2x}`pMkOkrKWD4SeEsRu>;tGQi~Hr?*mn(8}SIc(pMCGTOGmJ8nnME zW0HX_D70hPf?`Ls(VG=xL7|%jYe8v~{`SUn^6xKN)77Wr9946X3g%;ZHJ;Pf zygmCzK>lA4sNy3CX+%`>rr>!H(2%p{U0U!D2};HSCEIMxd(xl8sEv}UV&_^%ZSDnd zPRUBkudYda0E{ZmL`XxLnzxj^2A;+-HSdq5FF9(#2V;p!+zshGUa9%;=vYZ(H|a<2 zHE%7s!t(1D#!9*#JPl`RE-ZNzJPl`RJ`zh`vfF|iVu?yl0i;n>&5fe?vd7YS5LNR@ z0rmn&W1*UxMDm#c$&6cbvj8^$q;XKqXY;V}x*bYB21vu5n%f1K@pw8vy{`E@9au)$ z03Z!@YQ8+?Dbvh;N~4OaBcu^>&6`Uuv7#MINknaJM6@$$kX&`7ZSq-Em4* zS@3=8B6{2FQ6Hq<-SjM&Z(oO^sO@`4(oGUo>0IosO7jr3tKI1J`VOMTbnLdPeKvj4 zvR$3?c&$!(S6=HlgriO~IO=>SM_r!esOuXXo&Oa_7o6m%Ta_CqmkaB2)crh;dJN#G z=QNHkTF%kMk8{*(Cr6ij#Zhni3#N8;`c$4kQNL1-E~D>HwX1V^FN*3eAHva!Ssblg z&e7eEb9B$E9NjwzgTQumSFgi4r(NCq_A~gv&m2AY4@VDGm`L23Fh^?(Ia)_PxpsBe z)48f$-AB$~a6@B`9&63ffI#=-THv8vhAL zHyr0^V$NjBY;q|_H#XsDN;{6G_U35XV2-Ab=V-=!j%F_5Xx2K8ZraSz>{mFN^ASgL z4{i9Nm6DM@ygKXxTd)-T5s?cb(#Bd9^8&*~+FI z-Ca&m#n4^hZ zIGS`7N0X;>bmK~nrflPA>K=}!9p-4dZyMz?BcG$0^*EZC$eB*LEDm$Dq?n`I&*bQiRvazu#?f8~|cEJHgSl!I_ljb%h*_uSZd{HetK~(5_kAHoVrZ3rFYn;;8))jyl}H z(RsIURKA>}j_WzmlBG_5s9 z)BA8V<2sIJ(!Wx*Yd&i=M>lQe=;mD<%|6J{oZ}qbl6^BN=N5A`uLVc*yK}T)2uBNN zaJ1-dj+SiU=#CFKT6%<|Woff1mpcnMx~mCC%e!#2VgN@gCv$Z7GLBYlyeaX@Kz%7*g5s#xs>vFWA z6Gx8?=o%7eYdAIs?@=v33vDQS`wc3XnpxPO)?T9t(eHZ^{wXeS#H6}ix z+Jvh>CuAZUb~2;mfa+>fLML0JtAOfi3$$L%S9HUoM)!XftI;al82m>=K1`D!#3$5< za25FD)A$-a%4h>*t!qRHootN`2dZl%(0Z%hHM^QX+mPQ5hJXI9EeLvI##H6f2)C#i z?8&(;5uA6Ui`8;ko`st^FXnRK+2*Bwh2*GN+pDm!^!VYzE5ivGh1XLwj}Djah_5b{Zg8R@a>%NkF&oE3y1!p$|As!*6SRMgDt@7wQe(Gbc}&GYI0F3>oa~QYLQDsf z($GW$%|a5qvUCHnB7Xk)lz~S5ITjkh66SC2WRF3^>u=o#76Teu39Btg?-BYj<)ydH{~K0S(N72~_5IMNimFi-r?8qk zgpToSoQ-pH5H$D%$90xdw8{ZmOem$Po$fvbIJob^emMF!eXmroQJT{%<8_FgV1u;E zlRrvRTM6!*ri!1(!j%iL@>xYn7W~}Fp7bM%@6Kyq=ruq63%hQ2t@_g7b4jY9g9hSV zCh)Hep8aoB`n7@PoQaB89CI&tevy8!?C3-s0I~BCQ=wpa;C~XOpUS9|vH^osBRocVCzY5s2!bos5lNS74RGu10 z@1N3}!EZYk{2wB%D!m)2T{lO+B}!zyqb zNbjqFoTMJ&Wb1bE--l^cYOPcBSL{aX6}2kJ z%lVxt(XBG+a`6D4(*2K)_`gDD_AK` zeT{{4R#_5t3kLMf%@Op=~qrNvT8SAZmGdn>IWrF3OTl3rn@B~rRCx>@k9}{WRn?Iy>guvYa#(N^)s?C#4dYeEt*X9M(K%D* z6~WU^&a0tRafy6{c}=XKQA&Y64!!PH)%d?vMtY5vHvM0uM!(qVoBiMDO`^>|Hvb>VO&-mV2N?u{?HzFmNT+_cuako(;SYiQh6EiF1wEAa zJczG}JWtoaFA^RFeu%ho!68l7dR)@l0Pn=_cAIlataqL)pkmLls?Jgs>z!IP(yF>h zRjl7>)mp3SDpg0ZdAfJ9sw&-5Eqffp#h}mUPQZe4=OD!Q3kE)`)O@P(`7(WCjh9>1 z1yYq*<9Ds9n^Yy%xY9OL;)PO`P-CwP>D3&B!b z@<3TK36%G=&HXBwdmEa5(c5*<3WlT<_>a=ui&whe)M02!6)yEwFf66OWb-go+?lSH zHKp3%53MXWJdrbrBcGZ^9FbUr^3DTywjVv@26>i>9X)(yUi>bOx4b`5+9h8?I^N;K z@p~jq4~}-+DOgbM0)&pc3Zc*4OqBZ`!Yt)oi8Nfq1X)Dv(2Et}Ew|E1QX1_{`h>u> z@pfD36e*4FA1N(72*d5`J{6oMrFt(m1Xr23>B(FhSS$tNymA}@_gqx+4k-|otogMO=r50$<`I?bZw31M zBSs)9x!ekt%OXT2cU!>K`g%y-=x(mRtBy1M~fP&y9f3X%F>daq2fLyfIGwIpEiZL;Yl& z`d10>B?)4)6W$@K+LffDex|&WR`7O`fcly8Y8*Bdc_&Fg-3TW~2$}IP>WErtr9!!h?V}BTB@5Y?K@NKQK{lB6Pwq}s*Xujw6NIJ zpV^peto|pd=jIS?@~Bn)oTL&B^PN@wB2_F9d7XhNN^ZX6Nh*<7U#t2}s(3?%>NczT zJxL`>eAlY}lqw!^P+rRW1p@9>eaoTf~T*K$2Md6DESh&Q%`pP^3@FdFQ^f>ix7OowqehBdWq%Mt9zii<$srC*4-bw04 zz72R{toOX~eg)inJm98!oAgb+-lp82@E{()V2fm~3Gj=FYn{vu0?v7!Yq&pr)b-~A z=IlDe!5eH&<#F)GfPcX+*vY`utY*ym5Ado#gX?U#*Ivf1)RisdwmgFVg*-80bTygX?d3w z43z?LPOEU-6fsN+#L&5|6%5w`o^8^BuERJh7%c^&h>cb-)(DsrTXED1#>*VUR+RmU zCxg$Rp(bbnKTt5!UOg-~Q6{F`l{e9HH_CK+bg<5HQ)D{LeG1OE73IOUhR$cY#A4)W z`r&U7oI!#aKAH_q7KCu-IiCbGWyvCkS`dsT!7LxmQYYuo8iK_nxXDNJ=*fahAb6St zH~VPzJXvrJ1P4ek+eh>J$$|wC1fGRpj*n*blLhM`XiS1zd>_UOl=m{YONpE7qgif| z7=Muj?q~dh^JT}5PO&TRPb*j;1<{Fh<>mZta=29r=)g03pr#cpl!EAlzw%mG!EI6y zeI$V?AuCuU1bh;_qHMlj&+-h)5iF-JidjVWI<+(PQI{

RIj;$?0@mE%&PA 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�-S%k9(>TtHaHD@cX(+Dj z(q2)OnR+Y2iO*p%$GiM|Ea(44goQ<5w*)8{RHfj}T zqo3w%%p07I-Ah@67UhRg*77@^YjvEn)@M0uQ|eCQO7b~tTZ6N9%{gn|jk6B@IqP@} zXPu^U*7<(Ux;(;J*XKFA^c~K+eaYEn$2hzE9A{UACQ?J)D^b>HOasow^5|(at~Jly z%5gTjjR#nx@$DJB{Tj|DjOFZ(`JCOkp0kPDIh*t?XOquyHYINowJ^1qvuSNPo8E`B z8MkmY^DfTrTFTkoPjNQuEzV{iKU3DU$vMt0;q}+FX~pRTHsjUUv{g%-Yg@oxea$vlec~VZ2T!%(ZHR#KPaYXJ3GS zH7#{X#q-a%tcPC1`zXzrCR&ff(j5HAi}D_@Z~n+R^mGjJ%6yc=Nu?X+M zVf;TLTns8ed_shTTfw(S#YecD(KJ-8BBX-0U!kpmst5&Ib6yUrrU(f%5%z)oqTr!= zwl(4)uJ#(|Z2lI13x9>*M%X7VfM-^B?BkdJXV`ZPM76{xgiW{=9F0n3$4+7NL7*yZ zDrox^`W{dfwm@qZZ&MwMh;}rIMYIOzPyf-88$bn!Pl$+cD_Dq1WJJ#}+6SnLhzi<% zg)RcBA`)oLHQV*7CeU=`vca$!ci4)=hg(8ch|aL{n{CBZYb0&@l*4Qnn&m0NYQJ#{ z?wO_M6Hr2@)+NN3Fdrxj`2;G+Q%k6_*)+>j3o#X1o(+tW5}GaH*$pJ&sUI*L^Is+% zP388&RIdtXF4xZe5z`OT^dENVjM13Di*|NfKDW>P9o%x_j^ibB8=JyHn)$o-Ok^2> zc4dLI&qD$O&9yTnL5NxYuV18>gmdfvw*xh5_@JSt35p{N?gn+5 zDx5B;HWXnntx!`l1f@zf0M#voQZogmN)0j8U4l}jR)ESnAHP}DYqtLtEP@r>1vKqK zpmV4Kg$7hz=K*Hw9zm(PT7eo%rREAsm6~Lzdj+LRJqzl4Ds`WrRQDY>)I33{?z`Y3 zU249dRE0f3-GyJ)f*555=L30@(1o<^m<8PdB!HolwK#^V@ewQoxHC~p5;`qFQme2# zxQB^fNj(>+{*q2C-dSh#_hHOZ0G(-B7Gk1u#!igF^sM?kND0kqXw@JrtFi4LhmKdD z1Py)+XhjC#CM2@`6F_NUi57AvsIqM}G$W>Jr=fcY3Z6xEyo%dXDP5hFPvbd%G87@2 zs(lQq3}5b20H-kN58JiBquiJO2%r#kZ9a|n{AX#Frb=k(^539Yp5m=^56x0L`CnkF zOW*|3z!_UFTi`FuTKT^t&8bioQ|D6^8QV~%Ep6i=nktK=_RZB%#Lmb0qLp8XP%2Y7 z{l3!J?`D7A^_dDd3?8wp?7C@o!;GvdSg!2aX=RrG;Im#MxMP}C@D?VX`2sUv)u3Y8 z2W|i4qZSUGJomMlN2>e@(ht7J^?=&>GDgv)@{GfqDqtFiE zYOQq_8Pu|c*j)>FKUHc=xcCjgX9-TTO$GY_o!<#iI=_UZTXRnW?nZEifCD@(io^d} z>~hb}^lGULh#qTX2khBi%&PC)M&QWmo*hi)IvOs^p5`r;E;lPpz0{jsN|xi@kNbe( zvSm5Ntpi7oQL=MvT7zbZUNdk=6tUdBfa&QRI1y=2+cucCXl3tFQeb%TtN>yxhD%E#J)k&&i<4&p059k&4@k9inxm`AKRW(D=!;WSE)*j_@q%?DpiRQ*DJ4E>?TzS z5xb+IYD}jLm&=0{$E8Ag%m}WK0uD(D_8UQWDd1?7AU97p(L)M25GA-20zPf&DI*mz zOf-UCQXpbjZv?%iKs50k1Uz7_mVyuH4h5g#xRHjsxBC2tpeY30QGMl7Pz{#b4;(K* zzr@1$XdXCj`C7?c-_vV(xoNroe+agjmIug|sRqma+SGodEZlaWSNnO5bn^pK3Ie}D zYPmh2;?X%MrOI+=8o}U{0$t5VP;nm(k&#j~miw>ah9+{laJ$C36Ne=>VYws0mHilJ z!MDo2RBY?vBlD8&I91I(ht{Sv$1Y>6&6{Hcw`a8Cs?EvW|Utt+1NvRs0 zeZh4gZgMhr3%E6xVhf&<$myXy1A;e5Ff~zNxhudui(mFk`yBRVdPk}n-3oj!ad#zi zUjjcx+}(+sZuBh3pQ+I~a&?PMwq{E$xJL@aCOg~+?v(;QYf!t5wMH;c3dD}*h!M<} z0SSFhgL0YYK3=c?w2(lgo z=b9tP6+(co^#cBe;0NR20f37y2mDat%2tO*z6;{cgsLB@R{amEZtJ1Czb;hkgvz?? zEd#IDFkhc{`vUMLQa=@^K4sudaq6r#wsnTo&%~*V4E$W2x-H;kbg}qCoVuTZH^-^R z0REEHTjJF74E(ZGyH5gsAHVGPq}tsN=&>tM$p`YBh4%uqaxC|x5qy{=pvy_U9h5H7 z)of2v(Kxf*sz$IQNkHQae_>_>JCg)7jIeWrfZhwv-X#Sp$k~S5Ejbb2<3_MY3RGyX z8SW#=si?j&++NA4fYK57Od4GuOHKt;(QuzgP6X7<2=+;V3aFRi_DfC$G~RHZN=^mz zAUJwcJNt9Vseqm_+#$&o|3p3eh2g%HoQmZa!+j??6-%jhy1nlur(&rJu2FZya#(Ua zuGDU~g%KQ)0tz;u_Io!Q!H-fvwQIo>MsQRLC~Pg*2SFiT%gFvo3cMKf#oZ~R`Z={q zthC(ry24|rrK-zn8r3gS#Y-j@?>eJ8E>&J*v0Hz7VIDC0U!|VAL-fghqdJkK5*_1o z(93aBs#qZE>TXo0l2oFu8Af$ls(3+#YKu|*o}>~jo;9jJrHaous4iS#b=0HkOrik) z#R`ts_CJ#2a}ZT{s409dQ2>`axSx7psHFQw;fzxs;CKPbzVD5=PoT={gnekHZyP_n zqx)`rbr=w;LMXVdfUJvqM5u0ritEafbtS5vG*5}vx-9ogQ%#PnMhHrG*3p!a zHE_468oENjfrMoZLNFJCefVX&zT$1(9jy!Zqg#GIi5U3&vtAcE|168MO(-qrG*a6M z0`xf*kf!0)b7V_Kpo{ZmHEL(j58Tm%;41h&9AdiP>NW~+PrA){fzNMw@MUuhe4&Qb zk$DZ^=3hfyDNen`z*XYZy8#a*b=5faF#}hVYB$)`w&s$$uJ2hqF;?Tlaw`I!-3)Mj zwM^=wUM*8oaJ}%$Zj#Jh3w#oB&6Bygz`4%Wn)?TLKrQz)Nsa+iGyA%&G z@yqU@Vd_?WtgZsQ6>%Lkx82-t!|4|A#nrGtoiyj|kSzBma9n3s&GFa7)WXg(b#~Jn z+dLJw0o;f9W%p$lrQWvaAJA}N2i)!kuAeT)|A45#1XFx;H#k{P z3xcmmFjclJYG?<+za*IEqr23}HCzKhAs)bIPxsM%^kl&}2-=ZghL7%^CkyU_U@Qq{ z`sn_CvS2*~>q&5zkM8Ox3qFA090~6BeHJgU+(Y21jsiE!M|ZhJVaxps+|{>%nov{+8R_2=0>t?~w#PbYKMYq`-R+ zVY!oxV7?T1k4h|ekr6DA0`CEd4kU96!SQG~n9My6jz`$n z$=nujJW{?%=5~PNIKP#gTE3saah%^JbHUy^&hL}CD&RPlACkGY;CLAhCv(?><2a8b zb5p<#8-UUNudmG^I_B_+X)ZmD|Mfb+XMFA=BeBv3vVhs>&8F6q~!2PN2%s99@V0z~=+n<*E zZESh|Y^y#TnEj8>J#aNnqe&8w688jPE*VVg$|coezTHN>u9u`?O6qw}VPxW$T`?^mHV~uU0_cK`fD5(y+F_(_hfgQmh+p=FX%mLW)MEgBLGVRd z{n&6)TfKZ%Mf|cWrJcLiQ>$HTJ+pYnZX#(-$avR!ahf>AR$K>gYw6miL7K46xYq!l zK(#lHgYO2EaSG}t5>|~iHI4HA?$-!fRs?;6lvmnGiYEFz>UfeoQ9aWX%tu+il^fjy zZZ~ngHAi*fuR{Q*^+q&TaTlobR&M6J5vVef4Xz9ESEn)RT|Fe;Uy1ZF%6^GT+8^>s zkvip%EH}#jiOSeHdE^I(qF18f>k~y@2v(#%1l7O9Lfy#Gs}t@>FM|$LD6JVQG7ji; z(hic^B?cWVwJ!qw3cu_jQhUOnL!~xy6}}-s^$wHTh6WujwY`Bh{0iEeq;`TqM@a2T zpl{%peRCR_-o%x04lC*LVnIjGL z^agAa*^ASxP)m&4{N6|kb^-2H9p18wE2K9-UOsb5T{1*kg>9-T%UI^_e%KHCucMt| z;dKVwGl;-j7@P`_j%}HH3xCwg08Lp1RFV#FncEB3KtuRVRpA4YlRA+#u ztO9C-4t<$B3cokS_a%r5Gm9-g_+{=-WSW4XLs#afiOdk7^aYX3FDD#DYxH(Q;KD3g zz~{kisto2kW)kSEGSw{pvPkC7fp>B7iCzLgcSSN!vXmkg)zx|!R61OqFuM_7>pjdL zC%IqE|Apzw==RJUp07zZ)`PWBaXwAu)7r@&j)Ebc9Y<4)aZ(TA%2W-A-O`LxLcQ=)6yZ+tL5B|7=z9Xq*>0rNY8W1*R-tjod+?!%61+` zw!wCuMfT6XY0d`Ze|9Is1^G!~9|7Yg;;Jkv-AU38004|81j#x>855BDOSF zYluE{Zk6Jt8K@yX>s8QT4RJTPb5QAO{Bl;>fB!^>%nZ6(;w7@~pe4G=SqIv3wji~g z-AH}TL8NKUDWvI+jpfR4a*$>^6_EO!8b||9E2KfE8`3PNFVa%ZaHQGJok-7f?n9d6 ztU?-co<>^Qc>`$~=Od(H=OEHt=QL7$(+b1Iampc$I8~9Bb6O)U?_7m6&l!f)b#6r( zb?!o%?<_%DV7ZSV+lpV#L-xl%d&|W)Y^#+^qcvqaZ-cj-50Ki_SxB>;GDy#J$|22hDj*Fxm5`Qpsv|Aq z)I%C}8Y9hhS|Tm$v`6YVmm-beWC_{L_~op!ryYwA_hZ26IsI&B0wyfyZlt!e6sga7 z6lt3CEYfsm8`2EiRz!9hznq8d?Fkk6>QF_4Z08^Fma__}?QB5mb53?jqZ`#(P*lM$ zXQRCcV@MAMw*jEb34U7JKzWR~*8sYW;Aiv$Y6VXRw2EN!gjc~&0opfq+{TFzmlwVmIP)^XAr;1fb!`wne#r<=FVqGTR2CNwsihR z+R7<~&w{mfB1qdfRgjiA^^vx9N|3g5x*=`v3_#k!8Hu!`GZASg=N_b;od=M1ah^ch z)p-u-rOum3yEz{rz0COr>E+JfNUw0tYh+p7ojjyHoXSXhIt`HaaylaI?es@_rE@FN ztDJ>MuXZ*e?c=gz4bg1(((qYbrNQXNIkly6{jC2HSRM`#mj&ZI8;KJq_;V1kdAj=LVCON9?}WUXGrgGjv&3$ zIg50nlZj1ql2eFuvhCDHHpO;YAe(AC-H}bRoq@=v+s^iPY!ZfHch+g*4rnh&02QjWp9)jMVQuj5Odpg*51FL7L^fgS3?M z5z=hu0MhfEqeyd{-;stKAFeV>J2^|H)n1724CCH1AiBKG*%`Or-UR4vf_KNkI{+Ob zcuyRB6wo<>KZ=7hU|4eT%h?+T7XoTT@W*j*D?q&o{v;0W4`>|0`{Lk9fL0Q`KMvjq z=q-Xjjf1xXBKuU%XL0b4fXHl>^LZSc*#f&Q{BpjCgR2ATNbpy2@RfkZ5quyHo(X6T z!3X2uX8>&{`0F_MQ$R-vK4jCWm^s)U2Q=qdd^+S?2^U)}v46%d=R3StLaSGu#un!T zt3~+tak$$67)O3sH5%aaS@#OS9QjXi@XdfZ^5b#v9Kam;sW|u%z;EG~^G6)KAJA!n z|FWqun@_;iS-6|gN^}2ejvx2)9VoXFxR&_kq^T!fI@C)64JOzh2ag5BC#=~%K4I1B z*?{?c?>rx$?`e1yU_P(P@$q?;hF=2AXGx`fe3qo)9f0}#C+y?%9}WKqn9qO8st0Ns zPHU~te;jo`RKxjz`TVDxeoCQwz9C>f|0(a|^B=A537F49T>Y$2sc!0i(MH0NI)J<4m(!kM)pe1+ zK*kf=L87yOJVt0oiM{~j3qm^y)XJwVB$vkG7+eGT%hlp(7gXQFjnC;0Qo4=kPadWwDRdfGXD&c5KYyd z3Q=hvUw@a7ta3&acCpggeJY+pm~<(e{gzenET*$ibN1VT8pLN`WBdR77mbwSxog!N z-vZN6e*sDSI*Id@wyNTKjq@{);KHvg>uLP5Z=_an^SGvsW9?=j{IcXgDrnHXKz;W^ zJ4kAO0m?Ubhv<8|Ttle?`en(X60Hi9-`pEcU83q$4~c`VK|R_Dm5)fGt_H>L*o}-) zR&X3pewXeRiOvVgF6z;-b^|esL~z_6njb6p*v;19M#JAKc;2lB_Zez@0;O)|26O+! zS!OpZ!5xAZP4_VTM8S)uXB&R9;8oL48ER?*rJFtio}U)Y9r?HESF2zGruj+Gtb(ED zxzXJPA*^Tm)MxgLU^-R;KOVYQ6boJelph1#C(%oQo*sZ=^Ca2}C_kK8^rL9_H%!x~ zG_&t7h!*GvJPU%Oq203A2&XgM3wprx4}B2<2NQz)j{#Y#!X37 zS5W+n^64aM1SpR1IYH6ZZw2oL#SuQAL_G|O!+0TydKnZ4|6&rg4-|*7If?oe6bJuO z5|xFq#u086l-jq|0>u%&oJ92i#Sy-eM2!c<5x$y4tpvppzLrG235p}!mPp}kf2^<) ze6Y?6(IbV*>1$!M3xrniTl`HNz;D70*8&st7JulW8pMa5wEaKO<1IC}Ud@R|9}3@~ zaT9dCLuIsz!Ya39iZg3+S+ zK-LlZny!L3yx`M-=%xD5>!MLQM(Z8GPH;zwe^WG3bP5Q)CLelBR#tQ#P6FsP`Ow=6 zwt}@V*Pf8~)Ui)R*bm59Lf^0aGVPEQItPf4mgd79=t5J&!v@_hYuEym-klHa5NOdi zKK%zo08_so@v;POM9+AK%q7)c1m-s;yvuL;WBqwb4!j zMekUK4vPj=g)0qpL{O^2mkjlzpj3sQfFkc_=qEw(67p*n!OE9v{%67S5-R>`@N^6g z{h}<`G=_EOjRHl-;L!0TY7Qtm=!bqypmfp4!O<}~bRvPbf*$~;lflq$NuBeDp-u}* zbxs85a9rwlL8;DZ2#QYeLVpTMbr zAAuI_0!pVAp?}pDt(L#|6d*bg30b&d!TW6LeS9Jb7+vv(vg}yLSeI2ZaJGi|DATPS zV7d?v<;1D4GjQoR^__s}bS4yzQ?E8~**Nvffa&eBP$W)$*udqb+ReNim(BQvE)r^9 zR<$)#msoBiDCm8>P^JG#H5>}^=7p-*2}cFIzG}E4$x+{_1F5^#2&zf}uQ&H?!xblT zYOT13jG&qn@KAC81xL=mP<6@iSaB-?XRe0iL{yE9pr#b4sCpQ#RwAdP8fgTzr9ee> z4>Lv+<>OG^Xm!wiberE(1rxfT&?e037`bjDkZUqSFt*}soBmqTZ zxh+7_OFW^5DFu8gg%{C{s?mR|bVzp?Y2(yV71wg3Y9du-w_#YR<=<=smm~>P4f~9s zsT5FQUBhW3XqF`46~R)~36UPU6PimYwWCfG+y+L_B1xda?PUZlrGT4I;f^zcR#LzV zOo`>rhk)KC47E-aSni{SYa=<;@>au@NKQ5S5jc7=D%8$?qCA~r@v%g;H(`XuZwG}s zB<>n4cNI9^ygJJ|)f)(Jfa49Ii{!XRmEd~_ctmxT0^;M$k

eOPxfHr8nQH=$u9rerCv#VVqYI``pJZ+vIC`febd9av z>EI=e*_+(uAnBcs(6#!pO`_lpkn~PRsK4wAQNy<&>79 zba(>G%^rm(y!eF%+3KAR!PNymm^fHdaK)*&ju|<))G9cP;rh_6;MVeE^39N?haPrr zL2fydk=o7zo_-Xm&vG|F%XJMAby@EFfDchML*w8h1|BA0eLS^q!&7JcLc=BJ?TfUk zB^2~NN@%3q0>t|$1B~DnDWE&5dOtnE2u4W(Z^vpoS!4vGrGTzZbPXGgV2l)qmnz;j zg0WH{-mLi62*yc4;@c$WjOtdYN_+_;Z#=eI{6e=$74L!7vyHYO>2;G3KH*8Lo0mc_ z%0R(I*{0jfz{}&* zJpiAkx>v-(!vT{AG4x;@d^cda&l*~3UlEQi&lXqRT@5X?-G?Ts8>yj(q{MvzFqd3q z-@_%_*UM_CbHJ_Xe81YQu^#^=nZ=?0Cm$SdOc8btb2E&ctd5AY4kO3!Ui9z32DBpLBTnm((;Gqws_I`tYD77yF zC3kmdyVU+<&>d16!ZRUqchmhV^t6tlqd|8GtveDZ`Hw^U>@nyLeYYx?Zj6%uIP{5a z5Lj*+PEPrDcm>}|zQo{iyfbpk8twwgt>JP-;P@n4{mYH2P9K)qg5#5H{ivUt z(%g06=($6vh#y$Tm755hPnL_5x#i&a<^nkkbt1tsEeKwYIqKf<1LeWS3Av^f8Y-Z&!CQ=arBE|fG!GO#QV6fs zB}kzISfimvFJYhscR@*OCj7YCMHfP-VhjEXidIbci6pAbRVa%6On4oQB->A=tfD$V z=?;AuPiA?52JAPq2dtoGa7v|`meONysQzf4Q+N1#Ji#j-J(F%S7m~Q2VUr&m_ zceQ#B5`HsASw)qA(hdGFo>8dw+5({){NZ=$5U3(mV?200D7qgXelLldY^e9uEi$T0 zl`2{Rik^;yaUc-ztAObuI*cO$!+gXo`qscW6fn%Iy(rK}-Gd9`SRm9j0n^oX7zYEd zZgrq2>H&@}w8OiTxe4G_;upqq4X>OPd>qg&fO_4^ zyOOvH>jCaf)F&~@3Jw4=ozQ&(Et(62{)Q{OUsR#{a056Vo}VUh!5!e}iaz{VY-n*8 z=(TnlJYCR-KTpjU_EV1x!e7J&hU&s#Cs1_u68w^nsM+)NY=C4MyU1V-Vpvs! zwIs~lgO<Oc=Jawj<6%xmgXF)9+^ zmffeo@pfJ-nL7xMcBJ9j$z17c)s8e=Cz)#nj&|JPy2;!qaJ1tN*GuNsfLoLe?qa(? zFB*5EyUW1!^(r7(4G8xyaL1`ggSaA9`fIpha*^)f=#Emjktm{jY7)3sIp7*6b5DZ% z6u)p2T_^XV>fuAcLj%BFlFa1+XRet(Kjv~YnBZy8*!Z3g<7jrp2i{7v=$rWA*;e5u zto1q=>EU~62js6#E75X0pq`=lh1=;icqF>F0HU+0aQirTDPTH#3wMxX+I_*m9pluW z06vXhxKkW_77(3}g*(T=6|iB@6;!y3y|bdXz2rXWs%x)sYumjE5;C!byGn_Bk12Vn z9XOv#@-pOZLP@&z3b(P{Gp1xWDRJ{q8C`pYFN=dq0MWHq`0_Y-7$Dx4ULlq~KpVH( z8@MYW2=zv}?ui1+{m^hd5;?8`UkHJKcO_TpHLBJ`J}!djLMUuL5Ub#}fNmtXkG@+$ zyIad02514nef0*b)DIeUzc~0+z+aL2nz%|18Ti^bweLpDs)Ap*zl4kH0J@Uk0oc=U z6va1Sb~ZuR8OU9PS$f(RzFu#k6qxR|ZQ$r}U-*V(?g%(~EE&F0-+|_Gw6oRQYG5G# zmH~?%9>iBW@^I`{HJrIY7c0!i(&BCq(A9K!m=07$R6GS3T^)yq$Kmb^!04fR_@=lH z+h^brvS-{s0Mldj@Xc}R$RG`mlUEQmFrZchFSO|>89R|tV<*}J+?~WP5+@B-bdG@+>j52o4#;5=>J#q( zosL`4 z5_whrHSnczJriEbdoLB5C?5sK{JKP*%h#myJig+ske=2HYp_hq8Yl4JsZ3j+zdtU6 ztisHmI77j&Ob3$sZ)C8E0Xuo1>i)u;4AUjX@I_^C1(*-0qRVea9cili0(!i)i_pu0 z9~;3HV_3jV#RANy%eDNWph7%VA5;0`X_lrcWVFOJP9S{Q1y5G6tk2Q6;ei#>$#GUb zd{xEugM1eK#Z~xftK!4kl^r?UC%xjZ0cJW-k&dsle+&1?u6QB3;vm)0x3m?z3>;(? zRt3S=Mg3_c`hP{D#&lszFxTQ29uQ+rdvw+?P}7LMP87!8G&5-$F)oG#LZvU=6`XU zOw*Q~`!3Y`Y1+06KEm`an*OKuX37G!Ge_YjS9Q0+s*KrWW)apz=T32vy@F_zx)c zA8iSprvIa@9!8w{k2dPLz)p+>PAvYrO7$OY6afE6TO*9G{Q0OnL^0;mz{y`lvouvg zviyxSOH(CuXv(L@O!;pTMpGq}6wpKQ19zgGdL<#!&;zCX!=$095>9@nS$d|DZ`Hum zqUksF9O2%Ttu((`?DPRv=2@AxDU& z@@Xocr>N=@sx`kVv9xR@G*v=V`8-P@RLH1;<8>f3t>Oc?$A2YBXMpdAi30iv%SBZX z*VtSdu-zc^H}{p)pgZ&vNl7mB${DYhPP0nq4K73P98Ir>&-J3^GW62XJesL#2MXw8 z7Y7gE&drFzpOHlmVsaHp`8!8eVJ!fc6Zixb2~c9yplb7QEA)Zb9BzZsT;SkK7PjKs zP+}34+E4pj+y4j&gDZj1fh_McYQUf`0`(F4dGlHxTJRJUH)4?FjVqvUn9wUMc_V|n zp{39L=6ykdm>PZsLbr$VzM}VM6dIr=tYGHX>IJU6@96x?6u1y*bNuqYmuOoc0}1^> zqN9M!CG@cRey>`T3cso&ZQhSbP1XlRmx_5m(c3_A(R4M`u>?v-I}kisX7i3G@K$gV zD6-7vok*gVfg($6-l;^Y=y_0NBF+02%`QlOe&XSnkcIUV~U2ke};{nsnsyx@8Aeu2> z%gdYK_WWJltICT?g*yT;-EqpxkAr6eraMk~1#$2rfaz*KuVUOnz6zLbL*$*WKhwe6 zhWjaCy5Ep@K^%MnFuggLS2?bd>_60rY+jW(xCk)aZ^|pux1m(sZ2;5#ro7^~y88j9 zJ4kueBy92D_I`rhn*WTQzX$^-^cco%J`Ikm`eLV%zm_nX&F_dcQ#n0=Eg%qW!Phtq z@eeK0*7#dqp6e@aSo>NHyk+6yRflB5cUL6N0@Ff@ef z>Zt1qj=~&0AB%Rf@$O!nkelhEp-lRuTX2?9cNJ=;iXH+*4Ayc@Ghy?#sZ;BvgmXg3AUemnU>oM&IUz?t>}!>=tLc)q8>EV z%*0YfPlKW>+UQ-n1dp(y4-Gs^!w#*OqVEhmN5i~=i>x2i)ok>hIJIlwxp8&Z2TYf_ z(R(#aLE;lt)Ic}G-6uH}(@?|BlN=XTf|(G|lfUSEDNx+Q;OGiEx zMW@;e_61K5^rFjYne@69{CM#6Krgx?HNPA@y#o||Pz*(0`ru|zbQeClGNGtd^bsg} zBpO{UdcX?)4458?MjuusXmQovCm1|}=xFKmd!mA>42pKM(HCRwSiu%R=|O39bF4db zANK}D_bH+;iPm+0i~vUmz37er{xeMXZNYumf6~*&=zGB#MzFIg3wTp1*a-n06r=A4 zAB2F8e$ib*5PShBJq3#HmgvVo=>QttBU%goXwZ+O_FtfM_>AtAXyixr1StBkMC$;h zV`}u^PO%g(v{BE0q8|i@LO_pyqF)O^aIz`(O$Po^O$`RCU@MBz!=LDf!EL74At4Cv z2TBLx=(iF*0hErz(eET0JgT?D?_*0Gph@n3y|ODC(GQ6tHL_Y8{%|7C8+4F9%1HOp zqDK;Wn#ZZV;eSlvt>8RRJZSYBVQNqL1W-C;M~}sJb5`&*gZ@Hc>Fx^d2TIS4qQ@nA z8Ymszqrb`;O8unK6H;3Ul%5VnPfD~oP&!AAo=V!%t^q|)eWLoUG2TH_St~dJ6rIUO zPpeaZZ{MxQ`vUOv%qRMX+DtqicV-OrX9A_xQt{j1>4{G?9gkFE+hg$|gVX;XGtO(J z_#AM05){QPDT(L*tnr}1IrQR7fYT$JXqLvU;+}x$!A`W4f!vXR=)5kPtu_NXqnHvT7X@AHgwpdAut7poUm*u#F+z#OA zsZ!KU=K2{fUvjF>F{aK6lH--+-fhak6oKWGE6QB~?s@#87ur>sQ(e6q&~F4+QsD<` zg0$R!0JZ%Ea1{+VV)#BlPZ31y^ z_)`3$wKPnpyjHX~pos+6)-at71t_ti_W^%_xH_7nv!4JbO7IrQn}q&s5IA~n z6jk;JbuQGNmaHa?9OX2852xf6(mQ{PvmEbZvkP(k?Yp1MpVWx||4{cP;B{8j{_uPH z<~>cCbfT2D;iQy;Pztn7n~rquNoj_*Y11-F!bx)4oHofxPfpsVK!H$3ML<-ppyCLk zqNpeuPyyvCiXaX+T}N=f3Kl2s_3HQgt-bgA?)MDossHc$p8N0f^kna~)?RzY~uhQA{;_i?c2PmF8*^779#@8W-AyRT|u z+2ox+i#UA7xoT2ba89&pa#{J=B&j-~Z0wi$X&#a&=U&|b_#xt|%hVFjGazuPZw81H zwW?Uz3jjn^I<;7Eufff>aVJ71r}`m-JKe^qM`WKcxHD}WKd$Fgf5+hF*f`#QajJi5 zaA(;#UY>EP|7vh^ZJexNSC>2byBKHNIBMIe#ww0_-)CN#>MB*S7XZvxtE%RQz?%T( zJ5*H*Lg32*=3`b>wIT39fccnJ)xr??Hh}p&Rn?*p_=5oRd8(?q5cmmz`8-wCVhv`+ z;iESI^LeVOB_Znn0+@HJtCohq=v&k`LzjiXa{=b_R8`AE;PU|wf8229JJ+`W~W$FQ8#rtW1`5s%tTC2d*0p<&{RogG+}GX=TnvKKFH-H~G@?h;#ooxSrcRXL1)Jw4tgyymDEUm&lvFsu`rOdWRPo z`w`G$F_qDG>S#IBt3kfBQiXk&jnygMYhd!ZEJb&pfqk5utJ4rcJlOr-rvXqImMh%# z2KRuCQ@q{*T-8T4FQ@v0h@QtUpncqxYJF#HOM?Y+jSb>92!7YE$`Fb+ueAhUzh!Dp#&I8miCPRJn3JZ>T%zC=N$KAT|7yEve{6 z5zMX91pjUmSTeL3f-ljHv1V6J0tlIp5A^5pXVAaJ>48cn_ zfmNF|6SWM#unDZn+6e+qx2t|_6Ik0dcN&7<+60!6-!cThvk5FA$4$~%{N5(8gse9N zf3OKGArFB-T;v~ZH%K?$6QY54bgCZ!SRS~X5(0k_;9uc?)zqlv7@iWrUjdwJ z{8iJUoTDgFbi0pEiO3><)r=@jG=w`DIIgo)Ra-cxx(;A2om8D10yhK9{hF#%EWz|s z6rI3v!=`FhKJE~3yy#GMYCi4`;N*$B+4;B+0>_IERj1|Sz5txOe|LI5?gilFo1te$ z>Be-4t>!oBL`^WqCa{`c+z^~)6Id?bIzw=_O(4fSRj2ZVA(*EK%7wcn!#@nc0-L~+ zp$;c0q!bHn0!xPdAdoMgF1BT07EbkN4Q`2zBX_6zMT1*vGgj$NI!W_fX5&=4^}xxS zk}E6&#EUin%Lh@k*nXx!EZgsKmLKt71NGOC8Vxdi_P0zRHmwaOOOdK=@DAdnBD zu8wm4s4LVWcn$=7Jfmt&l;?!<34R9x`5@}rsCqmjSB7$21(6S;u8ZrP#Q-?FJ2@at*b*d-Qj{5ZFB?si~m8g+IR zmm_%@)w!~Yt+hpeEl0x}L4f@>~Nu2`URP5@*vp%-d#q&ZZq z1?X~uFJh~Xj8(+_fZR{$#hO@}e8mVr-y`@Es@f3$5|HUocn!9oMTb%k6=wmop5V)Z z(l~RP0og?;wxETWNZdvR=&b}_9uTW9g;l&8;OB_yP_B*=S`(6r9ngeSx>LhSk5BzB zh@Gh~;x{t&kNCwW#l``(8vkoLi}R>x1VJ~6x&k6RiVVn|gzmDT?*`=agzi>fq*t0h ze~E^6D<})-RCEFQ*>}56O)97l)pJ!GFsMBWB^qHqIDY`t#ob7?H^^6~dWS*vD3q1z zqdBJA zGhL^AW@p*G7ou#Da~Yk9`#8VYg=nS3a07=i#ZM977=eJgNu@w|&PG570#Kg@{YlPF zJh@1xbQRhTx`5~2_sp9M<8L$RZ?W+7LOT7!CjA=<<9}?@-)7cwBpDtX$cTx%Msu6*Es&c5=eq8IXhs z&9!$)tL$Tip?;S|EvPv=fil#A|EmS>F z_O*ASoH+?V&9!$a(4517m}~C>sdz6S_O*AF@+m;gwRaItxzb+)%)>Y4+Pfve2sa+It@AYJ+;3OZ>VbB-Na|fHK$KMN|d; z6u{=%yMU#&%z43paqV5eQtfm83b0%cc~*lJ^^DWi*PD6m-RG^G&z$psGuPg8ac#hv zYwteJskjPY``WvpB&Uk^0A*i$w@^<3rLMh;FAW5NTL4O3dk;`f#hBMY#W?;Whxr*`R;z-NN+)7rORt;ob>c z=-Ru5`zmny+WTi9q0)v^ebj&#>nac>Nz1FQo)a43(*6}o^uECruE%wwa@LoBg+C%|0f!L@hGK&uY|%tantd$(-5n){ssZU|972=JfD zyDSll?<(9}lC8d;M${&!@ zTzkLAq}*zgR6hc+zV>dVtbPGteeK-_zY4Hiw%cx%zMP6s4z+sr*{BqpT*9^YKs`d> zR5uyij$E83H~<21CFa_@s)@G%%$*4T+PeaO0$_dZJ?KxI>SqDg*WOiwRn&hp)R*a2 zufP+|!Ni-q+aflTvkbUBL|qTCzV>eMp1TWRo_UmO?{vM++?xUNue}SX`ojQ)uDw$N zt+sCh7rORt;drHo%i6g1&M~#s+bZW>eZsjo9F0tI?OpX1l32Cl`3BdWi&Htz-39{x z+PiccESWQR5ODw6djPM#2XKAu-B#Em2HY1?*tY@J*WPXFmkqezrk=~&IsUbGrN^@Y z@~^!sJvIUqy7sPWayP*G+PgJ!laWC+$LHc=uC`UEaPKzhu8mmfLyN`2D-U_g}_U?nF4_6)e z$yb|nxb_|`b_O*9Gu|D**^~DP{USE3;@ao$7)xg`=-UUxP z(CMEuczx|Xz^n8z%w_Cr?*U$2yH6RszV;sA)wOrFU4896f|*8Srn>e%6W88rS;ga? z!Fs|s?!a_1z5kH4Q-34N3y_Lwok;)G2&5iNbfdi=znA(oyb{sKdE9`Tm3@lt@<52b8)NZK3{w zvf^^DL0xa5RH`R|QrDs_luGrV26dx_QmIZ_30=*C@HbOyk+Dyp2u{UXK-INqGEmTR z#cQuYz0pD`UT*_RU5mC*D%BGP^(G6YQvD}T>RPmgQtIPTUP0Y%p_KYo8`K>ZN-<0U zrLIK>D5v7hfZErhRY4yG)V>x?sIrfW-vgztMdv6@UyGgzi&NL4sk!oL*sG8qXCB2+ z*P zEcR!HzlZSHvRGsfkOai(#bSSBQ<+K_Lvi^zozWPU%_qk36FadDKg$SXC@yKqCC=C8 z;xD%2=K^9G-FOaml;sAr=WJwZa~t~B%R#mWfcP+J8H&A8QUMX0ngBw$GoRQ8h#)NX z3b@A}W|X10MEO;x_*V$K1)0Ua$q->X`4jsYqn}~gw~^^9j7o?Y3@hr~}Cia4j79wXPdFkDDN7Av+L1Buu=Mj49B53zB<@+U45b&=$X9_a7=_=#nQ z@x#l^v8#w+G|p(8H5UKNS3ZN4x6L&J2o5l~y5`?tqWc&;Gse8)lFh9MO=Mx? z48<9WNmOL|FtPu56V!O-Z9x3>{rI6($G$`aqj5&#H1~M_`w;#2`|$H~Vj0~y@%F$L z$-=0y|9+5d1|UA67qkq;rZYrD>~F*hcjgnTC4#Wnx4=ENmQjY{5*lv@@r1~@4Eo+-HlJlef{!2EGuFJ8v7DZF)r)G z=qTe4B0Ayzc6_1Oxg0+W__GT?@x@3mF@~Sm2R)>SGs;k$p*TZLd~=0?o&1^Rotqrv zOp45ll)VuYc%PB+NG(>J#-`!_#yt-I#}p*}DPGc@grVK!$elRl4Paz0UIO?z&hL>d za(1MA21z1(y76z|rc#s8ss1AnV~{LzMuhAlWB-TQRZm22FM>hj%!u$%VAvM0u`!Tf zqJ$ERey9?;mL0{jLuIGFy=*a%*q&kZ)b~clzMs-c{{osH3(eB9d#aFiO)UFXuH-@%v} zvD0T&xaE(73jcl&*u>KSoLTmD1m~PS?G&oFo@CRVQ=R~98^bfEI~)1fgS04Ypz{!` zge&m@`xjhiKZ(w&aLZtd{5J`(jn6}5A)4sC{#*cL_wjoOl)Y~G)D`#}nYsbLW2SD# zuRHZ3Vy1TC*PFTzztO3O@H=+uFn-IY-h$tXsdwXd+|&=@w{q&|@r#6ZqTxafLT8LO(IgLlIGdOKKiCR?(EwJ$#wFTz+UuPFp{rw}qja z*FmCs!ziciYC>-eLv@0BW?n}-P$F4!-N;n3cdG1NW&S2YW!ox%YF=+6N^W}wD5vdR zguX+rTKHv931;61)GP>ac4ts}5rx#w?5_a*8~i_eOCUPYPTMQw`4-_xsU$mR_TK=F z-46Pl0lf%4`*c7z67%{1qd08=bnacboOS|wko0>3dR6?ZNq-<0+D0v|E>wuN8<^mb zBv3itMnJotqf>Lz02bE(oVB9nR0Q9~;OPsx&%t$?NX;TZ-b2W$8lGUem%%e?8UX!s z62Y}KWcn(Db86ZF{V)kO$cr=&FnD&&AfTUO@Vpv+>-m!mzOLpCfPR6&cn#lq`W%Dj z)KmicG=mK_a}d1h8T6LTHLDR^N{_#_W(R`bCBgQZJqUhzgf)PxRXSGRiB7+wRhhLE30^x9!!OJA*kf2?H6BxX>=DaLC0)rc+Y%vBG)ocUw zEC$b)Qk=}5cWOQX!i^;SA_*TC!U*&=?+HaH;U~+Twk;%jnFnZ;F}Af5u%ES~0T&T)fVpVE zWds}~2My>Xpx5V7K6eoAJ4VxK+e6eJ z{rm)}I+C_)h`P+r*+$(&R2xkqV5w8xPE4lI^)|pX8s#qSa0Nsh!RE z?dUx9%>d6+a(0f8W`P#^aYj~4^HUA@CtCox!m5`qlj17LPn@6c0mVs`e@wD@7{7A3 zB=C~X`sbMPYUR)U;;96)zXRM)@PENRQ8Ry>wjVRWucS)&P>aET68cmw?NLIX^UJ8+^WO-4UZAg}OeKnT+x|(EycVwd8BVaA zwkWmw4Jlb}f{8?ZTTr6gzmuWjHJzyCK^1kLOu!0NA2selbpBb_sa?6M5`Su@Abt)A zYL`i~Jp;i-$+ks=$QhaP`5?fE_y8Kg3PRJuS)l7jb^~y;kciw)+d7iSp@{%0Icwn> ziO={f#E`c*ZLI{W#!Aix+)40%3AL0`%1bjslD4tfvU*>D)8I>)L{4R>MxwzD1m7CY zxBRE|)be(s{<|RR5~BVgDDqJpRjLl6sb>$js2?*n1+G^&S5`~3`^whRIL zq=fQgp$-x?AOH(`n9!^ML@ud~wq8OHT4X~6T$h`8Q4gSR%!M8y?Vyyx_XVl}D(1Hk ze?ag#4OHRpApU7T^YUGXXg1}j%(k}^^-zG4=EErb6H#BaP?G9B_?;+8?I+sW81Yn5C+IA3klg|N0T|wmE zeTX)gCejW2P|!^x-4TKC2O~_9TuM;t(9&L0qZQl0s_`sfMo=1 zumEcbh+BY71k_uA76LX}fQtw?-vV4tz$OdOO@OS^D?ioNPe7wZagYF69Mcrn63}c> z+)Tjc08m3iy#v5g*25SZD!WBw&#R_)h}V$Y06vX985;ssR5WV2PDv>{|d>Y5^t_u-XTdzkDSN zG=P)$n#_}Vn6zVCW76~nTZ0#wYAyieY zFjutSB2?9`NJBPG+h+(}V&(Sl1gMIzSbm?-`k;Cg%byW?t&CSCqaR#NpGzUzeofTP zGF}Z(Z7&o0P8qLS(7zJ;W^uAURJXBz5OueVf^t#Ow*vJp8K~x>CJ=SsH_w7ba#7QW zN(Ra#-f5dj=>9NN4;aoMDiKCGZRZl24MTN;#YA<6tJY~-NvIk?ibyKoIH7}KTFs`J zs1J#ON;Z;;QD^oJpa$`O#jSw=GGLp1C7|yn<}Cq6a+>`?K)*`NJpo3g`6i%$Cg!~X zMy2^Xpr>GByW)WWBQ_yow4Djm@?Cxt5>-2G^9k+sp-$Tp0tYPm3%@sfnfuVW5^zmE77ffzYNZEqm{ z62VJPE+vrkZFdrNUXZjKT-CTq@h7XccarFEkp9*jB5MEg`$@EvWodhe!JR=Bs3GV5 zY>Xp56mIr2q+2ga5o2n5f`IKliFRpsGT~=^=oY7@;z-1K5wwez)SQUm4-h}a@g0zieFfMNB6wsFQ2b~b1^#aHc z5R+=GA#}AsZxSejZPkRX6V*z+x5Ws!Q~)0nvWM|IQD|oq)kv1*f@(X9fb%WDA_8^< z+Ln-1sW9I)>lU z{_=t==PTFreHih`*oOqV;=8UKuUwO58UsBHDEA-N=+pR$_DMh|e9v{(9C_w?pSETM z>8|TQP8}89K#sW+$!@WkeGJfdV`FB`Z8r4JfbuTknzyI}{gTC;)!%oW4TE5Y&ou-k zskjN?w-Nka#X?Fn=UG5`vUbe_n)r(>(t6Rv!z%e#2$?+%3ga61nukeYVdlLDaV~++ z`#J)h;N`>!n($jFE4B)yj58Yh6n-W$+Qj??EhY^`ULu#S9IeQ)oS=wQyy69a%q$4fNmudPV+r-{3qP_J;wu{AGM2qW> zw2IALBsRD2am@=h0SUeWUVp{^-v2?CW5LJCyrK!pNs#^>kUxi7PK#QZIRmFfp9Qc3 z^bw{KRZ$GJNsw{gfW-JW2md3z^MUw#E{`5&J4w?`2i<8-?;>mpix6tp0UxG_yl%o2 z&z&%7+Q}0pM|Mub14(s`JE399ipujUV-xX+`Wa3G%2;+fpsOn@v0vdWkGK=C@BnmhE#)No`AMaMoOkYw&PSM1b z%%8-wYyftx{OtT1m@U;_7HOCw)r1^Rp92-MB3?HIftBELMhx0e>ORxwAliU+>53bV zuZGVDJq}g+BqE06oDGlQoP%1$pK~Wlh0McdlQUnL(V7{`JQhSC1m@+Zf?_EOvyk>w zS-Bd)MYN}zBM_yIl4_HJtc#Uoj8`Pfm!govs@#lt4eQ)pN#7Q;m!^&{8RWW?Nkd zy1gb+J7wpziz+Wh&9{0^Ehu*|Ap<*!Bx{Afz{8$7;TMX9OkY^p3`y~_eXg@$E4etN zW-!0Rr}LXP=`Pg@$ zXz5^MFpy3^1&o;VU78-^;E79LT#uRIiBQU=^js(Ijb?z8!nTgd1z&{@DIZpPBO6u9 z*S^TJXC7XJurOa=M`056a zx1yAES8sznMiQ#gaqf!D^UYd8{>_IlF6Q@kFm;@}{lq@v9?;qqgU_3TsBgmgQ)X3m zq0ZkKVY5&@{kwoU&kJz(B5vs3t;6`bfKVCudy$?kh$i+vU~;YAao#W55}$)|et@Yf zgFNmF>PkC&b{h8wQcDL&!~3Am{e0y00Ag(F0jCc^*K9f;_UXE&oad4DBao4_y7Wh^B(Wj&b&|V+@8rmG%(o|8TtNdlJ9uC#xao3Asg}SxhnQg=He(M4w8#92tFv z`>X<^PkZdC2VK+E5PXI|a;mmeiaz6HGja+IFfqI|1F4yTAL8ielpw0cRTx^DwyA35 zR9}r?KijGSL{B4EHL5(_jK^LV9)a6~%pfl{Qk!EsUZW>`!$ujQ0YY*|}`Mw*(^TWhyh_@hIYSvk;8ul(Uqvb`qtmq=@d=~zIaB(nLSP~2t zmimK*WkC|EeYtHRcn@7owa!zc=#{E>Ts292@@lHw?_g1YHKwOp8}JOelyw16Rp@$K zr_|^MJ8uHwe&+-3^||frWw`j@ zWLSqXCJefl-9bOuZI2{V;XZRu&}HsbLC5LQ^y1We?LlfEhplPj<@@alP=nTeJ_v(v zdxnxRU2T`FA*haQ!0zX=;SuSenh)#`4`mL7M=}T1j9`dK*}omK(5Q_o%z*VuGfurK zJn}hg2C`R&#bYmf4f?&H*Sps5IgJNYvzTG&D+9XgkjkFc9MQe}^?rKtz9FZ7EZ85` zp)(zWNfY`)fAp`HRmy_dx#!!b?{A_(CFIV<#+p@XDVsQ4y!=HlFkahD*$oM`j6`GSE|l^mFe792c7$xpeJ7&^yKUOp4{}OdO)^8 zb=Gm!S^ulOC;OVsL8)mkEcX_6jaz-Q(K=RLV_uJ`y2fp}H9|hy?FwYeXrxI5P!RsQcE)cy~b*-0}uJuwi4Ceq}IkwlE(fehpt86o}m?3|=?+U=~ za?>*!tlxL~ePRc@N-U+Q4%Y{Fsjj+EkEter6p4;mdQC>y$gy@}rj1xGF|#A|m@19x z$(U-d-H-KHeGr81HGLD-N_58{%+rWYH$3}Q#AJ+K)MUY4&FVYtN!vi~jMDk#Dclv? zF&6WyNaVjKjOQO1kAwe_fn?9Fu1sowa{gdy{=Td;e_&`Jo9vz6neOdP%pV-c%un@o z_6&9xR|h?!~jMS2WlM!n;7UlcXzTcnMrlRQ3iEl7|&0p`w9r9>Z-jH zmEy}Xm`(Kz6l8*hw`}`?R9{#6z`XAMepdg!bjO}#XSO}n+ut*<+rciKhIA!&4Oq}b zHr)%+T;Nr(z4PF~+FG5YBQcQbRB#Q+BzJYD2m7)*n#g1lLtTk%LdSRaq&pHi!+~rU zG6Mp;bJ?N(WP3J~V4X9sT|J5211e3bFO^LtdQyjy8C1bQR`5!C%BmR;WHYJ0-JwWN zDx1uh%=UFcqZ-{Ylue3YI^G9^80b%QCUf!3PQ!wraLuMOltbmpP;as~of!&X?fX;7 z1B|w}2Slm#z^(&bgzi&75~&Q@+xrH4dit}%cHe$fOE8bIfJlyg)9wTCW)g4Lwt_9|U8$a=YCo(A z)QPGll_|s7XWdBHFX!9lcHuw3DBG9L77w- z%oSWQhmfSE7OC@b$Wdz)xpYcc7%Pj?LDYjJO7*g8KzKm6DJux3PLLi?xw;;~ci#c=@xaoGl}A7XHesA6VpSNv zWRdOe7T=<=TmiquGGHdP5|X6)R-;d31tbr4Ci_LFfi)z0cBeC`YF%RL$U5ro8unstHAQ;#Q7=}0AnGQD%i5yuSI3lRqwc4#8ZL9abbzd0UNR<2F6~s((H5X~Dj5oPvp-zj=6s#s0$8jb0?`KIt?@-OpbQb+GE9?#tz>stQzH)V=l~ zDpr$G!G&vh1=(MF@TfOE>Q;j>s*lw^I&%=@+l5l(3U5Z#J&_gNGonN;{|GA8abF%& z{*pI-+^gQ?$Gi%+0vINSN;p8={Z_9-CG}ZpPkfLR_!fz->`4EY#Oq>y{eJuyE4Nx zHcxt2;#{4zq14&^JgZZ zpzcjD^E$7}z2*S2{K!>}AVMWf9r30>qSp<3_?^{=-)NH;agpaVZ=(CP@#P-@%X=Vq zh5KdLe?FTr_%u?atR31}yGLthX2hEU&98gZ^P(eVms5n_JHy~VDcS^;y6&AC@Co6EqcZzl-1mcU^fFTKoPGD+;u~h8n;_z3sB}D3IvHB!FUoZiH4N6%Skup5F-%@}RKgTr&W<23 ztQ58uWx1wLE9^-(;*A~WK7JTRSg{$>RJm^+GlJq(xPO3KXZ*A9>T6M@PhUCg&1gas zdlD7kehP+xBHS{DjqV94eHFSgP%d((G?p#*&T-#~Hn)~0@wUT9(TTZV2cwg`Dekjn zWW28cU$Joh_bRN;OYWjxD0I4lWYyGL>mun<9366 zXiTJRr573Jjz`^j?uW02%XGivAZLUdy|L~$95$VZd$197r@Oy6OyK*VKLtc21B`o; z0T?Ra$GW#h8k><8Zf~p$&qD@(gp!v-ThBO50d2ht%7!=i#2Bj&vCareg54C$oyh!H#`MWCjZF9);y;dO_W94f8Ris0+o^CL9D{ZM*T7`ApmGJ`jo)$v%BCl%aKCp|BZQd3 zFg)UQL0IK=_tnFwk7poE;W03TxK6)fToAfk{Ndr1p-!NWk)a;4AT%#w$Xx!@~()a)O z;bCtUBjqc#_@sQuP>vfBtoQ&!N^k0ikD3gq`$<`yzt;Vj6X_L+S!*zNmDBe|gcs;zxXDrXH8Ixl?gQ{R zlbgMh;e1ec)zRy`>09f)SJGKF9s(!AA7_ z?}oQujy@V57z3?oaD8At1Ii!fu>Wb$z|cQ8cGx@l58jDLHxWgta67bbV&<=y%%4E! z6&MzfJvl%%lcFsY1$O5?qF6l(R+Z(MK=#WIXxYCh$;(&4zkUR?<7E6Ut#dONPKd&> zdowqCUe`1id+B?-9j-s)@Nn9GB|Ih~VBRK5I*P*X=-+yqJJ=f2X^I1kM z_gu}iYu#Tsjo#`oaH0E42eq&gna+pSS2VDbt0-UXo%m-CEtOi|do{h;Z1;B<-vB*} zM3l;XO@x~6-h||}_&;^ny~&97iikGVeFNZgjtKctA>ZKMt{A)jCUUKT2$GR|x5UqJ ze}jDHBH0qE7Q>fDREB$V`3Ni_Pb1>Bg^2I;182vPW~Hy+qx=V<0g8b5Zv*#!cKZh8^8_ z_w$nbWcSITqbAO5K*#aJvrr&npE$t23eM$k=;1(C;eHGGpF$O`b>Dj>E#(vpN};so zsQa-)?2e#?SKzXw&$}I^LBskw#+mLX(dVGkdlp?i{lrJEY}^DML&KXu+UWiiJUFnM zj|LZgOxV8*lhxJUJohECXI-){QW?AxiOW{IzXGPd$!lrw&V~;F$z=4Ll6i@~mH$-x^>;(A@kn{2x8XW(d;`Qf&Hb^?|HEZ)hV@=#Yt;SOP@{VVELRFxG5ncyP0< zAq?WgYm9e)4zDq}St?sOw|5T>qXk?8fk362Sj_z{)Qd)RuWC}i!152H_ee`bWh#G+ z0hp*X>V6AC&Vj4Ywfdtg8XHip)7%eW97wBv4)$@{R)8wpk3rLP_i!(p#iY?8K{S!^ zmNDfko64%)*RyrjxZf#L)7+CV4TO2Rk0Y0}WU2^*f{Pb#8g*+)J=JZ&8UpkBj8ykj z_bX+MN4$kMc`J@^Wy)KRMuX-u105I4=RD=9KLoiZyOm^clKW{9cC!05&EQjIjhOU& z0hyw={Hd}g_ueaz&1y_Coj6rd7?&wyS`vmvZ z{lg#`@7{*hGOyyMvT5#7cbJP?T#MjJ5*MnlF13%Hy8H1;tYf)np*6Y}!b7`jhDTkx z!b$;_oTjm-|7vC9Hu$c2T;am<6&BFAZ1pLOW+%Hp#K4BK+#rixlimNSFmWzOo$20N zaTGGbfgEdbtBXG92-edo=$j_EKhuSK55}EP$OQMbgDA^2=w7?nC~rf{CI9_cH5`4V zi#9juh*t4!Xcp*6!0)p>`Oh%30h|$hkuzc+*jPOxmShDa=#sUVFj`83& zNwo4Pq>FLH1KP=0{2sXu@Jb9dj>4Zr3W{iH+B8rkUSVUoifRG>JSmo;&Me0SAlidd( z2n+ch^j?9$9IK9aCo7SEgnmUYnt?giFfi`$Zow)t7KR!B^jMj}PgH9eUpk0o>#^7= zIM|54sze8|+f~L3F&NC{?(`pHXa7RIRelVz|9cJql)mF0?6=Dqi1`P!DzHD>nMwEb zBs2XPY=>sDDcL9EzIpyGxV1%|zaO5vxBUOp{6`} z|1aGBHg$;|Kh|J)zdLk#;eW&CcX)f-I+daJHZ6d4Ok*GSTe&f*i2iqNICG0tZ;Df} z@ZK}_ZjZJ1oU`5DDf`acjV)yZ8h+8=faXRt6vRDle=AxU$9^8f=)`sbwt=PP3xH>3 z0CCEi*j-$&IcJ zi(ZQRe^C%~>y~kD-A=H!=*H6BbL*BIzwV+lvNkD&&>Lcx1sRWX@4)&^*=+Q+N3lWU{_TpRWldg` zX~1~IyCxESROI`cO3WRvV<$dCB|ZfbxsV7GZZAUJoaR1N&aLF*C_XpR9_7yU1z6Su z2kxL^Y*zvg_l^U@C<~;W%Uzrcs9#C0v~jEoz>FLmWVV6yo>Tr&&mD&)(5POxoCj0* z#!Y$*^V{(e@4Rt;LAQS?*2Y_~jwKR)ZD`Et$iJ}8=V6faDU2j1U58cp%y8Kx&ZhnY z+Zim|llYr!9+SK|?vJiGig5*Z{b3$=!iMHSKi5@3KX1xFLH`mD*#%b9XBNuQ&keZu zU>@s@o2up>#7r`n_W;8!-q}sEVChAhg{T9gjxy&XW>1rZV!nh_;t3yp+|Gxo<93Mp$L$c- z$L$abAGbpW!Erlc_nYH(z(6bNxE-_-9JixPrkHXj5CH$U9Son{njE1+Q_w?1UE1KJ zqUo-gNw|+eht!+yY`383iU8c#p8!|?s2#gXRcTZ~k&|RRQe`R@R7fBv$q-Z_hy@w_ zup*I@WID)`WJ0Y^jDgxeNhT>ZT+v9!4zTXn0W>GSq~rC^BkDtC%tIe4L(uNnp+w!W z17SLLFg8Iz!zatoF{_Rp7~Qc`4%M*(h9P|TBqQ{0o%Z5WB{*PUT-$Q)EKY;(AAhuL z4Gwa-b0cM^V|I!8c@>=Xavo^F-1#rE`00KWTfXD4;D-I*3M_@rh{_qS594SC`<)lC z&Vk2_yy<44=rrVHo_m>wg_fggFOOjJ$cyY!Dwj*JdADUU_6*0i$P&Gro}RTonHfl> z`)0{0>REHLI3_!Pdwp~Ly4L#kWeXO}-<85?y0e^IKW2_J&gVJG`Or&Wf2t>)b@m_V zZ$BWv-Ojdb3yy>1T%*%|$(H4QtakB+bYCA@2(sP51A`4)THEWIaWuA}F_o&XuW#7!)n30}Rlh^@O4#l>v+%RpS(n*Oh!anu6gbW4#4>Y9e z7cNc>Y)|e=W|Dn8u!_^tIP1AZ&Z0wsMRBZ_Tuw_1P+y2s)EhI&WMN(gTYy{bvedwi z^Usr1~YYCJKERc5L0z0kAL_`Qu8*riYwW)!P$!upgGsoHIq?LUEcp(mpayXdW zM2HX%gDJqJc6q>MT~}8DDST*w)C;XrfX?I-lE8vHfmyJz(8?3-FaR73K9Cq1XvZPc zy|}NC6eGHzsWrPqnS1Rb5Q;&y^CW9Ss<~r9eSPghr1XbBzcUlA*UN zB}6_L)2A`7mAfzxOm9V%&b zMkPq14d&peq5xZhEXQC~f-wF4^(nvQoPBl)c}j{BIQRBioXOfUnncQ`^-qQ5^!NdFUuoA!ExyDMCH)$LPFv`L^}E zPrFWflm^_t+?~vTj~btfp%o)Bqi|+dluvCfN5t#Yloy6;#h9)b@7jejkl(Im#VC>; z9W_ILlv|9o(NHn`=o95pWL|iTdGRPo7hwfewd!J0Eyfyy(8%9WRabaIJxcCHr_rON zsa=}&C+(;uE`8LeQntnmL#bR}8>o6#P>1l%UmYyak-{@)VMTOST(#R-^TsX>V$Y{wH$Y94T!uaOo6atS{ z2@AuFe4U0Fm0(pljC@6h8ENowNaSlj%%~LmDzZd0np%sl3yqSfR*e@?7g#dNuZaLS zTB$=!@@oN1N~nVnll&S`k{q*X+r`P(KA4oEd!I?`U`M`A0$^!60e!ws0$|BZ@^zvl zDP1R^&(}!+EKL%aO1@44V98AKbwVT5YvrX`tVqJ*W58g1hmxdpoq#@HCjoHO;w&|p zZq4MY#D|s2B3~g}Go|PwEJcnwM2cf-!(x%IjIEjDYBLw53n(K1j;am6;ekG19RaXp zCi!hfNpeh$*plR{1WZcMiJ9RQ8xNSNYB9W-(v5;2b-ZCFZbj2`!Zu1vGn1%d>CIHA z7+xkc1*RLL<|)f%3))F@K{3W^bqquWn5(Hy4uaf*&BkTe7n2>aU>IHi>5sq*r>(6W zNM>8{2uPx%Ct2Tt%}_ta+?on-ti|?~pMraECQ>W`M)s|E118mpxq=CfMk|llC|U^? zDR%AR;JC%s1AQ3%g1!F$l0b^2#LU5`+u6rQbENck@&N1@H9LdcvFJ?T^`lgFXnPVb z=j_MMX?oW#D9zcXC!rhDnO3|Sv~t;MOd9)k&ypV|+=rhfbxtduW>4Mq7kL#rX|mz#Ig5W#|>yTziKK4jO(Hq^{gpXsy@D;j_Pw~K9(tTU|`RfRwNV8aiYOd^a9OzDGvd*CTLz^{Jdmy8~ z+vJn8F525Wl6XT2&9hy~YT1o`IE#E*v$abCLs5u^Pz}{C$rZM~zK$Gqt^I2p7K?EI zM=Ta4u^fzLkox|-qOA-JY{iOP@ntQ3iK>}n7u9&y<4LfG6?r@fxan{_N#M>~7ao6- zaxGbSMpCtAxdVP)IyhZ^>pPROJIbQwK$#d}T7CerKLIx3MU=X_JU_zf|l;F1Yc-qk)Yd8&k`_p@qn=vxL z|L$}bhCPX{7ImX%$hi=&x+VP>yJ{SOqj_hCoNa^2%#ex2lky@R29sfUYiB0aFJqG& zI2Y-qjE_q{~u$-FWddJHWQXcB5kXgms;G zce1`^={6;2QG%x86brL#p`B==YC^Sm8`an48%aa9J~SpB9ba1jt%o)(GPo>6AOjbL zZYqQ~44U-tv_Kw;#V7=|3&hK;=MWI(#h9K>N1{q=1(+@qntF_?`~--QypWWZ8}Xfp z?PiL)lL9#xb1Mtl0|)gl^A0%`n@h2h)zi^^6rwvKSKpGttw@av)BQwXgK23^KJ??QCn6^WiMHGuS!c_;?=R z2ZX;n5*>r^7@W2=3tT z_ux%dI;IVjvlEWYp^KIkn$3yK-XPX`AkmL@>9l}ucP7!_-I~N{GwCpysTG4uxBxv- z*9JU7E3bMwt^LVPJP{n^v8@^6_SF(V<^peHkWoNxTor8Z$wM1#91u?rY_&8n3uYTt_yfd+}tp53R=&+juV(L|X=X zJ8*UxC!|w2ZXZwWPGt?OIhm#6G{x2|yrtvoqn(VCR-D?hqP{*IN!Y$2-G`HJJvxS& zeQzSGBX~kLlitk(;EGfq2S+ER0bA19bpvY7>nNexccRiV@X|>GXigsp19qgcJxQBl za~g{TDU?C8Pz7pX?=&b@Mj3hF9AhOL8pqqhA;4A~V-Eo~K$po7q(KeIwhg9HDx29x zo|Df9Yvm60cBFgSHz%^)POA!UfNpSHd&tE7LTJ27NLy2evAhfC%B8!7W%ywyp2{@y zXFGrDx5#g+{O;iII)Q8u$a(@KbfNri6M!*3JC0 zUZ-kcWP7vx+1M(7TH+02_DbN|+C6w77naEG5i(mbr%_>O(@8(FAu%Y1Ymo85M30Z$ zp4#1=^<&M+T|s0=Ceer2wxLZQCIgy4cT08NffUOAbWXO=bvW0l+LIY~gaJ0~!rm0@ z8zVC|T=2G|HeD?qvEHmnL1x8lszqH%o+(A+rDFtLC~i|O31N0%8k0i|kh3L?mLKqg zf9*@d0YRl(((5rm+>3Fcyo2s+PIkf9Iby(0!$2CInf^GH>BQ)=m7^~Fb~qRC);iPU zdVkW{0(YH0;I#544=!KeAaB;$NQX?P9%#OHK^Gkl-0L81Ac$BrOW`xw#(~$NFj72% zASGlWYiqM<@dg{H}Q2D^kaA^-NZK~J2H5CT=Q9n z<<@|<6=@TG${pQ_L|?*C#*_OI+l@!p4Pu7g+ludDN9f15W>P~w zw;hSz6bAaDiuN7Jp26LNCf1bb>%*AdL^mgT5<~dkYXGencO!11kkZehIg$3ksSeB& z{8DcoO7!8ec7r`Xna0EI0eTb8st@||)MvX>>Ha`18_;uMLIyKc^1{dyFy_8>9e80I z16Nq9#%$f)9SFLe9k9VPb@$T36@$%KjmA^*T@6`Oh@a>AX%xhdVLFI&DOr;atvAt=-fg1bIM|o=Ggv>^o$^f&q#cRA z1HQ^Pq_G(6^KDM`cKDUIBav$M^~5ecky&rD*h%BD61H|H_FFpGI?$Ww3oK;AP=6+c zt6sXq>+z8VJZ#}d2cdTq$i%lK4=`)oThjFBW1$2pwzAuS-Wvvtu2EG&>kw{|rM6(y zW^1s87u5poHo@nn2fCq0lWaXSZ0EdTurHa~h4F|XXz5O)!C_$MS5Zqh7U^4j^=;Yf ztGRWsuPb45YfkoKxMo;w#n>>l*U$Qbz|vb2gBgq~F#9#MO=uY#QCoE4$ZKJobg)>>SYV|m~!iR zOQHiV(_-0@=;AnUr*zJ0Ij!_1J5zd%KAN}x6SRj_%m2Mxw& z0%11|qPw*lF1Iha7|3auF2cGltD{_xo^kKMU{EiZ&~)f>R>3e@tu+W*1uZl-kOx$ntr?3h46^7^d|A#AZfap8C?Sw$Hlah| zlx8-O8pxkb;Kni67W8bwidigb>rfr(K6D;x`AHSY0@$>;m%RxSSAQKuh(i#Y8k`|| znAir`v^f76CiG(#Rb6LNb~*UR0x!bM4Uz;Fij9g5r0nL&7KQ@c5TI8{y;gu8%;je30u-e=e z3>z0-v9K|rH3}P%vn*kw^4B43tUdF$;Qnks3{%b0f`#YyHX=Now=iY`Z-MeUGYf}% z!LkOI)ty(+-xY)hRp+~3iy2_b>sm15Y%LIza$QpGuB*lp_*RP$KtkO_i1IPOqF~!XL9UnZGa9d5qn=5WY}yv-#FZQ40~Mtv5jz*uCqlHw>DJljz;M z;siOncf|?qEjytqB=P@yJ9VA)|KIJ@f%kFl)FDOAPF?45?9>&hUTj-qY>@2IgSTQ- zIlFVk$O`PpS>8<@QX6fDgQE;$mg6ZL8m|5Il$JbFokQ*>E@}*^87RQLrm%rCgH1F$tU!Ore)&AXkz) ze0Q;@z7y90@R!I?zUW`o8B}Cog1H=)f-%ph>Z8$C-b)Ae4JMOvL{W$GGU(h7?SQ#C zzcfoWzh|*FX3Z@~y+5CNKRzI3U zs6d{KJhL1Z8g)$AkK|M0Wf(4bB)cxe+6x~&;43o$gbD1d7h@|ywn*e}9=nB!tg3=g z4W*i!t4l zxnpi6S@2MTx{gFAr;IuD7C1z{6yF8rfg?6e9TcH$!F(FDAvs1C$kBBQ5O0(!MwZzBJDUsr3$dVS=lOCET1_R_ISW6kGDn_ zVysaGxh~}%AQ~!N`Id#-vUq$ATVbt9oHWO$s&PcW9y^10@u_b>gOU_C2ejp3zeHJlj`kN`?D%UiE@(rB-BGFS5ycv?y%Qi0rD4L)BUgDD`6h02r0;0g)@ zM~mYI^~g+x@}w~Y1;jC^Lh@L+e1QzIphOvbkDVh$jz$^El?Y==IhzKG0vU&~d0AWN zLYe#M&e2$Rj+zuH_4$0e)_u-Er~D(Ww#}Ggk@;v0h#yTl;6{}X57g$^Ij%Gof)&UF zl!kYx-&s5WkHFEB{B;g*<5QseY#+`e;{dll1;4xiroq-zeI1Vw!LjfU1?8hC`P>Sn zfn@56W9dm$u}jE+ud>qH;g8eGpHd~$2@4cqWiWMH?ck74LQab+SvadOvk0-_09>oD zy|wS=;&Ka`iJD|coMHu}usOK_fR0Cp!uZ;S8mxHvRE1b|r3P?fN*yhdP?*(HgKyyz zvob*n6D-CR3M6l7+3!dwj5RJQr>q7n{bEoq12(1@V0_1$o5FaUoNSG+DFV(Br_MMg zR(_DFJ@F2p*0eiJ9?Zc4V!aY2Qd^v5^=ZE&#v>C=)vze-VgZJm0VY;ZiMqX11iy6@ zv{_mJgJ5|>U6={kDvMKyJ!Wiv_5}$rYa5-w(qy3wOp6dT6(XozsM>;>AEUk6QEIKA zSUI!tBFfFZnp~7y-i%#eCo3dy*hmUd_!IhK`32@wD7j42i*)d-c> zJqA&6v-BG+jAIm5rU{Qq<#)5GQOU5!#kRbTQz8>A)~axiN@%eJrg-}CW2D%s>>Wi? zDG)D~VhN7YC}~un7~OKBH>NVUT7xs3CR~hq87Z214@VI*Sd7;8ZG~!5IS2GM#q7{u zXb>e8r^{OdSfCdk3gsG_$?ML&5M3}aFK$2~A6t-#b z+(9sFSZb-V5aZlrax~T?J6Ek>m68q(`XEmJ?$Ym*w`Y0VtW;T*_f}Vx3%kjj!YS)M zjs#dj#Uq_*|>Q zyOBa$QswvefY_L*ydYXqvfh-HOr8fVHQ8u(v!v6sToov8^Y&G{qN4~s>MGW7j)BHe z5P9r?e~Jo1zXrD~gvh5*wJ*t-LS>TtbVSm>hP+aSe)f=T#R_vpS)4^7c6B%iC~q(n z83Y|)c40TST5W~kD+^&kix&S_!Yu9d3$H^(SuO6=1(UxdD^z+soFU5`TQK}xW^|>y z^CC&~ge9D!82^IAqnWJku!?sjOL}mm6+1q7>{9|obKa##1M;`1n)Eic89GS)Nu+3s z#fEVa{nT+Ufa2*vMZtz_h`^&DUhSvpA&Lk!+8Cv_Rt=;~DXdsA_0%pfgc+4%B)oJhr2C9s2}==^wb$Q|+60Bf<{EJJ+$!u=ALV~Gtw>s&e0upFt9VbUKHmRte9Ug>MzDSfRe&vSNjw z)*@LwtN0LoIn<{GVg;B?ij`oQUdvPOljvnRe}&J27S#bx5%TPTIiZ!4w$x-r$3{!_ zvmf;>);gnJ@6)KFdDQh`{?smBJ~N1uc~~l}ZI?-vw)Zf;D4#__*M+M$xon&erWk|e zI-mX_TLgUggx@~#am7;C7SEpPi@9(f&y&0F4Y*%H;}Zk5M7~n`F3}TA1ix%(S*hj>rb52jo7r5~4VN zd@)4r`}^fWa}8EVM=Mt-<-eXou|gEBQp_fBfZ$(|*CZ=0?5MnpNt!n?5dQY|3KqWl z`DP6_^-YjOHchayw^Y9|kw+1%#T6s*7vkvr)k_rx_LF=nY*`ty+{}EMfCNULcZg1U zRhvg>gUVW+GBj$qWfwemX{tD-ES4B_o|0u{q$pOFL5gB!38N?$r;q|IdzIH04DqM(aJ+{x5)YbbB`0%T33Z~wr#4skC zRscuS_Td#2-i%YxotYlIS)w3K$z(rXb4cMH@9uisQR^9Sw)Up7IUt+8h*b0eN&gUP zu1waBPVomUi>3}O*&cu9dZlKR&8!tG>@vzQ&R1~AGvuhc&{LB|O95gz8(1o5J#{FF zJYDd4$)ci=T+J3r;$HY!$)engJSka}zVLIBMalJ3lI)I4lAiQ>YE%-vemJsZ{zaaO zEGoY|6In9%f)7KE#{0O+Di1=IEQ>kBTAJR&k3J%klC&Rw=dsjOCA{sZo{zQWYq^cy zb^-oljlQPgpcR4M_p#jqy1`A!gEF zbi#}0pvc$Gl{W=(Ri}OcAM}w>F#=q`E|OI3;}v4Mr)ZjkMKMD~F}w25#u@3m@=;iN z!yQQfF}Kb=ET4|&m84Hz-QqDZ6)Hwhpg=llfdXkvfdXkvA*pk3w&ZC;Erw_-Vmc?X#2sHrp<_dF1T0*qnkbk5pg(VDQXqdls)c;W?87iAcoYNl1;*vZS+Ah!E;W?akT%W+3G<-hP>`U-d z=fR3oamMG!6_|76O?MTZHCO*V149|ScBijbvJS0p@#4Bqc%P=B1$XT_csxt(M+Bd) zD@ZE4+U;D&@I`LNyA600bfvnJqn5*t!9_N?A=t6V^1l05P$u)$hhuOv`>e+%lSX_j zrD6T0$I(yctH%Y8!5EWNb%E*_bl4{qx?_OKIk&VdOR`mDXO0JqT5XC>?CV%` zC7CPufvyC5WyUnvV>LR`m1L*PxfDYsT}hS-!Xl=cS7o+k7PDAu8<~b>C-Jw9fw1A$ zCR*N+XbV?hDa*nZTAr$1VC}W#u?}GiFc0AivR^dNjfYD1wrA7ryKoX4N0se(ZZBTD zNH$oqU20_x-M{6B7osajb+%)99jgNkom;SPQd>*Ut{YH8XFWdJzQEo{0VLQ)Q9Q$K zd0{O+a$&K>HUQu9YiRDMt*>9W0G(Agjx)Ebz3%oTUwdR{Q~>-h@x}6YdwN$p-zAbx zPV=?F{0c|DfbzW%cBb;^ZhLQHKwfgO8m_-1WVC|=(AE|cH51(G-j4mJ-f#&*v`Z6R zT{wA(4Zu!E2TP*H?O}1G?fp14&yHEeGXB`YZu6lW1KE08ns}Xu-&*0hF~3|Zd39F& zq+jX~hwxqS&e4jutT%B`9tKbYjl%q}#RSt!V{@hx=XWJ&38U^{x5xPbZ(UfCS9-Ie zn{|?k+jOBcT)EEymB8klS^S2~|HIt7Ek|x6YomOWzS^<=6%+A`I?Lhh2(?t*)=1qt z+Fmm^6;u@^u~k)+>map!G0(ogOdN=h} z(?32`@1W}*N_RE0S<@qx5tEXTHcUDsu+D=B*URB-pCVvx%q%G4Iaqd5RvO zOH~PbMv9jiz20M-D<_5z_a$OizfyeK$}zR#O0?z?y&j>E{MY{h9rQ4kL*>teTn$Y6 zt?B>yzi3?jpI_)|W>s-jZ!@8&8sC6jTeKEJ@{HX>xOD&&JZcI|tcbN;4qB)2oQl@- zU(NT;o3AJCdMT0eh;>rT^KAy;P?v_55fe$`aZBOfIl^k*XmrJ^hti^|Z-#4gM)W~u z#U*zksa=tHp`>#ysqYNuIBgw@p^G2bK@1V-gVM&hr$&FpA=nVs)8PbmP@yg1FD*lF z<(zK+LHR;VGx&(ol1q2xNzcJkb1zvjAEG;0Z_t9dy&VQRqdxHz)R2DaDq(wE_u!(~ z8eH6iG5CID$0q)3kJrDm_OmeG4tbV{X4o(-GMyBtag{;|J(jxw8ibm zjl=rkn#^z?*T1MKl;;1KR5|_BYW5rn_0U8+d@b^~vk|mMEQXbe_Q8Vz2Wg$a9~E56 z5LFMF3=aN$KFIiPt8}nyQQkV9Xi?rcjc8HYJ_Biiz&ze)QM|Itgj_VHMvkv8vUp{WOU?p5zui znzruj{l)4YMmwBIAOtY|a+aUQBB$eDDYxntvxdeoo%V*MJ!>>I(!$?Hm^F?mY&OEP zq#Iv=rFCB;FeLOraJD0ct`txkI+DT z6ap3C+(k%;mDCsJ_N;Pg?8LJWver%9W=_$)N}G2wr6;@{IA;^sjd4D%*6lkmBy3hX z%oDOGlKZTo0~-VMcH?CPVe97ZSAyvAlZCM(JAM2exalM7#>_B2nCfs4en%{=mR;v? zd|y1)f+MjTu|h{7w{ed|gky_?P*7T4=c6E6B|wAKS{wyd8yUdXHbN}z#6mhBst4t; zSXUG>j~C%+-AcJ!3#d29DLySty!}ffBQTrxDJC6TZ)^%$ z8HR*iX3vq3wx}*)LhXmB;BAo+pUYM9*_KRi@U%tbNOvnVm1S%AhS!(b_mpMfgXi7W z6+gmEOV>YnlvveBy=LrZ;O?V|IRm?dC*B$u-_6cL<9pbJKpf{f55)JY3xT*UbsmiG zP3MF7j&vT3??dN<`0jHa413P4;js3dta?YfP|!pp1*YTp2wF;8NnVAiBT1F{({qBg zjO>Qcsu3jb_Wy4XVEQ}?GCEQbHsZGGnjTTbY~$_dlF^s!anK4?)MniZTf~0d3YUGU za$m%zXm={E)IrxM-HNWbjk_H>^_qxlyKRL{J#yk|l--c^pse72y9l-ED9^13OFche zjD(KUh82ReE3WVvMys}}^NfxpDKv)m(uy2?MADI-zVL`JL%rzJK-G`R3q*aWyg>8g z^!qCOML(Mn3!gAkca#u?(cee65?lja57U{#*3UdE-%9v#y=`3E=tDBicw;@xytt*I z?_PHl8uJjgBPuh3TYsoJVp29Ec!l;d=P7(WnIsfCCa!-^lHueQGw&iR~>P3f8T^_FC zZ)n7ilV%x>wil_>k!|6V=k-GmVpEI%_NWhQunr(L?QM9wD0^YGfwZR~Ze#4Bw+w{6 zj1Y}4JPOhOeND*gYq~uYZY&-3kVX~t*%eXN{Y^boGmmxMQmX?)F}%8BGd$C}tLDnp zPUxClN!#P=)^y%S*RDxAx?(h5up4xdqD;Dd^~X8GkE|Eg8Tk6(okZ6U^IZS0{An%3O0o*+?+;=YPk>5V@ z{@5MH-3zyU)cr79yT>t$`yf?gG&Yo7RU;Q?Ka;%13JK`BtKPwyVju*4nY+fLK z#exoxjZfl2M};^&#AV(|j(A9j`G>3S6nBYhaTELCID!=v3%*}38X|u8&HX4b&ffFlyIe6x={Ger^B~dSMeP(M+LAEH24P zx-toKh3;_~%7_A6`Kf(y4VCEzsmiQI$;4i`7pqK!VUjgTr)1$>=!Adr0yP98V71!H zrkFIV;p{R(4DvoX5v#8I1h^v_;x?gA;{7T*la1N*uY6wec%mPDh&B!%<_JGAozgRg zG~4K}9eBzvY?;slsTA%}Vq+xgK2nd8+Y3ME$JR*Z|8RIQ3R3mI zRX0VR>Z5MVPJH=ZU8#auH{M`TsafD}C!t548|_vS#-1%^`$R?`t%OL2D~z-IhqpCe zbx-28%@aQYn-vHVkrOj@na=e8upVg98&AoUqFDA{s6HPKNDgZld2W7GGBrifnkT z-`qGwzz&XK>R=hY76kXTJj2s>#i&?*M5xCT`2eknG{sA?tX>kP!8iTh0$}*1I!aFW zB^MD$Q$L|(6r(nnIQR4KFWB(o)}Z*|wGl4^t|oW+d|Dv*DPCB6#mf}Nw~H^`r5CH- z5ZCi5pS@gG7XyuZBwp@Y{<3*j~M5#^FSFU@4SHiHMa3uX#u=e zeh}}$f?hH#9tsDwm+WB=mGlWe#Nf_`2-A-qQ9lXQdAf6bku8f^Dx`UT!XJPVKSD6( z)eEP%c~0tNRWcr^_MljBl55KlaE_lncT}J0eHI_LtMb1CZ5Rm^qR0r4-h3H}a5p`Y>kHP0-)30) zA7@x6t`JLq+8y_ne18|X2Uq4o7wc>BUUK!`(ziZ{SYTA=og;XNE^*M>@} zhpoR2_)SoW&rIjnKm+OKG-FU@F9$}3y1*u8eIw%#rpgS;(7TvNj2!r)iK}H?#>`m! zxyp0cZF$WxGWNyu(IVY!MY>fiPWfqR)@*DBrzvclx2mh|iKAB8?P5W>`S_1w`9yk- z&vj#JHOMiiBP02UZH%XSHa4=X%W6itUPp~Iy@UqRj3jlVx8i(|7rADW_8KiDgiBA;p$&;ycOXObA z#>N%6qh;h}n9OwIN}#G;(PeJeRM8>qF&Rs@ zZ(|$vTC1wti`7kibKHkh%}}NW{%SFHk=NYbHz#Bny}&?eUQ#!bYw+>B@*#lLY*qxV zb6?!3(7gL?B&(5o^({08<$%BX79ZDF-@MsCy3=2Mldpjq)#)sEdX{qSvfYYgZQ|ij zTA>w!xfh-Tb}3$zUnY_)=J#soo7}fHDuGdYh^ciU*BNh6?Mw@7;JsO6k7L`*{gl~M zneKOiac!_R)9WDXC8zpaAF*@0(4h3_rFSzIp)!9lj5L#9WQdI-y0-n2~>4A*hN&XPTv^OsvpMp6Dqo)$4!?CE} zqUsPlosDR7$yHf-yHqSh^MN!O%9-CPq^Ei%7pIN4om>7!Ps8(O55ZfmMm zmZ@S|8I|g%&Rguq9O@q1WrL-9tW7A2oWzgra;zrt+2|Ql!S4;;GL;3!v}ISc+Yg#b zV#I_}xh-MSX21K2E3^`sA8)M=xXDAj8uN>o)*F%GM`NoYqv2Dhs)dc-J5|7bthPEr ziY8B~O4JRXKb6q1ON5^5HDpXi_OoQ$+?H4w&c?*bGq)zrfHWiZ*kud_(Jo`^h*lBj z0K~L{+x9LSpS1_Jv#i~TRhPM^aOTAg)(`t=$SNp$NlamD!RjVVyKpttTFq&LpneI7 zRU2rx!YOQ^v>&xo#_q(JJ%XLc9uOx>^!ld49SAI z)pW#AC}v_8>SRgPESRU2GtPAi3KcArQz>p?td5Fiw~vk52l6y9)J!&B)d4&%vB{|e zK!D?V06f`S4}jx=dH}RST~~0}2J$00AS;rC7DaMENF)bsh~zMb&2#oBm)8L?Bi8|O zcdP?qhOPtRZn1#=W5|i>al{9%<`pB6ogFYrjU=aQhz~~Yr8wAEDe9Ppk8iYm*=H)^ ztk*PeX+V2rQAq8zNTosvU|)S6K3<~VI$@m_=~fwMBq~(K(AD&LXF8%S?tzX>wN7(1 zj)T>#7?rFs8mzRBR0M)hnt#S3VBHfUk?J20X);pp^hX}KiIUENjY!m|H5!XLt5Hnj zZ&rD4@&_I=hw5weDtHe~S-l(kf%6DVLs^1prt(E8GvUcCr)1XzVt-*X0Z(4qwXyxm zgb>rQPO)_)oeY`0!VM#3JhjrXArGbB;y6$q?VW3Qp#PH1`Jxi`UOM@(SX|^wm?`8I z-OTv9n%=7not^@bC~-MA0V1q0uExr`=^1V7?H85^ZWe$1Gctv;M1%nq=OY+XatI#ev7_vt8UH0ff zAkfAX?`ebN6Bz2*_tEUR{l#crsNJGL)vlaje$VHNK*iA1*s;%&f*p9Bi~6-l;j!!G z34z)p4ew1ZZvf1xRjsbuOohgp?;^?Ogd#1jUqK*sX#AIx9)U0DUSE)o}*Aqz6 z74Bs7$HDiakP8OBc-m4$IQv~^6VI%yNjz&B&nn_s-{M(|c-AtWHHJrKwHn&g$8+R5 zSvg1u?lU`RqK%@oc1dw4Tc3@>QC0HH%%)sstjSxS-3X#7&<1dufl6p4d55oy7g~HC zNPE3q!b$u!8%}VUdQZJC=bJtxu&^$2Vgs11sZ z1kj>>W07}CHx}Z`M%{*CM(I}Es>*M~s;bz=d@_sHG0BuXr~+476Y_?hZ7;G`Q`10X zB6N*JRw3K=Z;Tno@NeY!PKFjn^H9JjWt|8Z>5faGg~~Z9FiN@S1V)y1NMNMfCj>@@ zyH_=NSKaXNMz3?T!_BWQb0Eh=Y1z`u4D;fPi_JEA+Dy`S^V~v*A~645Ik-}DbfS_x z!K$ozCQZtsXVqwJuuW)VlWi3+P5TDpO}oC4Y#Q~=WWzddB%6kQGdT>c{aH31%0|h$ zk!-bFmuaWP=;FN1&=)V`YlGPrM&Vlo=v4yHqA<3bElRa(a(XzS+fw=Q8*U<;z+8qu z=DCrd>j`oMg}!pAw^C8Sid%%-WNNgC+Q6H@u3wcQoiK9VK9zHvQQgb)J|h$Jz;E%~ zy=8d@LvyGgO*u7r7v=0RSdL7t(ady<47IbzH~=O>E*^yd{!fz<4s%!H)``g^H1@Py z(d8kTsRY&Du80M@ZeJNLw{DvgF6GE>n`+HAHYvZsMoH0J6%@e4Q&j1O-;Z|1+K3j-K*qmZq@U2q>CF4&-krchp%9p(k;-S# zq9}Srr18PNljf)j3KYrg?FvJY{KYe;&VI@0fQil}UO%a~t?@L&F^QHLu16QfIR`E$?t(uHkxVAdFIdUee zBsEltRk|~!Hs#}seD;WIg|CVAZP&GpJCe&4t@|QAh52bi?#Qh1UH*MZCt=n%!KO#- z<$wE|l36t8aYrT2nlQy8&J0I$gm|LT8UegPX)8uR*j+2aPl( z$ZHmjz@6E5N8M^L-)n~|)9 zuPte+eB*AZxRoB#%)FZ5{P+6{TvF)7wJjMTT$-eHfS{BH=lq#{Cr4~0)5D|IdtAI#u7^DbQG3RqDbC^=xO3{pZNXw2<4=N25 zZmm{h)g>X_TCw^{qTM!$WjK;)9JRRREH@oDGu;-~yv3z#$pjC`yYcNo1g?F1FrN2M zq%F2?;i9oD8*XN0UvP7jjiG6}?O)}VsxE@dIkg5rw9*AIZg|H~sEgiuIC?l#Fg@HF zjUaI@B)b@_Tged=*5%{~%)WUQ*{j64*zM*!x4YeJ^E$Jaw|GOeR(Xxn%`}v6kS(^r zE{vgi@Ky0Bpt&`XOz?(pwWkmZty`Hjebi;TdAnbsGNsDF%gs&UvxAFnI$)Xd^YiF) z0kt2`I*b@R;#S!@Krw-B3s=l_z+ysc2+S_6xQ@q*%{t8Nwb~Sz{a_mdlc7igucP8c z-jitn$HKV|PTh`a0M`f~uEKJ!uElrOu=jCix0#qsi{^l_p0SS(yf$p{m=KYFcxiVb zj1zEH$a|ZVw*3YaJY1QDTpVYOkph{#OJ-8%nP=`Hdh`VAg zy1J^I!x6Wrc@W~}sc;8$yZKPHwc4M!;QC=e6Po6MMu0K-k(0Gh`&>+xBZ`}8T{v^UBgDd2XBpw`?FTiwCkL_LfGl1s?<+UO33NgZFq1v<@WYp3_BT zp0B%kRuG0*W>n>|0y0GO6)W~a6q9uX<5mil|o8^XXaPys@4<6sm@D6TS z5oaNyaf@IJVMSFG3@bEdj0Lwskr$~D26-K2!0{Ui&qO$oxXnocy2c+pQ-&sibc^CD zNbF?g51F0%J> zwPc~)5LvnjCPcjuk*+jl5abS&t;4qwaZux6rtOKcT4XV@Y~74{R(loEM8F0rckqOu zE<-@oO=iMn?lF~3C}O*0lbgCcZI^Wnw=EDTyfrajz50br^ANN6!^?nbjK>$TNJL7l zXPB|WSLRfC(yf|6ta11FHJ}y38XyN>4P=GxJY;8WKx?#^sx|daDX42yE@i5)I^r;| zN~wV0!tDU*6b+Q7IbBE+rgf~t#uxRfs?Y^9vi9=@sIeR^L<*HhJp#4ETwTB5m4dQI zifEaIMw?<3VODO{FDlzc?+_6NGH6f$kxFVhUp1(rC=7hHz2n>b#hF?i_oCtx<#(_| z!`cmw1Y2RTXB}|EI(0{f2)8Q4-7;}UPr7+jL91{eo8F4dPZQjU8zl1URK$@|pW1y{ zC7jJhlhruC$g?qSUfkv{PR89lD<*ahoj{+>7BYS|j;~+f7G2fN6bDZh^c5I~R>Sfi zKIe!Pw5*XERk`MDz(btTFL?@SD1LO`Rl&2{+PWIHcia<2^#;Qg?I><{hsiY|T&Vq~ zGZ>AL$=A~LI-qAq>`aD6KtF$OG}jxWlv)GZlnu?@jq#XQJJkGQUF%SZrpZaA+1EKL zZcxBHT(*OB%3sz}a>!xxM85iI0qi5XC}$Um_+{n7(aAES#T*n&PCI2b^h2{sYyEtU zey@0B7jAqhB3Qh!f1YJSY{DS3z=qtZif+mpqvXbXsmeBH3Qoq&umy_4NH(J!sN{5q zWcQz|#gboC8OR&YDk!_uw|7~9BTzRA7rbkYDlWsx=O(y8s0nT)SK#UPvLwamQ#l!{ zkO#U@D6=YR`##Wu$&$r9s&u+J*g_T7(4?IpDxWdM z4xJUGO6R&{85uFUG)N6$FnaqWArVJT6m}!smo9(w0q05hu$e6vCUdJ3IVnaFGHYm& zUVze=tN5c**UcR+yi-x!I^-54POpcq9uo)*03$QptJ7t^&WNQyUMq~^{ zT}D?1y|~6rUbR@4b9l8`rB2}u*+<|Gh7B4_rJ)UOP(rYELn7s1Xu9%w{H4Xa~q@4uP&O?Cb0Z5zCm@;#?hSOt&rX1>b$S6^(WjJ;<-x<@Y zkCR>%ux_Sma4WR}cAp_b)w)O^PY*il604dd#4)a<7O`6_U5Nwj^P^~-LnpZEWi(x$ z!|PYCqG>>#MEugwd}u6dvoAuLU{$?w7!lWB*MfNf%f7x=X<|E)bmP6atMg^S4+WqZ z>Andhs-y?o@G_Z%k*~IC;!{FYz1}58y2UW7s?&v)XV!2ESIQA|nw@R=Xr8VE8u}lk z?eNLs;OY$;aP^(MQ6W)8m)Iq$Dj3lJCg`uy%!We!Mv$-UO~m`hfhW~w5y}v9>;apC zKrxwUqNCeB%uK;s^+h0B@T}Xb@x?L(Z>n;elx)1F`;|7_n=1ZWjccY1P-r-D6}FA? zp-MYV|Vz;(ygnqD&4z=t1^ODaCK(z`mM@!uimP3G{(AitJ3LC90EoT?0HC~ zVkR_ZW|b;@yj=|9-7YtE62veKrhX5mz6Vnu>{UpSHg=L{B3PzFu}pO+mZ=WKGS#72 zraBbMREJ`jDoN9#4gYLscv@l!C+oUwcuLo0!=Jk@8&27E*$5&W$W~noHw&!breLt+ zMQmwBrUk6`{0xhL>CD#;G_cxq6wS_2N6b1pOkg^{H6$xZAZDu#i@;V8f z<0cs)Fch2VhP+_2E@*_lP*6q)Yn8-~|88$+9PH^I&1KjAXfC_wM|0WJKbq?YrZ#34 z>-eCQp(m z*hVjsD2kgrNTOiR#N#FK9oQcZXXEFTF4DU1#7JP=0}4DxV)m+%So7w9N~@&URKi1$ z&fNlqz`RqS(hP5JL8Q4x7@4G3npu_yxL?xB_R8)oo)BvD8L>@=4=TE~B1pgMCS9e> zciqzM`)pB+WTeis5l7cc#oh_7BFn|uXaMWOmgz){6gZ@q9HYH7e1Ro?cFfh4^QH@# zf2^>HS1r`#Hi!Gb-= z#$&qCJh*vl1a;0}VO&+M)2nl4Qy4C_-phWgBkypUeIN1@05$mF6}?!_OE@6EC7KUE z%PlhIKE!85AYEKTrq}9Kdekpml_S6Kb|wGu0S~t2RGcUmwJw(9pMDbK{imONBGuzo zvS7#lX6_5O@8N4%j8!vK+i5{sOVC3$Sx_TPT6Q%j#ptOk4@E(*l|{!BR;hW+-trax(-w z@ZXrg`D|FusC($WV~8a^cUU>;Q#ALM=+mv?P%;BcQ3 zbB3-()PO^N+y3z()eEY*79DsJ)mfNs_l5)WvS=ko>EBSB7TO;3E%LXsH|PXd&}>~gJqQ4X zCgA~_0M#u$qeq*Tw~Re4${Ti`7Nu>gQVRs80jWjtYCG=k_kU(9lu~>@$R|cyRAKJz zTNHQ904*?>76WtkY$_r4FIM+3j11ai&}Z5mCVh=#I_(Wh4=sXsgtOE(o@I;{^@gQ&C*#RWsC3|LM+~kR zuKA=RC;%tg_ezDLZJ+GTJM%%JXwL|Vpc5wy9Bo+vgE&M2hVnULl$8&iWW&YPo;fb2 zPFxBhYt620W*5b}?aVD3RR?C-h`RC0$JLru2Zm(L%I^FM;OoG&0Jd(Niy&;xK17to zz+_45gL^)@4$SkBb>m$aAF-~|${Z`-KHfhq9%21{yK#=0TzlX)+#lZTlPC`aUJh$O z^g51~ss%Jo+(g8>25fC3s-=t!@b#b+Y#JIKF}fa5s)B0)6$ha;)>C;v@|RVN?;a zyH(xNs-B>YvLmLBB-I!mEkm_2QVizH_;~*dG`PLf%S0VEk+$lf9#O??)9vUQ<$+V4 zR;Z#D;a1op*5OvT!j|GzsA5**R>)egHMvsal` zxNyUCkXnve>U){Fohj|u0VJGe=Aqu0vCvG(W40JtAX9`@i3kZ{8 zZ?k|#*UKy*u=O+x2xLEQ7Et%(roBmzypSgl_S4@AWnUd`;OnEu6}o=9Tw-HiEMs$i zhQ<$i(IHfqhimv78u8<#Sw3RYi`3}{QQ(;D^+OM0Q;Yxhs1H-H4&gKHZFsvVdttSK zw5K6%W9*@~41~Rm5RET93eo?4O~~tOx;+$rBpvmTMiuqh6;amxO+8dIk9FNrNBzKB z>6*4rSjTQwPHsZi?Ap*hzNgubS!6flOxTKH2BxkJOm}cYMP1NB)M(emv>koqQ$Sag z_B;=;4)|#9bsfq&qNCy7m4o7N-Scv2MVa)p>W_1V>sBwUGw}7nJBh9z=D7}7{c+L7 z+?ynZ5ck1X7jI7tw!OA`puBh1UVxJu%$( z2J4aEKJxz99md@Yw|&(8Fk8E|F^l^kRbwQ7GkC0u=qvr`tGEtCiwPcxfYH;B_u^wnK{x-$X8TO`p_?d*lY%UWi4c3+Aon zYS+%%HCj)Pxb-tKft9+7c}iG&X*JRGLphm~m4Z z@z>n=G&%-Mqd+x*m^tlQkEy8|SN%3Wj=HPd?g*m$B{zh$BcYhI{>ta_1*nd=$O=D4 zEQ9Hk9Nl=NcEkwk=te$*F-p5fkNA2Rn2Nk!teGT>^YU$Y|BjoX^uHbm+(wT`q^vQh zhb2S>Qg!Oc(-f0wK8K$$g@Nm<<5O^h<1dN3CsLWvnsZl@XYVV4Y)7kLH>q!kd_F9`3QTzagELv+|z|0XYzF61)8L!D$=CJ zY_A3Dg5oifD(qu@ut@+{(I!vDYlwP&HDX6uaOVOr0#{XC7jY5@t@wXerwd2Bw`+G? zxFdB}Q71uS)!B5z3_G-?7d=vCM8!k_aO^at5{u}ODr`8?b;l*fwqDz`L zG}{P3H2S2futuv_AfPD_#VqyWPjc5v-4|-X;0AqxEyX4gC{>lXXQV?=sO~A?j_SkUG@V5QOcJ7;7F8hYVp^nM!cecmklCC z(!$%eI~rC&4QN|MAK@UoG_jBRtM=>pRz*6uF0$#|pVfHn5Ra19QzsxL2_F*eRf8iY z_8XG2kE-2RcpP@KCLo^Tn6uPSvf{M@iN~eX5FdC>?H-ttINncW$_S4mFQ#BhM{=viR% z{)mRGJY6)6SsAHpgQ%4;43W?Rfq-E#48dFB82z2Wh8~M)4_QlxQps<6Jhw(}g#hqAO`d>&TudjBKvmZj-*!^aw;9dR_Pd ztC(Hwnk8^}roc@aq+)$_6JY}jSzp_=Mtb*lV~Ir4i6`1?xf@eVH0`y>%g^u2W>~z1u%BwUjSieCdP1f;H2*z z+mVqz!ft%@@pWcn1SN5?vP)P&Ghxlrm+DU!H|}Yf9TXG56gcyA;hd@YP>7wm9!f9g z)Na)|HFW9#n(L}J7Q{6%G|{465k&KJ!Q8KBmAp#V2v)I`4hz>2tfOfz@%G3HP91ar zn9z?Qd}tTqv$hkR2%ErD*X8seVHGxW9d&k)&E*>0fhe15Umpsysq&f_rRw9iMfBl- zoxMq{&5f|F3vaOzvfx!v2&&zs{+WHVGX}Js1id$8eW9vMWM+6pc^2*)gxWSgTn+h< zeo&I=9nH3_D`>Opj;xv?+v2J*#95|XBUFJt2m^Q41axdJ?5*f<`>L-=p-C{t=1uDt zTg-afRsh1L+_u=F2Gh0(Bi7Tl=)$Jdw%B5J)wcNJM%LCCn}vLAF3dXWV_%cKM%d3X zglG{BfZsG0}$7RvgI37aDgY!KVZwW6~>Ra{~8_L^Nu{IN1%M2_rB zZW~6AY~KHoBfz$dHPLmS*21TYZD}*Gbtg?(KzbeDB8Xvs8*Yop{$>mn22z>``(tLG zGlq;V+1J2Rto*Svh6*{jJ`7#+5pLt`O$t;n$37Ph6K6l#vu=EUOGiBJBw3#u8BA7@9eU=sjr9KzdmjggRlpT zwzpUJ*+RLotqEY+T$mcguxyUb2tL_EV=F(z9=c+)V3r#+xoJGhO;Pf+?fRUx-e@tE zdL`(ApD}l|wiHSSD&D;H)oRlz>qp?ENwx=8N-}--j<&pXeXDw9s*Ai=ISnH3iOnwV z9{FuMW%bK$8+X6l4&d&K**5APc^&ZG>X+ex3i{=Gtb)E+AHd%u|9z*ge%bHi@0a@# z{CzRsN8caswFet>yeEn^Qe$7+!=mP*?MN@t4*n$3|T zE>NQ&n$0oVkuUp@S1T}Q_ub3J(KMU4eba!N8(`irrsigtbwEXqEm|8|as$MTBWrGe zbF<)@n<3U*SQ}q+1H8cyn|&R$#DZb=viXT2cOq>nZ^?fcev^(5Z!q4$+F+X-Fd4Jh zrtvm=!QR7U6bg{p!=#yp@OCG+QS8kPSlc}OW^<$}#AT(N_R?+{)l=$>{h{p5OiP2H zaWu~6>|7U+v$wfyqoAD4>2DdAvzH3UINvTb=MS#l4`9{aqGd&v9NcsY(78dgHwp~8 zE|%p6^+qFU(vGM5wD2P$b@tJ^xG480OYP%zHgDlZAv-JG#<~tc$*n?I@upY@iC3qEv+K8OcbxGfbsLd83ny~t&UPenCuP*?$6S&w zv-puao0Zk^H=9N7a82Y+NmH}Poz%5f%&^v>cW*+Qu)lVwTVG>*ZbS>gTJ`vM6U1 zld?u}ZQI2Ey~v$Bkev&H+j#5A1Yzj25Tjb77d$)7s z&aM?!%T%+-oo(vt7P+%?jekcImA_bv$ellAWLo>1fRtnI3`Xwc5pJvTt>?~okOVmHh;K;i6Tjgy59kZcgSGctMtH-R^(U*Fhm zNj@GunJv9{9XBArxDD5igrNKF1_bDMo6RG4MtVYHY96^Wf=Ml5jUso(aLCA=h3AB_ z0ds6$?sgrdeOC~E%301fphRP78o4vV78_3&-e^oX4Rg$G!T6Nx3F;M*V}sj-B;n?) zqJ_2Vb?GYYngTZ`gP78#n{=SEE~H3r(v>NdlXw?mT<79$>~XPqX5>v| z$3@naVL^QDXS3Ay6z<448(BBL*|<8hEr6~A*8)zy9a$H^*o}Vygq@if!`Xq8zQ=Ay zM*0Z5@zKZEnT-*Y#Kp=kVMp#PjL4k@B6r%SWll`aLPYK?)b9QKQJ6VP!U8wFkDffkZYz7QPN! z)L*OLqyiFjTRz$zSfJ^Bp{h(|PUKD!4&NZumf~yE5DVKs(0 z%am(G!{ErBk~?A;8k?rJZE8h_+gE)}3Sqlp+otu4EoQxKP2DK;x=~wfQG;n)gc0j$ zTXbPlYFlhEyJ}l}aU*MMj141qHeNGypv}G}dyTN4We8zGnndnw+}_P1cQ!`bEOKXa zbd4f+Hb$qc?A@0ag{g-XLL2Y9Q`IA?Mv*%kGhRgQ>`5b|$esP6`mw603O1>)y>{

rR@ofb=@P8%FMI+_@H!{mmFUa;G?b=#QCw&KN3kXHNr9vGT{x7%E<4gUFrD zg+Rr_WKr!+3KZ5p7Y-9=KiacqXn#vbP2^5^PxhstD8kvj*05DjmV30X+ex3i{=Gtb)E+AHd%u|9z*ge%bHi@0a@#{CzRsN8caswFet>yeEn^ zQe$7+gA(JS?MyuA>W?-pQ?JND5k*FNce# za=uiAc{eqG0QMdxqfms+9v1n{B6l_x=Vp;R8>34%h}_v2sS&wT-lpr`O%_g4ZTdsm zo0*mdLG#F+joG<2a%W$2*=CVD8`Ix5a%UeEka50c*Au^U!Qh}+}XH=8%ORWjmFVuf_IV} zn1IeBuS@7)oHBB!3YZCnMMUmY2_#Som~Sef4|czBRCMX@Yii{<+O(HYGm&Cp$)k7DQyX2;1%cdjq8Wid+yha!|2 zsJ8be`oz6Hh`c1+Y4A+hrkAK z5F9N_>WWY0WQ=%sCK-VYi}r9y2mS7H4z10>Y%mlJbO0O#2Mdz=;-RR)5rT2iAl%DT z^tEav2~XlBTTSHny2p!AQFw*SRI3cRflhy0J{)>Qj6}1<_7)RCa&`EzSbD`SoE)=k zx(E4S30B2ef}BLN#P*Jp2@}`LBpXpQ&LL(j3!BO_5u`w1v}7PFG?FanL!fjTP>mF- z&&jk3Q&pqIu4>!W`LekBhC)W71%I$C&t}W~ah^@8GIHvMupW)Gz<)%?Q`@miXK|d zPs$ZXTXK^E#Zu8~Rl@iR0Pj`pRRx@sK%pJgURA{U4iwncja4P=gg}wQVm8jdUp}1B zy+*+U$o&Wb^W5Y>;T;L}g~h=vCsJyP+!l|sY+@D>DS;xXtmSr6F0BIi4uE6l!=w+i z(3yp*)IiZaS@cQ@o>@?(1&YBDR4_{kpIPoiB?bznhL}Nt;UN~|+`bSnfQcUgbX%23 z0j&BEh^gg%p+hB8D4~7|_;`blv{a#x{w+$?HFtZ3YjO%LrVaCxD060w(NjKphFs1t z?A|b-Mz3E0bM=ZIr1_bq^$)LQG5+x1#v1X{PgR{i{q*0-O^)fM7%lVh z$FiKPqvBE$;m|NH7NaoBk}Au`y;Egg&ZuWBZW~3B>z6*1Rnqjc`1t-cn*xQxK*8Ec zK8;Kd!(oQF)UVmnD27eRYod~y6reo}7jlP52zd|?JG0qq`J9UZP_+PqiuV({Re!Pk zZf{?I&Jkd{7~SL;2{Vj9EaJ0ey06kz%I(20_8*p!s?Owi1zlb63*wuc7ISdUNcf1& z$a67!yk6z2d~9U=HY@&IVIRY+rlQqP9#}3##L;t~P{SKBlsluI#Wpn9Y_F4Q__+b= z_J#-*<&Y*2%GidVxWLraw{@{O! zQ8Ivd4>*^_Xov+e!!Bh)G0t~S=tpow9BMc{oa+muSm-NpKEr;`7)D=@u9sJH9_Q)a zHO&WN#{P(1>mb-cm;zjU$rQ21ACl|iWjQTIya~wJ5|ZxPX=jBD3yjIy&iT2RA<#{g z29&fjO^Do2GvZnep*yG@L!cfg-5=9rUcR3_Tx5&o4Ht2f*5Ig|Ho%4Y>UOy+br;dh z`5%YBYcS|#O~?mkK)I1g?u+Fj!SNmJD*1Bsl>E5@_jb0E*IXwd_o|!}qjyS_zn&i6 zlDCH^?4Rfnf?H?|e>~;0UyJcLXAaYvO{oHW7rW&}y0x5Vv&Bn^aQ)zL^+B{-;M@Cu zE{Ck+3?It*@cQ%d>F2@SaGH(gB}&FKJxu8#fZZ{n8A-KPtT4ujUkIi--J0Z6@jV|W zUl37y3Wf4Z_MQJ;L2~l>yviA{Sq`&#a`p(-2pOmOLk6oH&)6SV%VjzHSbk4VNXz3N z<@CO!AD`x!h?CFra`i%=7kK7jFfNwKO*Sq{Q82lEDY*1qcK=5)#wl!a2em?Gf}?g1 zr2FW_;xBqLVj}tkjC7NTeNM4mbU7vzqmZ2tC_*Yd#>Rx#&{t9q)R*5qN7z08>Jo-2 zXkXHp1oC|>2Y~wBrqjV;=lU3SfdMP3B9tG{NX-Ny#P|+0`$$+}(cNNI$0ALhNP*O( zYH@NoFQ8Fi&c>2X+z;O8;JGt3KnDXmq6$sRFwe5)J|9ks#qumrri#3@K}9lzl8gW6 z>*Y^B85H5Yqkn(hzy37I9v7jyv#;1Ftp(x0X7yNT`%{mnycx*NO${ajT8k;aY=DV? z1g7(v`bMwcAPm&QH9+ND)wd36eT8}11Q$WA$Cb@Q=haaK81B6_Fb!%O(Hy^qQ#u}a z4L1*$SffcGRTFDqX$DcCe6~^pyA7L#y#(?1$)~!`9B_e*! z=|JdHImev7d>Y*I1Zbr(Yn*~l*}^G^$=yw(f=)S9$n~H;QC?JNr$s8XfoL_!7IvCn zF#l5+p{aK*Qn0?M0~I@C^m=&xyYTBo6?(I+(vsCES&WiD>2NHOy5}v9udvp_yKQZ|+KkPe3U=lS@m zgvun8)N^R5R^nND=$G7vZe*4`#iLF@a0ZQkFc{Mgj2YA!)r*Rn-<>Kw;JTwC@)HoA8ZiG$N=OoAMiBXfA_>!YZu+Qmv*4L_15LqnRNHQ+M~E$ zFgc^Mpz7l%aj-ku-DUPnVora0!nkD< zNNSVv4W{+iWL8oOll%8&Ue3puZ9W!{gV`7k@7NwJmy=w6Ks`_XX?nM zFtZ_>e`C6vuU?ik+LAx!#WMet6%$OCU$I+%!QPGFFK3f?k;%U(i9wTN9AE>_-F!70 z!J3!+HoIRvVADh8^EU<_e24Z4C73@5SiqJ6`obB>Enp|P224)N)xG&GHYpX=+j}7UQ@9c|V|zQ2M;oVbmfwmaT2(J; zRR!Jpx6hev;QXjTQTtK#MfK?~zlsB_%aSo}3)3wWg@KB*3&JBmJObv6!A+(&LBITx z{E3anVGv9ja>JPmE|~5IOD=^8IFeg%QP_vwRuFAGBUv&>so#UJ@4?hlwt{&mcuVf3 z9{$NP7NPVZSiv}$dNuNrCyPNAN_+|>s?B^QwkR%iWpe}~k&R$hOOWXE4T(P6kmz#_ zi24imQ>$9@HS^^+~hfEruYTY#dGnZ;4%EFFCUgB*ZJ~}jxp%yn&&w; z$uC7GJ=4M|=B4@Nj$lNe+-IX_yTU-KUv@vc$CWI*pqu2C5}O|77g7nc=vq3O)}6%% z)yXx^b&lur>^-4%CQq*K3Y=T;Z}IB_n}ORGEDG5K2Q6@zTl}nyFsw4~T@%DvW#bVf z2z@M+c_}p+FHgk*LQ&T|XIBZ=Kc`M%m6AH3mn%$Dv0TFr@0EmpfK%8ftSJ~PUT(TA zvW2-y0Qt0~TgBp((eR;J5K)RHgRo>+NX4)Z;32PcHi!LDz^({mTdYL~#bPjhfuDDn zY%7Ge*C-0{EZoq&EX1VdoaPybSSEsshs&vWyJ(B>*YPkL5Tdmn!~q^;q%AEmB!)zW zQpD3dF%TVEtp?_Bp40t~W62+n5{xm<$5DN}A_+t;JaM3XvZ}=Eq1;c!92S9a2Okmu z*+L`vyF})o2=|E?g(A}zLhYBx#7E>LO(&@Q3`P(5WQt}+AjvI>PM@*hsIKwr+#9h! ztA_9xZT%6R8x(`^Pgc?_|5v5T0t?5>5>hTFA}7*(t&_zib!7qgu3 z`dbezB&;bk9-9J#8$+}7HidrN2=}9bdoA-`ULrE?@(zGud3OP)(}oxU*bF1W$#Vy< zZOrtnsU*N@r=iSDiwz*7{cpdW;x}ZAhsnqMv7mipXo)l4@$rh+<(Us=dj)CwV7q9f z(wet%Sc9n4il2T`Lp-e1m`~AoWNcE6J)dx8{!p&1&3P%tqsDyr#mj`30T$#Xyd%=# zp=xq9`Fij=46O+s?BF0|RG{RX&a&dS-+CU#r|F?u`~0%0kVRvC^kMc43?BMjTD*in z`6X*JkGOMd7GByl(b{Ve=T)C>3786vPX+7^w2Q%EtxyDo-s8g^LN8hiv@Gj6Z zOZg%R3uAU3O7O9pPq%yMu{5B)F+Co$yv~gjjcB~s;K%tWGGmqE4%zSUXodwIUc};8 zHBCmu0C#Ws0Q4GvY+#S5c^((={BZaJ>g(ar1a^1;1J14jBe^=^wrh?KLFDJ&*lnr zL%11vSblN)urJzbvBd~;bi3pUrb(Qs|Aq_jk24%}vxBt0nY4ZVC3~T5AUU}o&T!+O zJ}~>KpCr6#6p9u`J2%~iN#eCAR||>A{PdA|;66rZOB0@u`ET+OmtmiMM28DlrRW}bo>ME1XX6_M=hYkn@{y&m z48gy8^u=HfeMFddwB_cjqOpxq=1wQvnmZ1Hgw9DNrb&ey%NaG$$`h zIl%PqwZ+Wwts4=cD>N{<(GhqDcO7U5wP0ujw~XRn@f^ww)+AnTYAf26cUo>&_be)O z(#`i?WCC%l7QxnpVrG2Aq^?Y?Rl@qhD~gw47OoQ37TzD1rxvZ4*OrJTHXA>uk9q#aUFf5szrFzQn?nI@sYEW+C4O*RweLtO3k$-r|ZaKans z47CoQnkXw$SPS&A@+oZ{6Zgd=i`h;5SXVQ&bsnK8pr+W6z<6h5*0a+uSuqck!q(+K zgp_F5r5^!KYH_WHxs=A87#ek)2f3eSFFq~KK5LRMaIy&ZYK+3!jvS-p*@t*BOx6Kq6qkPl z8N-(bP9meQ-hrez5QxE>=Z-NLJZj8`Q`&kF0~G$p8Z6rM&;Gtoo>x++8$`!0Ar|K;51wSNGX0NGQdRTBHhi zJqx5&cs(E%2^@cd37|mztfk?AjJg6|{vz;Lf0_2-C=X1a7$VbL+yEv9VlKl`dbBy8 z#h492>tUrBH-y&5pD{u;4f^CnIg6bAnE3a;W zMq=w0Y9hUEnRP-OfUoU*7k-^c2jJ^v#x1Z`z}*7tiR6|)Qiec3+B+9e*u5iM4;1g^ga;v~iq;DcMhCTJI zbG5t-g2$0p#<~Xk7i>*jV_yyB$`OTieZAp`k)oi3b8#~iDIzeE>&q94sVtf!sx^{p zS#6c?K*%08Z3v@=%CTMM-}S~wP!Y9NbO*g`wr-&`=@lpY@?ama5b;fi3c?wvBI59^m`o7L=ncDV_0vXtgvb%M zPqhJk4ZIZxPeh#z(?Id9}ugkO`e0k=l_OxUH4c=OMVmWBZOZNpT@GF4k` z2bt5dQc~Mnb!`FVgRtx|K&WmE4%n6{ zIHMsua8kfNh}L<|tHqF}@R4|&T|RIbTurRLU@#_WtSzpaP)8+zl+8HW62oW=RB)uA zssk;yY_U-&%NQGlGOe*uAln=pC+rXpU}Yl;vM*h6A`NhFM#R7th#8sxMeYc7thLR+ z(MI@o;5cZ&5F7`NSc0PkOjB?a$g>4UAzfo|6fk5BjsjQaVB&qe%PTlB@N0ohyKy~Q z6H;g@brN7%kE2a$2IUx;Yulqt%ME~ZBjT)7rea}_j5b4oHQ~2+c_cE@tWA5gW^Ld! zELrP;EgRN)aBaO>5321}>p?Ax)p~H#R<#~lS*aR9vi)d1q_Rvkf)qBX^`P1swH{R2 zq1Hnx3)Ff@ZF^b|y2j)hMc|sdnnTVlQVx+R)Pv0JKtuB65wjaX@TKl&P+Ep{|Usb-G3?OQrI3VjCr`!GTSVV_}W9$2GCmwy71hY;Dlq zS@kprEE6@d6gHsNw;*6Hjq@gCFRks(fbmEgZPs=Z>@{m)gvlsQZ;R?}j@J=kLoz8* zN}`71CMDcCPMnLzOA58Leplz(n4{Pl1A12GI>AszSJtw%@*X83YGAFa!!m}}4g&ig zRYZw*4P5p7H5{BPV^{sA%<)dd16j31JKzi*XQ1f|E{sUb^(#c4qV}@+NO@G&G1d0Q z+_Z37Icsi*>`6v8H9p>)o$=}gG3S+cyKkC;ozeoS=Vi=JtG8rphFq-th9ehZE-nqSoTLuV5F}BsM!HZ{jQvZ!Ew}Y(@OU(m`pSy-6lAZeb0Qkb7?&XIO2S8Q~Mh z8&*amN}|gl9NQQ6SM^hLALViocTtA3MJQn-Ux)e!PW@Z<7a?$724K0M^t}ZxMo_E? z4rac0yg($G#pRipOjs=LLHD(7IX zdtLsj@}Qz~t-4>Jf;$Nph!a)HmyrJZ|E-FSe>XDzFJ~Y?IPvV0Ew?h!5!@=(lw6r= ziLOGbTLEHaS|z+ZY-Fk-v{tf~PdQ8^xG$nIL(0i`9O?Rsj%E@i(JBF{!>c(d#cz!; z>6We&*BvIlr43z{p$8uRN6cRTBWh+SO8%Ef{ud>yD$>1aHhapJc%kPapFQHD zJf3*8Qw%KIbE2RWn#8$QG(^!D8-LGwENVt5uTV6{@Qe96ScA z6pXzcaR}wEAav;^OdEHeV~z(XQjU1$nm}Pf z|4XS5t1YDwSst7bw_&ChVFD&E5)T7+tRzs*h62{YvOmHpG{?~tKdO2uj^|ZsVCHWp zf7{7t7D&1Yo+9m2bOK2oIYH>;3KfNoR!)D-z)0`Tb& z0-VYi5#+%lJ}jVZ@sgwlGe1qhBYt>c0c?v1>6|IAjH15U!K5oa_6%RY}< zTK0LwUf)m;62u<=v`3mqb2LVsXex{%ahI+KL#8Wyc(htZ0FxE$@m*jGX8*p#J6$rY zmjp|wbTlacmrD;JXR>)E+ENT!GS>Q&7QG^@;fG7a3QVrl8 zjo+t6pr>>yAUgtUxFDQFhJP8EX?o9`5p^T5bM<9F;Ub@;j&W%I>aG^Wm>`A2p~4zv zqCXGm9vYXyW5x1k)zAYi92L@9z~k*g_^GPOkjf*Z2D_^42%sl>_zRGnm` z8o+xMK2fb*Kp=OC*p|3LCD1SzoMT1`OaYpz41+9g=7~@yY>Gr;1!^chLKP8=GLozE zmFQR#t5#uX!m)B{imHbU^-$UuOd$_A@vEXyWm)J1oiu4uwJ0W(6=%{r!1FMie^rqA zj{i$!T2%o}1Sch420@5viAQ`Ah?M0cl#(zGt_oDpw4aT?tq=x@QHkFMoSg~W};VV zQ30My(yq!9sId?k5 zJV|e}Qs4~yz30i4tJMYV#j~TmR_A^t-d2i0kSv+DoQ-#nM>wta6;_=vWdIsiu-8QviLba+T zft0Q#Kec=?Zxtd;5wz@@X_ai4sfJ{j$%ctTq7?cR!zjuOrG%y;MW3UM7+IzYVkDAPjv(Y>s5N80q%DOG}P;H(3~4 z^uCG*rlYEuwK}B@Wkm^*)K)BFDm}%-B}-^c#n|47`9Z5F<4Q%T1kcb-+>)kB5-h7U z5w~EagSa`S?jZ@cln>Q>Q~QurxmA(IT1Xa3H6}V5UWM@67GTbGh$}zNsD$!6Eszg9K)d9>+@nEzJ;kq>Zf^X~Nbh0~9waB5aW;f){=H zjTA!=iOIQTWz|ipP!HgoH>*NN=xo+W@)gxh8iCt5B^ZeKWc0T=yL@je zpZP!Aa{znb9murp{Xdt((NjKp9zK-w;q~X^)6avu;WQh~EIgV0A~f4_unu*iffI~X_LwKf_s>t+U-a1OCC-D& zU8eFwIT`lo3z$p!V4d66`o4v~tzkryEf6C@15&5b3#-GKE%Y8yTR}}mM z@#FIO?9&_%`2qNImctDTfABAVw#xAKw)zd%o!RPnSu9se`t?#|&&e5DM%DZi7vWGiPtL)%X#obEXMbhS zPsw>Pd(Y-?s3ODf`QuaZS8|Rgyiw)`?k@%2^j^La2Am)~f=l?jd|H7@Bz?(7IcO3; z@g!}wct_d<&sX7JJY1IJZ;7g~v}VgE{=0aBJW$TpY&BnLdH9;YfKD7P&EN2BMK=3b zK2Pxi`Q-?g_fQcY+@)gXbKRGx57WIPuTQHd@ynV~Z{5PAA5g8CQ+-2X2XZ(wo0+PGp5pnh2 zv*ZpUOL+_Wo7}DD&$x38pr>Lo_f5bMC6ycN!1eoa1Lub6(Eyr-0h(7hFl#pisE zP6cY};n}|+xi2|nD7h%#R2FsH*KvN2u$R;_qYw30HZ8!}dHGyom@QyHyvrb3$*0vM zqe1YzdS5{dDC zLPw)BCgme{(U)wILDovh%*E=xz_hqnC3pFP1RG*|UcS$>lcxeQlia)!Oqt*l&}8YK zY+`!D zpI3~|^rzq%ABv+E4Az^CL82kek<kU`Ef2n?oeYQjG; zI6jrL_X0wP4xsLN0LRcBPph}=OP=E}GWmjujz$KE!lR+d*A?QE-vR=o9?2`P9wcMr zKS3@b1PjRQpHwp?TDD7&V(R`|>^V{q`qZI_~qxA=}iUD!^K6%0{3kDXa zG&^L)SIpSQ&t(Z@7ho57b&K8~W6~5Nn$0R1MJ$XJ1wrsvlw1n28FwDMQ*I{yocE8rodn47rW33@&*-u8 z8A?dCTI2f)+6pWm?}djZ7?XoSE&P|KfI=wIk&?>PeF%lC-m_O*x3PCsM2i9*q zR663Hs4N5I$83JT!gPL&!8OCv&GZZWBc#0S9^>Q>vo3wpFZ!$1SO^1k?1KK%Dv!U= zGx0zIM4Rwt;}Us7Q>DL;#R{_=G)SD!Va=feSRJW$!COq(lLAbW%Q>jSRQy-|SiTWm zI2aZx4ZL<<@pua~WJEOjIL9(D!5<8Igm=Jnkj*Yf5c9iyjd(Qi_TCLQ`2 z2tQ?5bMTw{OZ6i<9lWIJ4!xg&vXks3#|z9DBPSWu_?f5{!XZ{8()uCqH~9-5uEwl` zX>5#t3aqLmz9|2Md1nbGNqSGpQ7L}|30B1^1{;20c>=R|u7*+zMH8cpzo>zKL6k^o zz{%{hCIBx4WH;2AXRm1GNeQ{ZI>z#poRG$J^8Nxb725$#;AuX?X5=|J#WDoNqrfaY z#aatA>POWWnws%)YdKE_qZK+6e`%&q29w)t@+uM#EC@`-i>{wn7_Cqoz;x)}YJY)Q z{HZ80Cb7?$JX4P;`gz}>Kd||L;>24C=vzEMK4T$6n5B1o(^drdNuL!T(52roG6^kb zD%DqYdXX=nrre_&KVyIb>~mgXnWn#_j=d+JF_!RE+(WiWtED9igOdITBJhj*AG;dd zQYlw2$XsFK$3M#)>M{y*gRxUvWGj4Ny2eaNDn#;Yjzs{{`(<>`6Gik%ZC zeoQss;{`M{+E!c?_dMm`FZKWz1=Oi!j_7YWMzh{rVNFsB5Y~nf_=A7NW(&W@SPHPP z&+&7TVcw%Z@6?z0F@^%apdXx!H5I!r-gPM+;v2J6L7V0;*o4sri%Zha0@D5kZ|5xG z;rb>2UW}j@6fgh?Nuenj8y{M`GRh&fh~_o?SV9-VCJ#SZx5VGSNNlJQXt4ze5byZZ zT+ACjtV5)#lT2ffpmLmlB0#+;=pjqrxv5~#PNW{WL{Je%bH&1SIcqc$8iJC+LU99MV)w&qr34N3>~yJaQp^bq-AMzGG-6D+axX72 zBaJ%p1T#&watYl@;r$JU0Cc?A>*shK2^!p(dTIb;4d%;*Ov1|cI4-C1>z3a4QCZ^S z3%Y)Oxmr%%0jU`B+Z^^12rSzU1W~_ZOO|14_B*CEEWalRlEerSY|-<-z-#Phg^fXJ z2EW5PRA?Rx3PqiE4sFQ_YVW7ja#f8!X$Qj=6~ia_S5Br5(h%nFipqbBh34Pb5oY%= z5uDJtqH!ZD<#~prmJAJSxe-DFMG4c$B%i*EZ!y8q^jplNUWe@&MhiA~3e_?7u&Vg9 zfQIxLnjJduB!`X);=e%2B9#v?`Q^hG$jU#-0~%dR+DJA#%}!Rh(IN!>78)2-F-(gE z4HyjGFBynJ3(w0%`3hU%YL2slYzD4DhE?~lmW4Y1DCd*0gh@`}mNG(@7bB%{Tt2WG z6U-3{kl9qwjv3(ubHM#QYQ!W}zF=^>$ZmxC{VAty0d4?dkkG)Gk<2MrCHxR)((}R5 z1svX_GCh009nA~qGCZG*{!}Pj(ek$bWZ83eB6c0r{{uTQj zf$VOMeKC=fO{zq0o&->fjxGQMv+VInW=qvuUTCHl}LTDnN@y3W01di zF~^!WRo~EyrkO%DaZ*1^7*7=Gq_Y>L5;e%Ooin$ zR5gtflK8k%6yakvD^+KmO)*13cgG+gMN*ki=MnmY zc7gH(li!%k9_lm4+Embjt9tp1v>0gsVL*aLw}3J#Q@=hdokt+fl{$Zh&0c*hXuG1?fAy3-F0QJt5}RnF-O$@` zDm1=AaXJu?C~op^kO1|8m0o4QKm_@$Mg{aMNYxXz`w|$YR7_~b7a25E9*km8onA0S z$rP+8d4a<>#f)3FOI9NW7PN9%e9d6=lO^sjeZeeTePOHdrm7<*D<0!FE$12#<~sQs zng=QVs!15Jv{9Csu;8KwElMZZY6KH0#;Gu$sHS`*lh*H@OHmHnDQ;uNX?~pJ!+E>TW9Kns>LJuXXvT=sjMon3Pxb^+0Jt|!N{;lHP^kwap#{+?z0`+L6>fP62asLb zpg2X2?nf`X2iOZ!hW>5Ul^&vtF=1lzW|}0hpJv@UNmJli4~8b;WFxDg2TeLH zVPmBGypdKLd`Y(?V{YF}xs)ZkYQl*zLiFwHmkeh6{G zV)GVdTOE|-S{;aDS{;nVvsyrlWp$96V|73k!`46vHVrt&fu1-}TBh?w^gz0}a$<~9 z2`^j*{dB$?5x^rtCHe52{s!NV)BhLtthRE;7)Si_qD9x=v-z@mDK;cF;p z23rx)3|`QI81CuTCunimlCC-ra7H7EdaBwcy~?x5!stRb#tKz=b|G?E%&ALb1?_yRFvk2TN*hzRN2`EvOHqCG zr3k_*MRNyLw!Wx>vWokp%3Ixf7y`n zHmV`bPa85tq#bO`aLAfXfYSJ~;Bfy1I}BEY3QtOOo>e40BHP9od#PCt3sbao0LsF1 zFwWj170Vn8JUyroo<>W0Fg6av8^rUAD1Q0y2P{-zjGaJcQ&bKkUcR8ef8=8r88`(l zJp2RxS@eAigD?)j@Pjs<&Jy$n+(@KnCe=?0@3C0^e7*eXr&CqE2r#J@mi=schqpLT zM*OfS-+xh=;)j))9!&FWvBC?a=Eg`4Bq_GOaiaHtD`Mhu_61JORu$~=3jPyLnuQzM1iPykbCa9TzAdqQ z1j<|CXk<2ezkP=T#f0YW?JbyGj5ImVCN?CUv@y`xqCBA(ZR%Sf(x0cr;swWwB+fcb zfC#)6xhdu}jR!pfjsCl#54f4@%Dx+A%>^z{&7wKzvN>qc92CJJ)plZCv&OAJZH+9z zf`{g44Nyj_25Nfnz#0oqov^57d=vb8v48yuhS9|t&7!+1T}l-mf^kbE3Iz5b#6Q~F z(h0X`*YGV`lCgij(5YwnNQ#mwXqf++#|-3Pj>yq>@vd+y9;pse~g1C=i+Hvq=H ze;vC<%1oSI0v1;y8eq;ZH^5B50yC~wt)*l1`VDhBNl*h|=uAreY6#t&ki6UkH$gYY zjcbx(0%<@sV8zC;8SDmBjN~1XCY)xyvth3s;{1C_9j#c>fO5LQsEV-Ft3jFV9e2>m zC$I)r^xpXGE@GXryv4_|J+|$Qe44Jv1%l0f{FHe0WvwY@;3qY{X0*RS_zG}LC8hhy zn0coR3YfwVRSg4e>r~lRVe#VP{9R>|YH=Vpsj#C;toAi@^AAR?-k8x&csatbNU zR^YJjNo@%Zz(EePv}UPQi)4}wV&nYjC&^I@c}llv@kSjy#4d5BiAO;PS~#%=Z<|>I z@YDf@ivV-c1Y5x2saWE{IAiw*_anNhh1_ZW2Ftipa+5{eDY|wEHyagMz#WwF<=Y30 zEZ#n#oSU`us6pe(P~F1qV69uW9niW(I{+G8%^cXe1=|6wU9JPLO-ZO-svW$w3$+7V zvrPMtu|?X4j4#m+Y|R4gK-MhJ4rGJH*(uRrX?9AqSeU&Lstt4L&di#7VYV{Ad5+Qp zDgAR*E^}#ruXbQq2yoXPS?pDHyTm=QL1KU=w`^&ek2MS~Az-$|DPCSB>0gYXwqo;K zCRjPmteWa0JU@w=q#+QOHLzF0qN@$u^qmA?lI!2*ljIr>?U>}T(|^s8vMR>O^*?ca z@prg~A%T91d%xoMG2BVt#n01nv?5bZa!qmJCvectzvC%fx*K#jNr z&dQCMb}957on)WxR>?~;zzY>$Cmycg_rsR?SAG&!$0MyEsF*xRRX@24Gz17i52XBu^)6~zHD$K>1N{@apOo;+cbr*pap z3^;sT>!w>LX7f2!v=;Q zb`59{wgsMuBAE{e+-l8(2`3LlBrR6;=~D_xx?BT}a|ukVHi&iLoh}Hffud zDTgV;5u+d~T0%v%3vsbzIK?C^drN{7mP0w*go^16x4iM@JNKS*-+TAIH}iS`stJXp;q)s#FFMIir;V*fGa}O2Pov|Gl^P+v}qlO zB1#J&a?>D7I3)t3f9UYkgq*HgttR=G`qg#JsT~Z%0xA(5#9~M9^mx%nA|hDs!_xU; zXOa4#%ITUHeJ1eYmRw8}jk3*0=x?E zWl&O;$`e5|lfAFlC)oH!iH)RY;ndUgSPCVvu;9?bOXoeh{;#riIC3nTRZf8w{Xd4M z?#*l!OEwgvTBSp@Xo{3|oRw$8u--S70xB1G#sHBbC%_q8Q^QFw;(;3+WsKs@EeG_$ zVO@1w7zK9NXbm<+s}~(0mMvoDDiYhSnlLfrXV zlA_d1`kp~lbg_i*yugu4mSc4zl`eB>LsEF;h@>RBu#w8mS=GqGN-k++VcF{$sdy=i z8JT!`!f$F^DqhMmMkb!UfRKuqvVf6_m$rJ5iI^+qv~`PAj%kY)sfg~1MHZU1T#<$5 ztW~5Ux(gMlXznUSDq8juMJjss`a~-F5Q`IOZA@C5+AD}6NY%M3Ug*Ah8{-?hYk#V#=9-zF`eteYKW;%pW^nuNa6+RZiL`aL~1`@0R$vAvG6>B6d&yUS1sVG96 z3N-*)Wchtq2Lh!NI+T$cV5C?1J*h$%sL5-Bf2#Ew3<(m zRG&luocO1WJEEH)J%LLHl`F;R3;D=Usk2O22_Q^6~zF?q&&kIi+g z#umqpFM)fthRg1vJ`85mQ@Vj3?%DTYKB7&wUbKhnHVmF-aipZ>i(6OSf?9lu(luf_ z`4lx|#7-t~T*Qfy7}O|*u~1o|5G<3R7>)@`rf9p!(vws)Npe+DG9jaq5El_T%K(kE z29hCbHopu>$D{GF!yC`}#D>pKu=hv@3$_odO@RgVdv>kW>JEC|+(}%6SGOef3I-u! z*N_8vuZ?i@va3SJD!<2z85)&$f)t$nYIj1mh^A@9KN_U#Fqlfj4qc_Wxk~I{_KR@H z#unlx8#!bbXl|y46_&Xf*rUS-*^z=#Ll4iLEYr%%9QIWdG4=@iM0PsdT0nn=lgfk* zlNfV!B79c80;~Oek`os0ac~%$f>?HG_Zyf|V6RYtN}DBbPCs5)oD$!N@s;4i@lt4A zWnDu=It6oBI2aEjraBkZ7fkq&j@ChVf*Z>! zG@b?`n{ibS2Jv8)QIXB#CWXFg_i0fT1^Ag3jMB7p zv7PPcQiRQ(X1#(Jc#%u!aoaecoA@dwzD5#XrNq~0;%hANH7;M%9bAOgk-_$xcu!0< ztIP6nD*i!!m|pASZoa0XEuCr)nN}zJm;#;0Ck&-oP&6&ruyMdt&(?aO(5igU+v#Vq ze*l9glqD1o4kY(ia9Szum(P>1+1FVm1QmJ)gqp|0U9`T=23K<>JNqAn-3Io~oWSk^ z`)T-syoh}vlVV>gb7J2re`4RqTP^-Nfzy2#B?Kl^29Lx)rujpyLSpq2_p$2?LQ7l1 zh4iq^-;d%+X7p3dK7XHB>u<3a3Lkgf4duyJr?2d^2&*X=1~}R23Oapa(KTdh`b2(- zkjik3)(2WWFq+O>^Fay&78B4s(Sw+6jEOo9MF-G}JhR9Qpfe1}V`!viZOb3WRl6pP zg2R5q0v6eECJ^)vObslOgrhY0rTP?+Sr8&h&=lzeBTCbXPdy>&fE{X|-pD}BNJOe= zEubrGv4E7pgchayQC!oXR;8;mDk&koF*KisyF{l5(?T3M^~*Z+@(q_nA_i=VDHTNZ zBvk{CY`^@qO9qu}U<)QLtNFiqwvvC*M|ejG}n*?>h+;)Eec zr?m#9ufC$<4$f3zS6j2fTW`vvpJvqlN8%jm#zc!$kwTMlkFkg&(>WTN_ju5nu>RpK ztiX=3hc*XWxY&H?u64adI&MKfi%o2N;T}()jB`+rf)VLOdV6kRZRyb_%p`7j&S^;y$qk=%m`@0K-{Lr z@5czJnxT_`#ksD-42r1kMuD*vs#zNkgT>gW0gLW?k(V>=E)4K%iOwM}aknn)>x6s; zBMS6LeGZ+%vjJy2gX6VY*u|~jnliqqlkhMdvx0H*R$rAGOi^LZ*4t8%YOP5vUX@r( z5SC8YvKU-x?^p_9OOo>&H3aP`7NpAzJuI0M?pJ!9%`H7F!UTQ_M$9N%IvY;Rk*G0V z90!fJf&eyBgBnJaK~SYuqt1e%e}So>x;F!>el%mIDHZfb&qKXZm(OPEFpS)eeNNY5 zrg{3&lR@R&qviSF%(f;Y>$^3=r0XzFeFIPPdI$($yU|wLk4u*9IMWGXrPHvByt0S>+3ZJ6MOR$>$fk zcm{#g>cU_w2-@|Feu-lA3sICMLeX;#yv3di^&A%bb6}34DI(v?=V*DO2#Y+BOQ&L{ zMj*e2ozVa~ygBI4)XJomC&{>ajrMg3fb-@%%Y(O-a2X+&K>C@d{HPzO+z^KNkH_;R zScegd^vt2W;M`MKIdTRu@Ur<1r4K~4y1oNi{5aqasPuN##V|0n8QpUdkVAahf1nrc z0;;QYk_AjGNFFX&gh6Lii?Pww#Rli$H7-O@;rd_(*F6WGgPWWn%~c;Kg8*7Q#39%+ z&JKy6V!;)LZJYL(RuITM?a4zksv4>uQ|-jRw!Zsjf*3k{Jmx^W9psU5OskT7LXK|? zgFUe}F%0_T8ZOc38_0T_Vuuo$TpKA4gAYpztkn%w5|Agm{86EavciJoVlyU0u{^Rt zxftP9Y~5AGbI*Yd$tsqyhLynbutGDd@kz0vl`|9OiN^QQggc!7|lm~1d^K#?DwjH2oY*FaY!yUBN*wZ^&~jVB=(()MFGQ` zsJn!#0GSyCjna9-i!! z=E+1`*_ppza$CpFR5})^c{}6#I8tfV`5Z)ktVZYSyC&ildgmBQQipd&oiuedpCqH< zYImS?&Cb025$xY4lw9IFPYv`Z3`tzkxxie^B6+xo4Ilc>#bR8MScUGuaA{({EN0@~pBEe-l<_t~P{G3>bOIghy)UR2qxfjT4kP9X!PV;&Bam%p z4P=PSBf@!O5$mhD@#(_O&MOs0pl%n(REEG`B|}uh;Sa^11~GWALtDP0sG_f7q9ryk z2Nz>wzKG3Ey*wWV-#MK=#)*1qNv(vSwGBH&iIaQHPCvlp6Z@lh$*WH`$55N;S+Uys zKnFlilcgW5KJ;NQg3=N@J^?!wt5|*w)&4$hkT0uSr^?pC%wt#wX|~HF4+aIuSfVZO znICU9X=$rOc0|gbhk-9#f5n0EepgK5!1^h-GCrH9i zuQfmY#NgAkvV6E!J2K)Qnecz`&;fJ4D)KYqDpx1h_Y8ZHU^9ZF#2GyZoV0I6iPk5(E zUB$pNUwDI;3`j#c;UW$+KWVrC4?=if(4UE_KBi$>-{=D{QT^q>xY1>!DmYAEkIEp_ z*Q9iyO*po!w$iB!Nk5$%+HX@b)_FP}f5Mr4?}k+mF4O-A9GvA(uo=QzkQ4aTtyP3@))x3_gV%2C=3 z45BSH+g%bCkK-v9&uS@`-fB~Dc0=WU!Kuu#)p>u^3e8vyp1{*}^sWLOd`Fw)gqA%4 zCkrVrSFG&}Q16is+LOrayi6t`1NL{(Ov{y8izL!tw1I)<+s7`_uK4-|#VWkmX*9~4 zNc4m#Zd{R2N*k7>A{3NIU*d;)%6JVpHpK(BUFAPl@-1N%S8>?#pxW^xq==x7`? zDA(3Ektb%Q5+*yB575sJWTT4Ss*?_L#^S3ergA!XSftmco3}w}X_Rb?)tMcctTqWn zkI^V2j+%UUh>MUi4FB|26y>JU!N{KWDj9c-ci?#|jVWC4rEL)>^-LwBg*)9CCPXn&ogpzv~O2zMo9{hX193)7RZy+(1N?k6y0a(xsGYk zc^i~$F4idq0?>{k?lMg=5+zstyf2FfQ zFJh@KM*O=fxUo&@s&qf2y}M#F31j29FoW~YXpqLgD^{ax!iL;kv6zHPs9kK(kfKTI zLHl>b3i%WDIoiJ~J`;2zPbIABiPy7cCP(S?&Y=VSLH)=PeYEJvk=TJA6|83Pv@DE9 zLNg)lQ&Tzfg-b$=sb3tl$2#^B#i6`S<*ll-o>(ZZ;i6jL@f41Pfq2Or9?{vv zVHwjmbnWMGGj|u1nf-dMcyT#1pm92?J^OYeg5rQ-jk;tXb?mt$C@EsSVrLx*!vZ%( z{`Lv5+l(arxSO^)Jf!GYV^G33A(Ha#BJXg7${c1MGI}426zUAsYMqaPkQ@ofE(A)b z!i09uRh$XkH9UD-&kRqU+56@aeYn0iKg+y5Z!V6h{cbMGoyR!2*r<~#u+SUO)E;Vs zR#NzD7q!hV2Ehg%0t_Q|(ItU2>`FIZDUmlwzeQ82(Eb@@1&=$uk84;@&?VPN+c z%i}>`^*nmfioAM}Bl?y|fI4WZP6?8?lunPPN|U-bz)Dp{Pf%N5qFjwnuXdy{hDMAA z*^y+t2c?1D4{@=NwmsB7T)f@w$cK-BCYADzRCL=!NB=n*w3~Q`$fweBr$d)K$Qd%b zM#4^G=sYf|@z}5>gC<2n;&(_H{X)1&NAhu>k!&4AABje`V@4;~d``wGDCr@^89|MP z82BA7enp2(2Ha-X6(4ns7JX-G=-l;b?jg#2v{y&N(?yrRsxy_6!d*=_a^z=-(@Nc~ z#;USShcO#}4Vj~OGO0yNhC{VBO_W@H+OZB~DgGfc9!G}hqG7p476i#RWMW4*Z~>)_ zr99;hnP#<*bLUF0L`TTW^Y&*wM_GLTw)}*)=&u1%wqn z%pv3JN4C~Vm0QyzC|(zoULlKux5LovXpzOLU2;;-iwv2WNRhRtk~bsNVTj>lOP)^2 zSK<&dIqb+yW-Y(xO`AFhH+g~JX$9$&N_*OiES%Y=!DPJ~>su@elwoa~k1#?!gaA6Guaz;FW-34VDn%rIF{wVE} zchk35F)l~g?wO`<$a5dX)iG~B#prs*l_=Rs4x;&(%)c@wR_K?K11En7Vm;N3_Y6Z2 z<8)tgoHtC&ax^d+tqnsxMza=eqDgtYl>EwD3c-x34iF^msk`Fbz#maJ$K`4`PPEb4 z4xRQPsG`HEY7(3`vP{#lcp5YzSJH57n%s`v*bF4q{TTDD8A!I(*fg{hqp?|Nmd)5S zv=o!ES!lN1)-=2ngRyC7os`GvvheamOGaSzO~~lMwlsc(mxrHgD>jXr`}|x6R<1Z* zL$PVx%<|2)RcRvgnYlEc*;ZoHu!k@b>$au_o9LsyB050|Yjk{gb)nT6XtUYz)33A5 zg6eqm30NE+T`!k#_7YoOx?i7*$WG8kd1ahUOI2W>Z3!>k>65V$mO3k&0w3mlY{5Mu z`;cA?e8@ZA?Y6dHq-3qfPtDkXqqKBroul0$7yLV(3%OFu$7{Ds?P_&X8%e-fODx&c zx?AM5*~Nu?{i$7;*w>%hr31J0z1e{Mtl+V+)o``8(tEf%iA&qCh#oW>Gv{ZQe3Uut zP$~?HAp-*jW_74?`dwT%cnnWg_qt2Hi>WMYbcc))7DK=K5w5POeA7JWs5jd&P+D7Ffd zzDDRktoh=Iz!b+iOq|+JNK~=|^%|6igZW;oRd22X022!h`f1WnOZ})q9AJ4>CAFcQ z7JqV}F6lvMjlW?o#OuQdPaO{uk>v*5@>fn3rs60P+_AwFu}r_%xDVS{8|}l$R&B+5 z0+yF(_BetoK${Q?4t+toP5OlEt)lk8VA;~3vw@`~oMK*G!WWEVZPfbsCM#JWst$rD z)|$18*jz>|>Nui0(}_ej)NY&CP-AXdd0xlB(OYkH@mlnNJbgT)1h+44n?oAvARPU| zI0q&QHT4TWZGLzSH3RS{m<}U0Xy{D8`in;C$m$JPO2GkbBo_6>YhVo;KdR>7!aG%< z25lx1N9Dqbnz~Q(*zEXVwM%;-Sbo(WauG-wNSoUbS4mA`sZW-<*{`;6)EyhU)mC?< z3K!<#+85#0aIdEYx87Vv4mJDBWNHO24lKa%3Cx~Qc92Ut7A}ms!E#=+zt)AQa5ps} z>WLyi>8k*g2$^3(KEp=_dx&;Jgn&m&u_0n?h#VUt$c9L=A);)EEE^)shDfs^;%u-y zh)l%`<4sHtk4B;@qJ%@hfc#B=+8m?y` zV0jfSra?Yf_zK~o`eKZpO+gvDcw<8mLR&%y120nt zZ&XezR6=0fOdYJ5Djkfz0$ibOQkAbTMY!U*O}DbKvFdH;a3wKmc5o)`K@sRL(%uS* z(oe{gYjA0OSb5NZ3B56B;$j=>Pe*ART8@U+QOX_;)hqYF_Z!K*hLTFBLlO4e#0Hj^PUswg?? z=8Ezm>og)txYO=<+QDPxFe?W0&M^AB96-WBE|=-%hp?X z<9y)3Qjb2nD6h|-EGi2#1K9IJ8R0SD1!V?fsz|fIKrNubEdOy8#kp>Ordd|@#Nn0~ z13CmErc1`O7&Cf%hTh4c%SyBj3%g<9Y;l3*U)V_^HcPmYVKZ5zttN%ROh__qQpzWz zbYw+L8)hpfjp~gtlm`0=JhI~F&B5#%luB)|03(i2j5H+m)o)QJUXOaQUDR&l9k7`* z{-{NAY8_XMe)5PV4GM*|}peGZ~(k!AB@meHC*a=g-)j;^b zK`X6Cj{MLM9z+?c3un08mHXP-L!KEo9>q&YA;#!Yg6IunNzg<3x?Gemc?7{72C`yJ z7yOhVHV?hvz@uqJA~!W_>o(t?*-}OcQ`+KH&YF)=Lr3kc;A&TLW>)qZG(?Zn4nGqF zcb;FH=AiC)YSo0DyPOY!U^Z_+rlL3Er^np&Q(g!*9fSR!G z*u3L>)jV953{o}lH))2uO>_I^mA1ry3Tij6A`W7ay&_zTgYi^Y0ciG=Nq`yJ@wCom zrfq`K?x&jRq2Xy$ePl@}?3QVTLz*ha08?wLtJvAH<6^~bR!~f>_i;_YlIylbqP^6U z#Ti*U_o>nH(BrKZXHaf=nnxXlmtjVN`+rT`Xi6#4o*%)GC zBpYJ{GfCb|%Zx``8Q^V`?XWP8=S`FCu+*{q;zoA{$e2QHbdPc=967@Iue4;g%-XQQ zPVxXNhdhcGiawGD<&qt>emi!jsDYIuYQ-ym)cS$jouUR-j;Ix{A);0<+U^*2t_)XC z^5&0PzstK*)WFJ-YQ@WrI8Z(tqwEEfLA7Uv-7^aEUw;Cc3n+ zO7{S9Ka{;LmQQydgQXrl?a@Y;j;T-*kU~QHf5DllsoN|?56yUqeR(j zhs3kh4ok^Q2PHN09ITX_a&g>@ad1k=39SA}R-h^*0V==a3HQg;_J&Y2LpnKbgIuan zo$Erj6`OOqquzph;*-p~SY!V(4nA^W8n$l4K1aOKY&0Qh?90U+$}%6+CP7GtZgX130OYBDn9-k+c~ZL~6) zT4KLYJt%+lX!3p&Z8ESmeI<{+d`ovfU?Xb+!)%}IoJE-*fnEb2adfYW8Su;+@-`^=kc*NzWv1lj4L6FHf)ANBf2N;TqI?MSzuDY zTromblAT?wV_}U7Hif>Rzll?$v%U{7#Cd%zo0m}*`anWt zO3^S+j_x*iyb0X%JsB?o<0GQk=y1%Y*6#m*(W{F+a^~=6`FobDR&xUthJ@s zs9qR;=8k7V)bZUHg1V4{20^)E>Q@=I)9ADc>-?aJLpfwjG?C)G_Q;UsYD8tqE3#Uu zDiGWJovGDgwjWV9mXbC$jak!V#b9c#(Nu{K9Wb_M?3!X#-K?1Nml&)wz+CaRkw=Ay z4N`@kOsPMTFmr>vN__7s%Xg`jr&JFR>#p+MkeVu31?=bSa1>pzycEK^Td+*_iO9u4 z5lZw<`8I)ZU8kIZ9b z5DZ^In*`liLfE=*FXKTK718M$#=*3crH*SeuT{&mC}zp@TH*}0e`+l#$CkQkt6)dz z)Y>6s|C9!?APlf>M<$@LM4G51BRFz7(?WBOabr~r5%53GF?qmYjtOHOI{tWEq=^D* z{j@)v5|7s5bgdV+f`u#5bak=fv~8~9EW%!Qlu`2#6J;|V%+pRh2GFrGK?ZX6kuPUi zjKB;@CjUfP8YM`o7NwWeUG7?)ySRm{w^r()0#}pQ;_O)H1fV*W8a&1))y|$K^W~@p zN`TlQA)ha0&_??cH(->uzPxE@W7L(9Wu=!bB)fR<+~dX?qCJgL)RA(4hYwaB zwE?ay(I}Hr=T9OZt$stkg$epUIZL2%lO4~lq#b77teQ);w_Nk^vyS88xG{(qh3Kp` zHn+BrT5s+%c#3&e`*Fi5YwKwJBiHCIVgzSEFOP7eQ~LU_7?6*1o7t zW8tH_6!fdOPysG6FFw`8t)n8N9f>wBVc@yv6_4%?&}sYROC}hBAol*J^}8taDlXnN zp^C-F+vx!MOnv4oj_~4w><6pBq}%Y?W`@Y7+iWt zT(g4+guuj$bP>e~TG`YjmWAM#Wy{isXD?m+y;-ia#`jl@yY(P2GJ*oFo`kS7*4|}=9 zk^K&)L}gVRb;5)#eVxKCp7hpNyz1|%|EmYXJO&mJR_ zIIgKfDhE}MR?zME5p;5sE4W#vlz+K`D5vGiGjLE8$Df$TLwtCuv3FLzTu4pV)P&q! zVsrj9qByZN2#@!A)vd~65WB=v^o3!f70+Ojc)nWg_pG`PaJf9rsO>>|_~cCg#9Fg8 zn86Ww-;cHJvbRlwa+Z;P!;x}=^n-evu&(YN4DeYG8|N^9iO(GU@mQPFDk^t%R>llc zMidUmT(XPOqrpwAJk;oNZXm@_!832v;}F)k11^r3xYhg}J?d`KG%Vs( z0ea4iLL9ytMH+>cA7o8K9|89x^&yojcg=^jmeaMInxd4hDPVJPTTMaXc{GK{o-1>3 z>yu{*P{vyr!DDKK#pPZ;7==CXJ3MQEq*;KcAUIDtz&yrhN*}}!qYD?g;Zxya%t~58pmY&)uW+Y7nTL3*8 zeN0m17A6uNTRtKcMWu5Z_fQvLbvUfc{cq?movDOU^pl~OHqzOd8649smuWO{yFAQQ zmD`ZR*u1(89<}u|*xI2h$VihMf;%T9q)*{s!*J)? zVWGrpPQJ?JeIZhDDi>pFn-_x@SK3%GO(=9(RZj^~E6>;xuC-Q(3CWbeTUbcnr$2vlP4LkVqq<5Ee^w)JRpcc}wE2N10%wyv9K{4NB#M zMR_Ybq8l9ara?Jx%kmBfy>Cz)arcIrXdkH&rvGAMN^ zsiP67&fZo8dWpT)B9L2noS;a^$2mF-_0-?p-uYj-M?R!VeG35#&;QCj5uNsJGSyS; z?(r6PfpUqdUol)hYjY8lZ6f+6Ly?q3iRRQtNxw5FH<)k1)QeCmlvKx*%KIi$-7;n3 zGyw^E*PyT`NEnyJp42%IMMA0^5x=f_hfU!>xg>axf|D+a|WzH1zG-Jm$d_XY>u`jbL=FFT?) zIp}SJ;-u*79CVLq-cE|7)0bhxUEVM4JI4L_G`j>d8Ofew%yKrH^_@kLUM)ojOtB1$ zMiwV0x*YVRL2+{8&Z1n&jtH;cs=ucUiX-mp9Q39^am2l|DDPxPbd!T_85Bp{_c+Ki z13^bzuc;G#fL#=$c=vuz2Vq2cKYJgHKsqe?Eir?ZVdRWkQcwnr{Ype7aXnz-%49Sh zQAL7i-yMr;^>P!^fn-QJh>JTHlVCJwX{BFu#n{k~0?G87Q1nAAe`ipex5 zAs4K)Lcuu0$2>T7i_ad96<(CM6qKi#DiYA4dXiC|VRw%wHQaFiU{LP%e)fycn>g5G zN0o{ssoF;5*ElsdOsbq_`b~y%h}&+#v|%Sj-()BiPDz(tY8ub6|HT;0t|K=&>>YNY zU&VX$qDF>(wW&M~dW~I*?FRez^CCxDgDULaW`2;Wyqo|`f?0rOO%84CX);6l%(fCd5*cf zwv8}(aNcM7?aDn5&H=7BhuBR?)iDmLL@46DU_f>8)(yxh_A4Cpf_f-ROYJyO` zXiyx+H#z8@RcSjF@xo}e`a^H{BzqUz26TbFD-lSCMZYfZIpMu&crOd@O~c6Pf?P)P z!YC55;WBc%ySK7aJ8dKib0kd|?PIFFUia#r=jBUy?e)F{sLf78qioVX;kehxF(=*! z49LkDJ4P(D+R*`I$0bw|<2)#msyY`G>6I+bf}2mC$2oy3CZUdY%7Jo;sVk-;@hCkK zQc(71qezfc$Fx*lV)9oEn~Hc}@95aj2i;?68m3IfE-}?}hOsmA5|n2RinD^~ zqAb`sEGSV#PU*hnq`=9C94Hm8sd%YR{b4L2-c18?`uE3oMRkR#t{KJ^@m_jDqOU#8 z-d7`#ojWgPGupQ^)%7U)ud_D?l}L&V67M!t9*ZF;G%mkpC5&Kp$__EkQFhaCW;yIU zyD7uJ>l}0|LJ{xLp2_J7doM*GTb`TD;O&T!c=twB!l)I2vKWaN5L&##5b9pM9y3bo z14Seuk8yg(Na@trFLO|Y;&f71IMNqPDk|cA#ef{f&+Urpb*6g5Fm^Q5Ee`s+L8;i8 z`aTEU+c#yp3zU6KeaLXBhdaKJ=V5pThOoJ1bupvMhLMZAaBG9`AY=7g$c7}dqwH6SNh=L*BRwrgW}Xg z7sb&5E{c;sdpQD;C2blYI8%(9hO>{u7LCA8Gd;jT!X{-SuFfc3!^KIqpge0(DzCFw z$`ef~UQ5XT0;9ZQs1~zOUNR_7e!5(oh+bxDktr>&^5BS|!Y3t7Qo}^aq;;ov3g;Lr zvK6DyaKK;Z;M)e&5brw%X`6 zGgvW>V zoIHAlgCZ`@>Y1QiGh7^$8yxheL2;74@AF!g61%9a;(gA5YT|vtfGRJtxA3H9fUG#r z-g*SmVbSk{OeJx|qI=5l-Y&YU5mv-i`?ldd5m9ZEln;XU9TW1;8Bq>wUyy&EM}HRb z=n6MhX{pp1FlfqXmb$BKoY9&vI>c0WdxZnf%SXh@(TT5cY_GA4k-)un)w*Wk?D5Xu z0hF|u9{A5SDmrZI&g;e8+iWifiqFmke0;<|QQCJ<= zkRy&TS~Mtg;uUIWIq^n}oN=Krsu)J|;uUHP#Kaphaw`24GkBa`8uE%?$Wt~q1?6cI zzoT_8aL{Fg;$+7r2Sr?*p{t<0WVkpe-WPPmD6or)Dc-AJ)IrG9o9w+6f$aJuj1Cz_ zbK;E{)m%nSgL)uaqVtA#z0TfeB9JZ7HjJisMOC_8Dv@7=N6zjfG>#n|{P6R3k?i%J z0@Th-4c&=jtb}6;+MQ?r_VZg={f6EAXUQ+%>1hTVmz(Fq?6sQ0HG6zLHyOVMWde?Aq z#vv z61zyZc<=pb9R%fafW55YD2Mwe8A@&v`&{6gti$Jl6w3m4v zGrZ@;8$}mNbWa*aPThEb8Az&Q88B;j*B)dBB5aDn-GVio4s!3;_ z410;OZy2i2iZ?3wWw*SX&i-X)Akkx1u-_eR3)WQ=owJ(u3J2{o)up+gy@d!Q)%!IA za_Y1&iVB`DbVkK5NsY4AN!JI1g1f1Eo{!|vz7HmaOA96!v8fin3}qD3YshL=lO1@k=^)F-U!!z0X7-y9}-~1EI#;O1xh;ybYszHlx=W z`=+6C<~KP|-e&4|v$+g`@_sg#6;4T)-L$#Z{Tz0{q}nN}5(gc-EtCt~>t1FTg>Z$v zFGL`_=!B|kQ0Bz@v;ozG(X$cgIrhF5fwFkNXi%KRK#4v=ah4Qa6z4>sEej5B?Q_OM zcMj<)m($Ityu|zF&zg2~i@h&iHXu8LgwgAU(VQ@P&w%RUecynbPSIsFFFb`IR+Gj1 zhGFEC$Af=G%Xo-gR3cmGV;nU5Cxvn$JEAELS~Mt*@?YVgfkAOn^dtv8m5p+ZgI+Y{ zTbJ^EI|9AO-uEL=iA(>esRi|8?4620b{@aM(YK#i{w%Ip}qR;&9o^ zsoiI);s=cKV0J|JaL|5(;-u(22h|OVBkr9=+02gUaSm!36i3{v9Q3L|al~~|oR)Kw zso%}!A}H?|lsWOfXF&CXKc_47A$C*t^j${t!f3@%)m~xmwFqQ4m0OO`b0Yt661j}# zg;6~_dRu6kvf5G;%of{borY85XeUhcPLWkOXz@=0ipUV#(*4wgi+m~%!xN*RCgIUweLDJxM>(w#CywtYIaNA z_X`^GAiF6WbwCii*|sTavGHtk74z9P{?nn2slSKCFEusYOYGX_Fzr~5F`n4M6w8l! z>BWfQQ_SZwyJEM{j_-rUx8=CP@`(LJTb??Hw=BFD`P;^Sh2huOeU;rC8TexG@9EEJ zPS3I{#{X>o6Kt+cjK|&NZ?Q?2g+I%9VxO+X-#gJyF`mG6 zOZu|##VFJMu1%@G#j4B=4!_Cn8|;3W-COM1TwZ6m(7naqZ?h}LX1phCO8#cJ*o?95 z#n@DDGQJo>5#uRhm}Rl2DIRCnrf>B%WWcW2$9Rdq^Ws07fq$LhH`slh-8a}3GZ}ja zc1-#^Fa3MW&*qYs{+$f^0n7CyyS8x&J3hIG`r@Vzkt?fmY1GDl#=6WbmvrTJsEz+F zE*0ANhxppdC3at8_hoi%{3(V{vwNQ1$20Kd!in6N zuy32#{N)BrUi=67jG>$vZt?ds?ArVV?{N-)mfhzv@So#@W-qWShXr5aZ=1gyQOt|K zkNI3>S5DH&K{uQKJwxKlStdCFwaABG&a-Rt7rcsvcY(j<pwdIrD=X*Ka-bS|ZWsCM8;~!#I zwp0J4@w4QZ$Vji`!+8#WoL$++wdEfcKZ~#I58M2uyd->+<#{qg{wzG%T(;Bn_Mc5kpN2ByV4@By|NTVnSZyJB2d-0KV% zW3^&HRBU`s@%W>{?$hjEVOI?8UFY${B_1z`dzrt*KH4?@zRs@LFcX7iVoyxm^W48) zU{}T$Vr)zLe=&Gf;{Ns+yJ8>7xNL@|z^>Sb5%&W3kK!KUey_mp1iNCZU@!Mq``E4X zy)wCYC-=?7J;>LV{4H0FL|=>hp7alwbUi4sdyL&Fb}Q^IvU`Eu7Q0<`pJewE zyO-I$!tS%|zQFEF>|SN}8oSroeUDv__3V?Z|Kwnw93tHJl&Ah=Ct2JVGup#D43`yn z**hula^W-VzR0fT9{tKb*9{K8$?p3<$2dQ)-M#GYWA^~N5hv{v_$wSPYY}hp_q*)A zFZ92l=?=1M^V|OWZf}n_ahHp8w|AFUNrm6-y`2i*>rH%X8lMk&$3Bt<|FF0Di8T1P zc<=vc8vGvb*&j=Tf2(&b75)+L*lZg9w|NI1OM~C*U8<$Q@AJ}f_HOUny<=C>@V~=5 z_RDGTecqeDng;)7?AS(3x-cy@LLLgpLgEk^RF4dYvI4c@XHqb|6xAAVDWjM;s3~j{|DxC&wr~t z=4Y=e@B6*|7W^X&FIez>3huVwk14p@ejiY9S3i78!CifFP{9uv`NVTr!CgI2QgBzl z9Z_(%J|9zXSD&9!a93YR{g)B8$TO?(@AYH^Ebw`T%ZOOu=NT>|V}bt!!)1gl@H)d~ zq%82yF0`Cg{o|1`s8L@nGdGh9a20{<@k;9nAm zcE85(V;1}y0{>hRf3NDF?u9MNB>W=`zhJ@lF}!QRKgRG&7W@H*U$NkyV)zRd{2;@x zTJXaRziz=x43`;($A3o{E;9{*A7i-8I0Sx*;WG0O_$&+w-#KL3j0 zuUqi<82*+8|CYN+zJ16^`RohTmks zL5A1%Za;3Bu;e@ld=KN{$N!N^Aan7&!wP=DyYd|dq&#|@^L-dQCjUwb-|eT4D7f2C z9aHcJynkbLg}&bXeE4bT_R}}m&djDWPiT|*If3LS>&HJQ( zlo_*7J*M#Q^t_)`Dv{Fi$Bv{fzv;!PWWN_qXkO(mGHH|2F; zp8+Y4lvlEJJ?{xc?v|G>$M5jo)CFOf>2iF)Ye+@o5M507dsnUTm6YRqzhqb_k1ofL zd-q&V!gngi@Bhz|_)?C&k0#+#j1|r@pHcYVNMl5N^`x3*Y z|9XlQ%fDy1j6Yvu_}GVu&|N2)1pHHwU&eLQ%>N0%Kk41?$$ViS!~YK4?*zV#htDJZ z^!FRU|4!{q{Qeg6mvQfFEYDXm@bCVXbUuF>aFX-FCCy&)?U@YxYZ>s@0N>~B_l{jp zi0R$T!2fCn{CDru`5@~{_b|I9c+&ErodJJ21OCr5;D3|>{{+_Q(&Bw610H0+uVlb~ z2XISes1$z${Q;GW%on8o&j6k#&yxhd3;jY(XPA`Zf0==QEd&0KGvN1qTY9|TlL7zB zfRp?(?|7HX@vmgy|4Ih@tqk}lkifKjIFbQx1O8FyNzwnPX6o;Y8Th}R0lxt_rAx-W zdcNm*KMaNhzjR6SMRiht%c?%}N6h&dz)26tI;7~a-v*r8k-dKSPcr!YyA1eU-=1Et zKCa-=`jyD}1AwRH=V=AM*Sq@jT6k7V-cM!l{}sR~A6~em@rC~z8T>zr@!Us|54X6# zKEMNmPXSJRWFEK4c~=EIP0q_1@MoEi%pVt-|NokS|3?|{Pe4(ta&KxuCRpE2F#J+4 zncfcIlr9;E6j=UW20Tsv-^hU9RD75?=6p@zBY(c6fqFjRdHbPE()ibbmZqN@8Th}H z0e?9I{`(p5uK`Z^CiAuXISof4WSX3hXTZOd0sng$@IT0af9SiY-QDNOI-d0VKL$8R zoWGyQfd6a;{GVjN|Gy0QUqXgZ{>Zx1b(Y|9z|-VuX2Aby2K;}@fd3)j6t9dkrJa5) z1OGd}o9n+G5PG+`{#O7`ld}&v={H&Dyu|7HuK-7taQ^;T2A_8n+^y%|_AxEbl}nnH z$Uh4>#VhNs`#GkcW_;N(7X04>JWc*TVtkor>Ge~L$FL+y{AK<5AoKr2z|;7=n*qNY zf~Dbq0&uFIvi@9T{tFrSPXeBnpMM+hecs2Ne&ja*r*fBdEflx<``{?iQne*-whE9+V>F#f^sP4CCY04ID|?|P5% zpJ2Gm2Onhkml*E-f(A&so(DXwT>dWLAH{#NPb%sC?}UF(^O17@Y6c(wfpq?lWWfJ6 z;FPZJCCwirB=z^z4E%#wB1x0~M>F8(GvLo=z<(zL{!al{<;CL}bffBT0$VHuH|yc7 z-_`-AarKvZT#e+Yzn=u0+Ntbk6&e1UgwOuC^V`CIT|=*P;C)zcO2eO4aLB`QO1#S% z_?I)_uV=vjCGBi-SM}{DHJ{hC z2RVGa2yf8SwuTa7wT2e|0&%KlYc>@U(osnF0S=2K?K9P{%9#)JHkqQ-G)Oe+2L}d44hj|5r2Me^>FrDBzlo zP}2jXSfM3dh|IG~ewG8-;4EP@dPV&pi(+64pgFl=u z=X3^qDFgm18SsCe0sqI}l0NVLcM2cl;h)z6N`3y=A*!FzIhGNY{|w-1^#SHk34EVnW{F8TK@^oD%=pIhj zU5C@_|HlDW`LLxCUt|170Z&WsPh{}f%)tN647m5{rL|_OzSJ3fda&C4bgeg7>Q&qI zA6aUQR~yyC9q+;V;eyw$Uknsp&|X_z3VRB$9`^dpPTOmD24Mi2UZ+_Pn)R?f(4cyC zP}RP$UDuv=bv5)Tj&QlzK3pT_KK&HwXM}!A^fT%`xQSSU{-D|$1gq6%+Z%+NgTpmV zp|D5wuOb@NR3HQGnED-8zZ2?rl77bu>Q_ZKrfA0$?Uc1+QZDcUhbJFaNQ z745j99apsDigsMlj)Qjdun$c90u#T$!7p&|tCHkv9PkGO{P7F^n}>^vs;H=n;17tR zEh^fgqAe=gqM|J-+M=RWh$D)@h+;6J7>sDRVlbi@j3@>piou9tFrpYJl#*glQVdFp zK}j(v=}^U>q!^SGgOXxUQVd2F?Wm$vC<;R%OnRR=c`^t$YhiZ~45~}5u;4&^7m@-h zI#@1b#KD31wg9D37c}OA#vPDLH{sw+dck97C+7y0UUR)V2>pqf{gI={c=+D$pSE%Or zlO1GDSY2IOYXnUQQAJ&wL1GI*xx6qIR8B9Hf`tkCe;())%}zg9qM8J7GS(8n&05fD zXnq-Sp7bf{pM!?l4fRw(rFC%zInVj)kLq|$Dl#H2d%!>u96L5UbAk&`Sd6gf+e+T* zmzyNBUz|JM?Y5e=>HvM$l&^E&pPW0s1o~=ipsV02kB@J`X{!^O_dR%N>H&n?KUYUQaq?I0hG&vA1sUnmAEQ% zl+oGZ+`un^FA*az7q`05P^X)f(-7bcnzU9`UW1Zr%58C_jV5sRv?Op0jlb8dm8oDV z(2IkqaJ^Xz{qfibm=Ox)%jwjTnjq!U?ey%nG}h{%b%xuQa$#d73|o@N{@kPHlOmkt zybOC2IwMgTj2b3{L}L9ylpov2IuePjs@B+?l7KnJ%FpkG{pROGk*_#6AAJ+HX-eZ5 zngvE(q$-9CMN%#{>y*2T>xH0QECmryKUdr0c5N!HKh|tR5ER==r!Inz&&^mss7ffz z&E_CjfwF6byPU@hx+BMbcEb4{M zw6Is{p>6aA&9Lu}_Cs#aT!%A*AdI^}~P}La8tx^*$j`lG4Mml?EJH6Fv3w5hb@Ont`_=UL>TZ8a;uUFmD z`ZAsc)Ir9Rp4u4wk&EG01+})%ML#)rI^2@ly|~~PbpCTMk6NP@g*K{Ky{!_r(FuDAq3Q8LZhQ%^}{FD!gei8&$V)yI!7r!?omxII<9+Bm5ruc z^7dP${#LuD`xvA0e7{SIuH42P2<;k)TYMze%dEhT2?e4gwsRcjX;)h4(SgGd_`eWL^7s)6cygcPX^ zRT}YRB*kHUxP241g^6nTpt%|iCj7ZY^NCm%29v0&dK7653G>Ce)~<)WMvKM^D8Jff zHBi%R3^E6`6-q{Wb1mrF$RiwI7pF8=e+0RA2G#Y^X1m_mNVNW_kn;5sGS-TA|z zjxo{ziY{oj8yyu*yqM#v4WpmT>?%^U)16-P^B7RYT2-ZkG38cS4T?rhTVp73lO*{* zR1$_uqUSIkjlL6zMZ|Qfxf#|MsQ-6HZENTnR+&pQda%b=zMtJ%Pn!}f`p_n70)T!M zy-QH*tgd$2GqX#6xtuWvQbiK6FmsDB3|r9yX{BdUP4$S$-#&x6Y!!+5!GlXARZ+B&yg&sW(uk z6e11PN@s4}YYoT!tlT$MMY_rDRp3++<-Z!PqSQ?{lhs9yLgzJC*H)=QOjF0G8+-PY zY&MqDJSB@jdcM&yv2ufmw{;nrqu29Won=gWv!?&~5%+;9krOCWhUsichDd&`GGSTTg zmYCY->a|p|hL4t}#jDl!R;rpAY_-A#%;M0%pjLEYAlLozC+2zRD}&*gta-yZTHIdg zbOx-iFjhHTt1Jew8FA4UE>mFxBf0vtD&rX}t(>n``#nr(1!1OMByhPr&ZwA(r-o0? z^iN75CcbWxtIJiHYo<3+?WN31dToJ}q$vQS#Z?1FoN>LFzd&83 zw^Hq=C_SsM_Q%n0I~{eXHWK1e<{f==BF;idnB|=ob|`uoO=n>+A**s|97+wzG_>e1 zto2B1pX{u5F?jAl8Drw^)2wi++3&WhTb0g6*gMmy^W?7B@1nqh@tG4CI-%{C)yOo_ z^z&z^DWJSbAA?+&gqAC{77qsXTszW>v67wCeLq$QvnEJXN#ZJWas}BaT~T3fTD}sM zNwjANg9@xsX7JXl2LYxVi}CqJa-j~zF^}nj)}FC;VCt)?>ZhH89$&3)Qs1HrGs?wW z%?Ekd9`v?!EsADadOkEHuTeF_=dLZLgk?=s_rvil=8*OVW}ZQ1zHDXCt`}>#Vvo(u zR+qvSWvo$>raKs$JJqT#_h-~_wxGxUN)733jwVhRg{vj|#MCOg|1MIse8irS?l^Xi z@;Ya?q!v@rOx5m61D=`5Rjlu#2?T?(USUn24AC%ktxHQ2YB|wlh_2U0JFqIX2iw+k zC3OTdhUHe;%sdme*Q5cB&tcgx0i^h79aYaH)N1sYtQf||Ne#5Cx@pp9{qZ?kbyMp+ zyaiPpF};x5io(o;`>DKLpPB&B*6O70P~~z64okdUj{|kr*0(ZVTlu)L%LaG@k|#N zRUf~w8qH~SPr_@4egRs=tOCSl3MlT+^qTeA>K68WCad+jz1rApCfeo5@m6!Wy$WvB zSj(zurmkt&9lu|oR@m$}Wy&1QzJ^?mPo#JPYjS!zuXglkUo2WGr}+t0O+Cv`tpA`G zllyQ=-o{1`8(OitooEbxNb41+FjS&ZwJfk;x~S(vn1Y7w^@uo{U6xkD=JLwmRHujB z9jxfpB2(!3>Jioou!c4WvCwLwutqX8pdENO;yS$wmaVNT^3 zpRQnvwu;${Nk+1m{8BryMojaUWXsPP<=AE)3$ksZ$8bbV%A=}ohFa*6RMkiAJX7sq zbySy*l&(KkZ}!pjXus)fXV7eH(ITF%R;XIoYf!ACvEGTb!JyNg=!KY?_pzFg%r2ge z>)0P|Z(x)bU?ph{Csatn#6Dpu+zj*Os! z;?&7l+2@O?T)>{Ovw>DyC}PQjB8}=&-s-<5`xwwau~|7WgEHvh7@;~4gC@rHJ63Z= zclf?Kac1;nac+?|3G}zli`e*D)(Rq7^QGPBbspZyx8XBh!;(O49mjZTu}O%m`Wm#T zJDNX@Rbj4xYIq4*7iZ!_tzG3Q&nMH@nf+0vFt8|Ywr#0rO{_3eU#o|2s5G* z#2Q*g2Wj#=-*8VdPWaQ3j~=Pe$W!}JA{fO^;ILnH4UH-4%(RwDn+Zy`C#!N0lblU&XYnX-6d*DqzCyO+9+J7d8$D!Sd#2fQ^WLr;U>zgRNj4 zr>vEVP0qk5{ZT8)skAZ3$JiBvd^N_eSFJhvXpOo(97++@m)m8=^>xX$%ei+kwY&RZWZm%82kYmL= z3@ry1+8y+C2yG6~KvkjfM}RQQG^#|vzHSSgXjuo}9kqykI9v%D)O!Uhb>Pbv7}c-| z6+0&F9q#r*D!rgeM{&HvaX)q&ngS=b6fa^>GLl9HyAI;iG2&>TcbK+wRl4dpnY65S zz!9$e)ukougvwV78yVt9K8Y9mx#C@|)@TD=KGk5i&zBW$!@)IPWdrRl<{@^f#lSK_w=M1$ zaep`dXXoD>0>2THU+i*=tL<~@JR&|4kGMYp*nf!8i~VkK4-gUlNPdc2Pc$ zrSKCw-{M~WcEXC{7kWuQT_Ys=6NH36u?H^ht@|{b@*k!VO#DLsBw!>L7qhV&F80GO zd@BNDe{%0y+@C^NoL=ldiTe`n^Tq#!PGCO^57A5d#SXc+`=#PAfuvvPf61a3d*$MO zotVe|q}~eXZ@?3eU+kKT`z$rC*q3Uo-~9WU{&GhB5kCLkqW7+AI`67> z3;ZdL(8>26L{2bCf8n|gDKNdrDfl-1he1#B+wlm!w&yI=8kfF^hW@^T>GfCiTmOgJ zfAq7GbNXB81oL|{=wJAVuK3q*l`sBh)Bj)w{rOL6`qyzEF#c!Lk21ZT{s$|X{*(Vw za#nK@dU202eLN2Gmw%Xg71*IC1s(enIsu)|p#SSXr|FZiNBJ)Fk7dyRO{VW!6~K<4 zzAY7@SnvBa9e)A$V(ITw`1gDGC-q14H>qb^Mu5CyuW9-}#Qn$kpB+ElNlv5xzJIIf LS1bbS)BFDc`8J5Q literal 302968 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 diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h new file mode 100644 index 000000000..0ba42d3d8 --- /dev/null +++ b/selfdrive/ui/qt/util.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +inline void configFont(QPainter &p, QString family, int size, const QString &style) { + QFont f(family); + f.setPixelSize(size); + f.setStyleName(style); + p.setFont(f); +} diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index d9c170e27..24c586113 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -1,4 +1,4 @@ -#include "controls.hpp" +#include "controls.h" QFrame *horizontal_line(QWidget *parent) { QFrame *line = new QFrame(parent); @@ -48,6 +48,9 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons vlayout->addWidget(description); connect(title_label, &QPushButton::clicked, [=]() { + if (!description->isVisible()) { + emit showDescription(); + } description->setVisible(!description->isVisible()); }); } @@ -55,3 +58,9 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons setLayout(vlayout); setStyleSheet("background-color: transparent;"); } + +void AbstractControl::hideEvent(QHideEvent *e){ + if(description != nullptr){ + description->hide(); + } +} diff --git a/selfdrive/ui/qt/widgets/controls.hpp b/selfdrive/ui/qt/widgets/controls.h similarity index 84% rename from selfdrive/ui/qt/widgets/controls.hpp rename to selfdrive/ui/qt/widgets/controls.h index 3f048c4bb..22e36ea4f 100644 --- a/selfdrive/ui/qt/widgets/controls.hpp +++ b/selfdrive/ui/qt/widgets/controls.h @@ -6,16 +6,25 @@ #include #include -#include "common/params.h" -#include "toggle.hpp" +#include "selfdrive/common/params.h" +#include "selfdrive/ui/qt/widgets/toggle.h" QFrame *horizontal_line(QWidget *parent = nullptr); class AbstractControl : public QFrame { Q_OBJECT +public: + void setDescription(const QString &desc) { + if(description) description->setText(desc); + } + +signals: + void showDescription(); + protected: AbstractControl(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); + void hideEvent(QHideEvent *e); QSize minimumSizeHint() const override { QSize size = QFrame::minimumSizeHint(); @@ -107,14 +116,15 @@ class ParamControl : public ToggleControl { Q_OBJECT 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())) { + ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { + 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); + QObject::connect(this, &ToggleControl::toggleFlipped, [=](bool state) { + params.putBool(param.toStdString().c_str(), state); }); } + +private: + Params params; }; diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc index 7cbcc0aab..1395c150c 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.cc +++ b/selfdrive/ui/qt/widgets/drive_stats.cc @@ -1,11 +1,12 @@ +#include "drive_stats.h" + #include #include #include #include -#include "api.hpp" -#include "common/params.h" -#include "drive_stats.hpp" +#include "selfdrive/common/params.h" +#include "selfdrive/ui/qt/request_repeater.h" const double MILE_TO_KM = 1.60934; @@ -22,9 +23,8 @@ static QLayout* build_stat_layout(QLabel** metric, const QString& name) { return layout; } -void DriveStats::parseResponse(QString response) { - response = response.trimmed(); - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); +void DriveStats::parseResponse(const QString& response) { + QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8()); if (doc.isNull()) { qDebug() << "JSON Parse failed on getting past drives statistics"; return; @@ -36,35 +36,35 @@ void DriveStats::parseResponse(QString response) { labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); }; - bool metric = Params().read_db_bool("IsMetric"); QJsonObject json = doc.object(); update(json["all"].toObject(), all_, metric); update(json["week"].toObject(), week_, metric); } DriveStats::DriveStats(QWidget* parent) : QWidget(parent) { - setStyleSheet("QLabel {font-size: 48px; font-weight: 500;}"); + metric = Params().getBool("IsMetric"); + QString distance_unit = metric ? "KM" : "MILES"; - auto add_stats_layouts = [&](QGridLayout* gl, StatsLabels& labels, int row, const char* distance_unit) { + auto add_stats_layouts = [&](QGridLayout* gl, StatsLabels& labels, int row, const QString &distance_unit) { gl->addLayout(build_stat_layout(&labels.routes, "DRIVES"), row, 0, 3, 1); gl->addLayout(build_stat_layout(&labels.distance, distance_unit), row, 1, 3, 1); gl->addLayout(build_stat_layout(&labels.hours, "HOURS"), row, 2, 3, 1); }; - const char* distance_unit = Params().read_db_bool("IsMetric") ? "KM" : "MILES"; - QGridLayout* gl = new QGridLayout(); + QGridLayout* gl = new QGridLayout(this); gl->setMargin(0); + gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3); add_stats_layouts(gl, all_, 1, distance_unit); + gl->addWidget(new QLabel("PAST WEEK"), 6, 0, 1, 3); add_stats_layouts(gl, week_, 7, distance_unit); - QVBoxLayout* vlayout = new QVBoxLayout(this); - vlayout->addLayout(gl); - - // TODO: do we really need to update this frequently? QString dongleId = QString::fromStdString(Params().get("DongleId")); QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/stats"; - RequestRepeater* repeater = new RequestRepeater(this, url, 13, "ApiCache_DriveStats"); - QObject::connect(repeater, SIGNAL(receivedResponse(QString)), this, SLOT(parseResponse(QString))); + RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 30); + QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &DriveStats::parseResponse); + + setLayout(gl); + setStyleSheet(R"(QLabel {font-size: 48px; font-weight: 500;})"); } diff --git a/selfdrive/ui/qt/widgets/drive_stats.hpp b/selfdrive/ui/qt/widgets/drive_stats.h similarity index 79% rename from selfdrive/ui/qt/widgets/drive_stats.hpp rename to selfdrive/ui/qt/widgets/drive_stats.h index 64b93cfe7..deeb80f65 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.hpp +++ b/selfdrive/ui/qt/widgets/drive_stats.h @@ -9,10 +9,11 @@ public: explicit DriveStats(QWidget* parent = 0); private: + bool metric; struct StatsLabels { QLabel *routes, *distance, *hours; } all_, week_; private slots: - void parseResponse(QString response); + void parseResponse(const QString &response); }; diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index cc0dada7d..4e9d2e668 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -1,7 +1,9 @@ +#include "input.h" + #include -#include "input.hpp" -#include "qt_window.hpp" +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/hardware/hw.h" InputDialog::InputDialog(const QString &prompt_text, QWidget *parent) : QDialog(parent) { layout = new QVBoxLayout(); @@ -25,8 +27,8 @@ InputDialog::InputDialog(const QString &prompt_text, QWidget *parent) : QDialog( background-color: #444444; )"); header_layout->addWidget(cancel_btn, 0, Qt::AlignRight); - QObject::connect(cancel_btn, SIGNAL(released()), this, SLOT(reject())); - QObject::connect(cancel_btn, SIGNAL(released()), this, SIGNAL(cancel())); + QObject::connect(cancel_btn, &QPushButton::released, this, &InputDialog::reject); + QObject::connect(cancel_btn, &QPushButton::released, this, &InputDialog::cancel); layout->addLayout(header_layout); @@ -43,7 +45,7 @@ InputDialog::InputDialog(const QString &prompt_text, QWidget *parent) : QDialog( layout->addWidget(line, 1, Qt::AlignTop); k = new Keyboard(this); - QObject::connect(k, SIGNAL(emitButton(const QString&)), this, SLOT(handleInput(const QString&))); + QObject::connect(k, &Keyboard::emitButton, this, &InputDialog::handleInput); layout->addWidget(k, 2, Qt::AlignBottom); setStyleSheet(R"( @@ -111,7 +113,6 @@ void InputDialog::setMinLength(int length){ minLength = length; } - ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, QWidget *parent):QDialog(parent) { setWindowFlags(Qt::Popup); @@ -133,13 +134,13 @@ ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString if (cancel_text.length()) { QPushButton* cancel_btn = new QPushButton(cancel_text); btn_layout->addWidget(cancel_btn, 0, Qt::AlignRight); - QObject::connect(cancel_btn, SIGNAL(released()), this, SLOT(reject())); + QObject::connect(cancel_btn, &QPushButton::released, this, &ConfirmationDialog::reject); } if (confirm_text.length()) { QPushButton* confirm_btn = new QPushButton(confirm_text); btn_layout->addWidget(confirm_btn, 0, Qt::AlignRight); - QObject::connect(confirm_btn, SIGNAL(released()), this, SLOT(accept())); + QObject::connect(confirm_btn, &QPushButton::released, this, &ConfirmationDialog::accept); } setFixedSize(900, 350); @@ -161,20 +162,20 @@ ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString setLayout(layout); } -bool ConfirmationDialog::alert(const QString &prompt_text) { - ConfirmationDialog d = ConfirmationDialog(prompt_text, "Ok", ""); +bool ConfirmationDialog::alert(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, "Ok", "", parent); return d.exec(); } -bool ConfirmationDialog::confirm(const QString &prompt_text) { - ConfirmationDialog d = ConfirmationDialog(prompt_text); +bool ConfirmationDialog::confirm(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, "Ok", "Cancel", parent); return d.exec(); } int ConfirmationDialog::exec() { // TODO: make this work without fullscreen -#ifdef QCOM2 - setMainWindow(this); -#endif + if (Hardware::TICI()) { + setMainWindow(this); + } return QDialog::exec(); } diff --git a/selfdrive/ui/qt/widgets/input.hpp b/selfdrive/ui/qt/widgets/input.h similarity index 85% rename from selfdrive/ui/qt/widgets/input.hpp rename to selfdrive/ui/qt/widgets/input.h index f52ad4416..4ffd0a9bb 100644 --- a/selfdrive/ui/qt/widgets/input.hpp +++ b/selfdrive/ui/qt/widgets/input.h @@ -1,13 +1,13 @@ #pragma once -#include -#include -#include #include +#include #include +#include #include +#include -#include "keyboard.hpp" +#include "selfdrive/ui/qt/widgets/keyboard.h" class InputDialog : public QDialog { Q_OBJECT @@ -44,8 +44,8 @@ class ConfirmationDialog : public QDialog { public: explicit ConfirmationDialog(const QString &prompt_text, const QString &confirm_text = "Ok", const QString &cancel_text = "Cancel", QWidget* parent = 0); - static bool alert(const QString &prompt_text); - static bool confirm(const QString &prompt_text); + static bool alert(const QString &prompt_text, QWidget *parent = 0); + static bool confirm(const QString &prompt_text, QWidget *parent = 0); private: QLabel *prompt; diff --git a/selfdrive/ui/qt/widgets/keyboard.cc b/selfdrive/ui/qt/widgets/keyboard.cc index 0eda100ed..6613897b1 100644 --- a/selfdrive/ui/qt/widgets/keyboard.cc +++ b/selfdrive/ui/qt/widgets/keyboard.cc @@ -1,11 +1,11 @@ +#include "keyboard.h" + +#include #include -#include #include #include -#include #include - -#include "keyboard.hpp" +#include const int DEFAULT_STRETCH = 1; const int SPACEBAR_STRETCH = 3; diff --git a/selfdrive/ui/qt/widgets/keyboard.hpp b/selfdrive/ui/qt/widgets/keyboard.h similarity index 99% rename from selfdrive/ui/qt/widgets/keyboard.hpp rename to selfdrive/ui/qt/widgets/keyboard.h index 5ff50382e..c89f4fc6a 100644 --- a/selfdrive/ui/qt/widgets/keyboard.hpp +++ b/selfdrive/ui/qt/widgets/keyboard.h @@ -2,12 +2,11 @@ #include +#include #include +#include #include #include -#include -#include - class KeyboardLayout : public QWidget { Q_OBJECT diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc index cd1173722..7816b251f 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ b/selfdrive/ui/qt/widgets/offroad_alerts.cc @@ -1,47 +1,53 @@ -#include -#include -#include -#include -#include -#include -#include +#include "offroad_alerts.h" -#include "offroad_alerts.hpp" -#include "common/params.h" +#include +#include +#include +#include + +#include "selfdrive/common/util.h" #include "selfdrive/hardware/hw.h" -void cleanStackedWidget(QStackedWidget* swidget) { - while(swidget->count() > 0) { - QWidget *w = swidget->widget(0); - swidget->removeWidget(w); - w->deleteLater(); - } -} - OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(); - main_layout->setMargin(25); + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(50); + layout->setSpacing(30); - alerts_stack = new QStackedWidget(); - main_layout->addWidget(alerts_stack, 1); + QWidget *alerts_widget = new QWidget(this); + alerts_layout = new QVBoxLayout; + alerts_layout->setMargin(0); + alerts_layout->setSpacing(30); + alerts_widget->setLayout(alerts_layout); + alerts_widget->setStyleSheet("background-color: transparent;"); - // bottom footer + // release notes + releaseNotes.setWordWrap(true); + releaseNotes.setVisible(false); + releaseNotes.setStyleSheet("font-size: 48px;"); + releaseNotes.setAlignment(Qt::AlignTop); + + releaseNotesScroll = new ScrollView(&releaseNotes, this); + layout->addWidget(releaseNotesScroll); + + alertsScroll = new ScrollView(alerts_widget, this); + layout->addWidget(alertsScroll); + + // 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); + footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft); + QObject::connect(dismiss_btn, &QPushButton::released, this, &OffroadAlert::closeAlerts); - reboot_btn = new QPushButton("Reboot and Update"); - reboot_btn->setFixedSize(600, 125); - reboot_btn->setVisible(false); - footer_layout->addWidget(reboot_btn, 0, Qt::AlignRight); + 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(); }); - QObject::connect(dismiss_btn, SIGNAL(released()), this, SIGNAL(closeAlerts())); - QObject::connect(reboot_btn, &QPushButton::released, [=]() { Hardware::reboot(); }); - - setLayout(main_layout); + setLayout(layout); setStyleSheet(R"( * { font-size: 48px; @@ -58,54 +64,51 @@ 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); + if (alerts.empty()) { + // 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(); - updateAvailable = Params().read_db_bool("UpdateAvailable"); - reboot_btn->setVisible(updateAvailable); - - QVBoxLayout *layout = new QVBoxLayout; - layout->setSpacing(20); - - 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); + l->setStyleSheet("background-color: " + QString(severity ? "#E22C2C" : "#292929")); + l->setVisible(false); + alerts_layout->addWidget(l); } + alerts_layout->addStretch(1); } - QWidget *w = new QWidget(); - w->setLayout(layout); - alerts_stack->addWidget(w); + updateAlerts(); + + rebootBtn.setVisible(updateAvailable); + releaseNotesScroll->setVisible(updateAvailable); + releaseNotes.setText(QString::fromStdString(params.get("ReleaseNotes"))); + + alertsScroll->setVisible(!updateAvailable); + for (const auto& [k, label] : alerts) { + label->setVisible(!label->text().isEmpty()); + } } -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.h b/selfdrive/ui/qt/widgets/offroad_alerts.h new file mode 100644 index 000000000..88a69c8da --- /dev/null +++ b/selfdrive/ui/qt/widgets/offroad_alerts.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include "selfdrive/common/params.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" + +class OffroadAlert : public QFrame { + Q_OBJECT + +public: + explicit OffroadAlert(QWidget *parent = 0); + int alertCount = 0; + bool updateAvailable; + +private: + void updateAlerts(); + + Params params; + std::map alerts; + + QLabel releaseNotes; + QPushButton rebootBtn; + ScrollView *alertsScroll; + ScrollView *releaseNotesScroll; + QVBoxLayout *alerts_layout; + +signals: + void closeAlerts(); + +public slots: + void refresh(); +}; diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.hpp b/selfdrive/ui/qt/widgets/offroad_alerts.hpp deleted file mode 100644 index ec48f89c7..000000000 --- a/selfdrive/ui/qt/widgets/offroad_alerts.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -struct Alert { - QString text; - int severity; -}; - -class OffroadAlert : public QFrame { - Q_OBJECT - -public: - explicit OffroadAlert(QWidget *parent = 0); - QVector alerts; - QStringList alert_keys; - bool updateAvailable; - -private: - QStackedWidget *alerts_stack; - QPushButton *reboot_btn; - void parse_alerts(); - -signals: - void closeAlerts(); - -public slots: - void refresh(); -}; diff --git a/selfdrive/ui/qt/widgets/scrollview.cc b/selfdrive/ui/qt/widgets/scrollview.cc new file mode 100644 index 000000000..31be17c7b --- /dev/null +++ b/selfdrive/ui/qt/widgets/scrollview.cc @@ -0,0 +1,47 @@ +#include "scrollview.h" + +#include + +ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent){ + setWidget(w); + setWidgetResizable(true); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setStyleSheet("ScrollView { background-color:transparent; }"); + + QString style = R"( + QScrollBar:vertical { + border: none; + background: transparent; + width:10px; + margin: 0; + } + QScrollBar::handle:vertical { + min-height: 0px; + border-radius: 4px; + background-color: white; + } + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 0px; + } + QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; + } + )"; + + verticalScrollBar()->setStyleSheet(style); + horizontalScrollBar()->setStyleSheet(style); + + QScroller *scroller = QScroller::scroller(this->viewport()); + QScrollerProperties sp = scroller->scrollerProperties(); + + sp.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); + sp.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QVariant::fromValue(QScrollerProperties::OvershootAlwaysOff)); + + scroller->grabGesture(this->viewport(), QScroller::LeftMouseButtonGesture); + scroller->setScrollerProperties(sp); +} + +void ScrollView::hideEvent(QHideEvent *e){ + verticalScrollBar()->setValue(0); +} diff --git a/selfdrive/ui/qt/widgets/scrollview.h b/selfdrive/ui/qt/widgets/scrollview.h new file mode 100644 index 000000000..aaec224e2 --- /dev/null +++ b/selfdrive/ui/qt/widgets/scrollview.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +class ScrollView : public QScrollArea { + Q_OBJECT + +public: + explicit ScrollView(QWidget *w = nullptr, QWidget *parent = nullptr); +protected: + void hideEvent(QHideEvent *e); +}; diff --git a/selfdrive/ui/qt/widgets/setup.cc b/selfdrive/ui/qt/widgets/setup.cc index 32e14f20d..2633220ea 100644 --- a/selfdrive/ui/qt/widgets/setup.cc +++ b/selfdrive/ui/qt/widgets/setup.cc @@ -1,3 +1,5 @@ +#include "setup.h" + #include #include #include @@ -6,11 +8,10 @@ #include #include #include +#include -#include "QrCode.hpp" -#include "api.hpp" -#include "common/params.h" -#include "setup.hpp" +#include "selfdrive/common/params.h" +#include "selfdrive/ui/qt/request_repeater.h" using qrcodegen::QrCode; @@ -23,13 +24,17 @@ PairingQRWidget::PairingQRWidget(QWidget* parent) : QWidget(parent) { QTimer* timer = new QTimer(this); timer->start(30 * 1000); - connect(timer, SIGNAL(timeout()), this, SLOT(refresh())); - refresh(); // don't wait for the first refresh + connect(timer, &QTimer::timeout, this, &PairingQRWidget::refresh); +} + +void PairingQRWidget::showEvent(QShowEvent *event){ + refresh(); } void PairingQRWidget::refresh(){ - QString IMEI = QString::fromStdString(Params().get("IMEI")); - QString serial = QString::fromStdString(Params().get("HardwareSerial")); + Params params; + QString IMEI = QString::fromStdString(params.get("IMEI")); + QString serial = QString::fromStdString(params.get("HardwareSerial")); if (std::min(IMEI.length(), serial.length()) <= 5) { qrCode->setText("Error getting serial: contact support"); @@ -37,9 +42,7 @@ void PairingQRWidget::refresh(){ qrCode->setStyleSheet(R"(font-size: 60px;)"); return; } - QVector> payloads; - payloads.push_back(qMakePair(QString("pair"), true)); - QString pairToken = CommaApi::create_jwt(payloads); + QString pairToken = CommaApi::create_jwt({{"pair", true}}); QString qrString = IMEI + "--" + serial + "--" + pairToken; this->updateQrCode(qrString); @@ -105,13 +108,12 @@ PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QWidget(parent) { return; } - // TODO: only send the request when widget is shown QString url = "https://api.commadotai.com/v1/devices/" + dongleId + "/owner"; - RequestRepeater* repeater = new RequestRepeater(this, url, 6, "ApiCache_Owner"); - QObject::connect(repeater, SIGNAL(receivedResponse(QString)), this, SLOT(replyFinished(QString))); + RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_Owner", 6); + QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &PrimeUserWidget::replyFinished); } -void PrimeUserWidget::replyFinished(QString response) { +void PrimeUserWidget::replyFinished(const QString &response) { QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); if (doc.isNull()) { qDebug() << "JSON Parse failed on getting username and points"; @@ -136,7 +138,7 @@ PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QWidget(parent) { vlayout->addWidget(new QLabel("Upgrade now"), 1, Qt::AlignTop); - QLabel* description = new QLabel("Become a comma prime member in the comma connect app and get premium features!"); + QLabel* description = new QLabel("Become a comma prime member at my.comma.ai and get premium features!"); description->setStyleSheet(R"( font-size: 50px; color: #b8b8b8; @@ -182,7 +184,7 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { background: #585858; )"); finishRegistationLayout->addWidget(finishButton); - QObject::connect(finishButton, SIGNAL(released()), this, SLOT(showQrCode())); + QObject::connect(finishButton, &QPushButton::released, this, &SetupWidget::showQrCode); QWidget* finishRegistration = new QWidget; finishRegistration->setLayout(finishRegistationLayout); @@ -192,7 +194,7 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { QVBoxLayout* qrLayout = new QVBoxLayout; - qrLayout->addSpacing(40); + qrLayout->addSpacing(30); QLabel* qrLabel = new QLabel("Scan with comma connect!"); qrLabel->setWordWrap(true); qrLabel->setAlignment(Qt::AlignHCenter); @@ -239,14 +241,14 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { // set up API requests QString dongleId = QString::fromStdString(Params().get("DongleId")); QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/"; - RequestRepeater* repeater = new RequestRepeater(this, url, 5, "ApiCache_Device"); + RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 5); - QObject::connect(repeater, SIGNAL(receivedResponse(QString)), this, SLOT(replyFinished(QString))); - QObject::connect(repeater, SIGNAL(failedResponse(QString)), this, SLOT(parseError(QString))); + QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &SetupWidget::replyFinished); + QObject::connect(repeater, &RequestRepeater::failedResponse, this, &SetupWidget::parseError); hide(); // Only show when first request comes back } -void SetupWidget::parseError(QString response) { +void SetupWidget::parseError(const QString &response) { show(); showQr = false; mainLayout->setCurrentIndex(0); @@ -257,7 +259,7 @@ void SetupWidget::showQrCode(){ mainLayout->setCurrentIndex(1); } -void SetupWidget::replyFinished(QString response) { +void SetupWidget::replyFinished(const QString &response) { show(); QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); if (doc.isNull()) { diff --git a/selfdrive/ui/qt/widgets/setup.hpp b/selfdrive/ui/qt/widgets/setup.h similarity index 81% rename from selfdrive/ui/qt/widgets/setup.hpp rename to selfdrive/ui/qt/widgets/setup.h index 0479db8f9..ad6e0dc8d 100644 --- a/selfdrive/ui/qt/widgets/setup.hpp +++ b/selfdrive/ui/qt/widgets/setup.h @@ -5,7 +5,7 @@ #include #include -#include "api.hpp" +#include "selfdrive/ui/qt/api.h" class PairingQRWidget : public QWidget { Q_OBJECT @@ -16,6 +16,7 @@ public: private: QLabel* qrCode; void updateQrCode(QString text); + void showEvent(QShowEvent *event); private slots: void refresh(); @@ -33,7 +34,7 @@ private: CommaApi* api; private slots: - void replyFinished(QString response); + void replyFinished(const QString &response); }; class PrimeAdWidget : public QWidget { @@ -56,7 +57,7 @@ private: bool showQr = false; private slots: - void parseError(QString response); - void replyFinished(QString response); + void parseError(const QString &response); + void replyFinished(const QString &response); void showQrCode(); }; diff --git a/selfdrive/ui/qt/widgets/ssh_keys.cc b/selfdrive/ui/qt/widgets/ssh_keys.cc index 6a22defbe..d180d558c 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.cc +++ b/selfdrive/ui/qt/widgets/ssh_keys.cc @@ -1,9 +1,11 @@ -#include -#include -#include "widgets/input.hpp" -#include "widgets/ssh_keys.hpp" -#include "common/params.h" +#include "ssh_keys.h" +#include +#include + +#include "selfdrive/common/params.h" +#include "selfdrive/ui/qt/api.h" +#include "selfdrive/ui/qt/widgets/input.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.", "") { @@ -27,33 +29,26 @@ SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH QObject::connect(&btn, &QPushButton::released, [=]() { if (btn.text() == "ADD") { - username = InputDialog::getText("Enter your GitHub username"); + QString username = InputDialog::getText("Enter your GitHub username"); if (username.length() > 0) { btn.setText("LOADING"); btn.setEnabled(false); getUserKeys(username); } } else { - Params().delete_db_value("GithubUsername"); - Params().delete_db_value("GithubSshKeys"); + params.remove("GithubUsername"); + params.remove("GithubSshKeys"); refresh(); } }); - // setup networking - manager = new QNetworkAccessManager(this); - networkTimer = new QTimer(this); - networkTimer->setSingleShot(true); - networkTimer->setInterval(5000); - connect(networkTimer, SIGNAL(timeout()), this, SLOT(timeout())); - refresh(); } void SshControl::refresh() { - QString param = QString::fromStdString(Params().get("GithubSshKeys")); + QString param = QString::fromStdString(params.get("GithubSshKeys")); if (param.length()) { - username_label.setText(QString::fromStdString(Params().get("GithubUsername"))); + username_label.setText(QString::fromStdString(params.get("GithubUsername"))); btn.setText("REMOVE"); } else { username_label.setText(""); @@ -62,49 +57,27 @@ void SshControl::refresh() { btn.setEnabled(true); } -void SshControl::getUserKeys(QString username){ - QString url = "https://github.com/" + username + ".keys"; - - QNetworkRequest request; - request.setUrl(QUrl(url)); -#ifdef QCOM - QSslConfiguration ssl = QSslConfiguration::defaultConfiguration(); - ssl.setCaCertificates(QSslCertificate::fromPath("/usr/etc/tls/cert.pem", - QSsl::Pem, QRegExp::Wildcard)); - request.setSslConfiguration(ssl); -#endif - - reply = manager->get(request); - connect(reply, SIGNAL(finished()), this, SLOT(parseResponse())); - networkTimer->start(); -} - -void SshControl::timeout(){ - reply->abort(); -} - -void SshControl::parseResponse(){ - QString err = ""; - if (reply->error() != QNetworkReply::OperationCanceledError) { - networkTimer->stop(); - QString response = reply->readAll(); - if (reply->error() == QNetworkReply::NoError && response.length()) { - Params().write_db_value("GithubUsername", username.toStdString()); - Params().write_db_value("GithubSshKeys", response.toStdString()); - } else if(reply->error() == QNetworkReply::NoError){ - err = "Username '" + username + "' has no keys on GitHub"; +void SshControl::getUserKeys(const QString &username) { + HttpRequest *request = new HttpRequest(this, "https://github.com/" + username + ".keys", "", false); + QObject::connect(request, &HttpRequest::receivedResponse, [=](const QString &resp) { + if (!resp.isEmpty()) { + Params params; + params.put("GithubUsername", username.toStdString()); + params.put("GithubSshKeys", resp.toStdString()); } else { - err = "Username '" + username + "' doesn't exist on GitHub"; + ConfirmationDialog::alert("Username '" + username + "' has no keys on GitHub"); } - } else { - err = "Request timed out"; - } - - if (err.length()) { - ConfirmationDialog::alert(err); - } - - refresh(); - reply->deleteLater(); - reply = nullptr; + refresh(); + request->deleteLater(); + }); + QObject::connect(request, &HttpRequest::failedResponse, [=] { + ConfirmationDialog::alert("Username '" + username + "' doesn't exist on GitHub"); + refresh(); + request->deleteLater(); + }); + QObject::connect(request, &HttpRequest::timeoutResponse, [=] { + ConfirmationDialog::alert("Request timed out"); + refresh(); + request->deleteLater(); + }); } diff --git a/selfdrive/ui/qt/widgets/ssh_keys.hpp b/selfdrive/ui/qt/widgets/ssh_keys.h similarity index 61% rename from selfdrive/ui/qt/widgets/ssh_keys.hpp rename to selfdrive/ui/qt/widgets/ssh_keys.h index 24deee953..aaa7f80dc 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.hpp +++ b/selfdrive/ui/qt/widgets/ssh_keys.h @@ -1,11 +1,9 @@ #pragma once -#include #include -#include -#include "widgets/controls.hpp" #include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/qt/widgets/controls.h" // SSH enable toggle class SshToggle : public ToggleControl { @@ -27,22 +25,11 @@ public: SshControl(); private: + Params params; + QPushButton btn; - QString username; QLabel username_label; - // networking - QTimer* networkTimer; - QNetworkReply* reply; - QNetworkAccessManager* manager; - void refresh(); - void getUserKeys(QString username); - -signals: - void failedResponse(QString errorString); - -private slots: - void timeout(); - void parseResponse(); + void getUserKeys(const QString &username); }; diff --git a/selfdrive/ui/qt/widgets/toggle.cc b/selfdrive/ui/qt/widgets/toggle.cc index 551630dd7..d4eb215d3 100644 --- a/selfdrive/ui/qt/widgets/toggle.cc +++ b/selfdrive/ui/qt/widgets/toggle.cc @@ -1,4 +1,4 @@ -#include "toggle.hpp" +#include "toggle.h" Toggle::Toggle(QWidget *parent) : QAbstractButton(parent), _height(80), diff --git a/selfdrive/ui/qt/widgets/toggle.hpp b/selfdrive/ui/qt/widgets/toggle.h similarity index 99% rename from selfdrive/ui/qt/widgets/toggle.hpp rename to selfdrive/ui/qt/widgets/toggle.h index 8d9c779de..d2773f207 100644 --- a/selfdrive/ui/qt/widgets/toggle.hpp +++ b/selfdrive/ui/qt/widgets/toggle.h @@ -1,4 +1,5 @@ #pragma once + #include class Toggle : public QAbstractButton { diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index c88a47dd9..864dabf15 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -1,4 +1,5 @@ -#include "window.hpp" +#include "window.h" + #include "selfdrive/hardware/hw.h" MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { @@ -7,25 +8,36 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { homeWindow = new HomeWindow(this); main_layout->addWidget(homeWindow); + QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings); + QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings); + QObject::connect(&qs, &QUIState::uiUpdate, homeWindow, &HomeWindow::update); + QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransition); + QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransitionSignal); + QObject::connect(&device, &Device::displayPowerChanged, homeWindow, &HomeWindow::displayPowerChanged); settingsWindow = new SettingsWindow(this); main_layout->addWidget(settingsWindow); + QObject::connect(settingsWindow, &SettingsWindow::closeSettings, this, &MainWindow::closeSettings); + QObject::connect(&qs, &QUIState::offroadTransition, settingsWindow, &SettingsWindow::offroadTransition); + QObject::connect(settingsWindow, &SettingsWindow::reviewTrainingGuide, this, &MainWindow::reviewTrainingGuide); onboardingWindow = new OnboardingWindow(this); main_layout->addWidget(onboardingWindow); - 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())); - - // start at onboarding main_layout->setCurrentWidget(onboardingWindow); - QObject::connect(onboardingWindow, SIGNAL(onboardingDone()), this, SLOT(closeSettings())); + QObject::connect(onboardingWindow, &OnboardingWindow::onboardingDone, this, &MainWindow::closeSettings); onboardingWindow->updateActiveScreen(); + device.setAwake(true, true); + QObject::connect(&qs, &QUIState::uiUpdate, &device, &Device::update); + QObject::connect(&qs, &QUIState::offroadTransition, this, &MainWindow::offroadTransition); + QObject::connect(&device, &Device::displayPowerChanged, this, &MainWindow::closeSettings); + + // load fonts + QFontDatabase::addApplicationFont("../assets/fonts/opensans_regular.ttf"); + QFontDatabase::addApplicationFont("../assets/fonts/opensans_bold.ttf"); + QFontDatabase::addApplicationFont("../assets/fonts/opensans_semibold.ttf"); + // no outline to prevent the focus rectangle setLayout(main_layout); setStyleSheet(R"( @@ -58,11 +70,11 @@ void MainWindow::reviewTrainingGuide() { bool MainWindow::eventFilter(QObject *obj, QEvent *event){ // wake screen on tap if (event->type() == QEvent::MouseButtonPress) { - homeWindow->glWindow->wake(); + device.setAwake(true, true); } - // filter out touches while in android activity #ifdef QCOM + // filter out touches while in android activity 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(); diff --git a/selfdrive/ui/qt/window.hpp b/selfdrive/ui/qt/window.h similarity index 72% rename from selfdrive/ui/qt/window.hpp rename to selfdrive/ui/qt/window.h index 37cc70722..9d3a2a891 100644 --- a/selfdrive/ui/qt/window.hpp +++ b/selfdrive/ui/qt/window.h @@ -1,11 +1,12 @@ #pragma once -#include #include +#include -#include "offroad/settings.hpp" -#include "offroad/onboarding.hpp" -#include "home.hpp" +#include "selfdrive/ui/qt/home.h" +#include "selfdrive/ui/qt/offroad/onboarding.h" +#include "selfdrive/ui/qt/offroad/settings.h" +#include "selfdrive/ui/ui.h" class MainWindow : public QWidget { Q_OBJECT @@ -17,6 +18,9 @@ public: explicit MainWindow(QWidget *parent = 0); private: + Device device; + QUIState qs; + QStackedLayout *main_layout; HomeWindow *homeWindow; SettingsWindow *settingsWindow; diff --git a/selfdrive/ui/sidebar.cc b/selfdrive/ui/sidebar.cc deleted file mode 100644 index 805e1520c..000000000 --- a/selfdrive/ui/sidebar.cc +++ /dev/null @@ -1,143 +0,0 @@ -#include -#include -#include -#include -#include "common/util.h" -#include "paint.hpp" -#include "sidebar.hpp" - -static void draw_background(UIState *s) { - const NVGcolor color = nvgRGBA(0x39, 0x39, 0x39, 0xff); - ui_fill_rect(s->vg, {0, 0, sbr_w, s->fb_h}, color); -} - -static void draw_settings_button(UIState *s) { - ui_draw_image(s, settings_btn, "button_settings", 0.65f); -} - -static void draw_home_button(UIState *s) { - ui_draw_image(s, home_btn, "button_home", 1.0f); -} - -static void draw_network_strength(UIState *s) { - static std::map network_strength_map = { - {cereal::DeviceState::NetworkStrength::UNKNOWN, 1}, - {cereal::DeviceState::NetworkStrength::POOR, 2}, - {cereal::DeviceState::NetworkStrength::MODERATE, 3}, - {cereal::DeviceState::NetworkStrength::GOOD, 4}, - {cereal::DeviceState::NetworkStrength::GREAT, 5}}; - const int img_idx = s->scene.deviceState.getNetworkType() == cereal::DeviceState::NetworkType::NONE ? 0 : network_strength_map[s->scene.deviceState.getNetworkStrength()]; - ui_draw_image(s, {58, 196, 176, 27}, util::string_format("network_%d", img_idx).c_str(), 1.0f); -} - -static void draw_network_type(UIState *s) { - static std::map network_type_map = { - {cereal::DeviceState::NetworkType::NONE, "--"}, - {cereal::DeviceState::NetworkType::WIFI, "WiFi"}, - {cereal::DeviceState::NetworkType::CELL2_G, "2G"}, - {cereal::DeviceState::NetworkType::CELL3_G, "3G"}, - {cereal::DeviceState::NetworkType::CELL4_G, "4G"}, - {cereal::DeviceState::NetworkType::CELL5_G, "5G"}}; - const int network_x = 50; - const int network_y = 273; - const int network_w = 100; - const char *network_type = network_type_map[s->scene.deviceState.getNetworkType()]; - nvgFillColor(s->vg, COLOR_WHITE); - nvgFontSize(s->vg, 48); - nvgFontFace(s->vg, "sans-regular"); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgTextBox(s->vg, network_x, network_y, network_w, network_type ? network_type : "--", NULL); -} - -static void draw_metric(UIState *s, const char *label_str, const char *value_str, const int severity, const int y_offset, const char *message_str) { - NVGcolor status_color; - - if (severity == 0) { - status_color = COLOR_WHITE; - } else if (severity == 1) { - status_color = COLOR_YELLOW; - } else if (severity > 1) { - status_color = COLOR_RED; - } - - const Rect rect = {30, 338 + y_offset, 240, message_str ? strchr(message_str, '\n') ? 124 : 100 : 148}; - ui_draw_rect(s->vg, rect, severity > 0 ? COLOR_WHITE : COLOR_WHITE_ALPHA(85), 2, 20.); - - nvgBeginPath(s->vg); - nvgRoundedRectVarying(s->vg, rect.x + 6, rect.y + 6, 18, rect.h - 12, 25, 0, 0, 25); - nvgFillColor(s->vg, status_color); - nvgFill(s->vg); - - if (!message_str) { - nvgFillColor(s->vg, COLOR_WHITE); - nvgFontSize(s->vg, 78); - nvgFontFace(s->vg, "sans-bold"); - nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgTextBox(s->vg, rect.x + 50, rect.y + 50, rect.w - 60, value_str, NULL); - - nvgFillColor(s->vg, COLOR_WHITE); - nvgFontSize(s->vg, 48); - nvgFontFace(s->vg, "sans-regular"); - nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgTextBox(s->vg, rect.x + 50, rect.y + 50 + 66, rect.w - 60, label_str, NULL); - } else { - nvgFillColor(s->vg, COLOR_WHITE); - nvgFontSize(s->vg, 48); - nvgFontFace(s->vg, "sans-bold"); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgTextBox(s->vg, rect.x + 35, rect.y + (strchr(message_str, '\n') ? 40 : 50), rect.w - 50, message_str, NULL); - } -} - -static void draw_temp_metric(UIState *s) { - static std::map temp_severity_map = { - {cereal::DeviceState::ThermalStatus::GREEN, 0}, - {cereal::DeviceState::ThermalStatus::YELLOW, 1}, - {cereal::DeviceState::ThermalStatus::RED, 2}, - {cereal::DeviceState::ThermalStatus::DANGER, 3}}; - std::string temp_val = std::to_string((int)s->scene.deviceState.getAmbientTempC()) + "°C"; - draw_metric(s, "TEMP", temp_val.c_str(), temp_severity_map[s->scene.deviceState.getThermalStatus()], 0, NULL); -} - -static void draw_panda_metric(UIState *s) { - const int panda_y_offset = 32 + 148; - - int panda_severity = 0; - std::string panda_message = "VEHICLE\nONLINE"; - if (s->scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) { - panda_severity = 2; - panda_message = "NO\nPANDA"; - } -#ifdef QCOM2 - else if (s->scene.started) { - panda_severity = s->scene.gpsOK ? 0 : 1; - panda_message = util::string_format("SAT CNT\n%d", s->scene.satelliteCount); - } -#endif - - draw_metric(s, NULL, NULL, panda_severity, panda_y_offset, panda_message.c_str()); -} - -static void draw_connectivity(UIState *s) { - static std::map> connectivity_map = { - {NET_ERROR, {"CONNECT\nERROR", 2}}, - {NET_CONNECTED, {"CONNECT\nONLINE", 0}}, - {NET_DISCONNECTED, {"CONNECT\nOFFLINE", 1}}, - }; - auto net_params = connectivity_map[s->scene.athenaStatus]; - draw_metric(s, NULL, NULL, net_params.second, 180 + 158, net_params.first); -} - -void ui_draw_sidebar(UIState *s) { - if (s->sidebar_collapsed) { - return; - } - draw_background(s); - draw_settings_button(s); - draw_home_button(s); - draw_network_strength(s); - draw_network_type(s); - draw_temp_metric(s); - draw_panda_metric(s); - draw_connectivity(s); -} diff --git a/selfdrive/ui/sidebar.hpp b/selfdrive/ui/sidebar.hpp deleted file mode 100644 index f273e16f8..000000000 --- a/selfdrive/ui/sidebar.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "ui.hpp" - -void ui_draw_sidebar(UIState *s); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 2d268f795..0d91560f1 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -1,21 +1,24 @@ -#include -#include -#include -#include +#include "selfdrive/ui/ui.h" + #include +#include +#include -#include "common/util.h" -#include "common/swaglog.h" -#include "common/visionimg.h" -#include "ui.hpp" -#include "paint.hpp" +#include +#include +#include "selfdrive/common/swaglog.h" +#include "selfdrive/common/util.h" +#include "selfdrive/common/visionimg.h" +#include "selfdrive/common/watchdog.h" +#include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/paint.h" +#include "selfdrive/ui/qt/qt_window.h" + +#define BACKLIGHT_DT 0.25 +#define BACKLIGHT_TS 2.00 +#define BACKLIGHT_OFFROAD 50 -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. @@ -23,7 +26,7 @@ static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, const float margin = 500.0f; const vec3 pt = (vec3){{in_x, in_y, in_z}}; const vec3 Ep = matvecmul3(s->scene.view_from_calib, pt); - const vec3 KEp = matvecmul3(fcam_intrinsic_matrix, Ep); + const vec3 KEp = matvecmul3(s->wide_camera ? ecam_intrinsic_matrix : fcam_intrinsic_matrix, Ep); // Project. float x = KEp.v[0] / KEp.v[2]; @@ -52,27 +55,6 @@ static void ui_init_vision(UIState *s) { assert(glGetError() == GL_NO_ERROR); } - -void ui_init(UIState *s) { - s->sm = new SubMaster({ - "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "liveLocationKalman", - "pandaState", "carParams", "driverState", "driverMonitoringState", "sensorEvents", "carState", "ubloxGnss", -#ifdef QCOM2 - "roadCameraState", -#endif - }); - - s->scene.started = false; - s->status = STATUS_OFFROAD; - - ui_nvg_init(s); - - s->last_frame = nullptr; - s->vipc_client_rear = new VisionIpcClient("camerad", VISION_STREAM_RGB_BACK, true); - s->vipc_client_front = new VisionIpcClient("camerad", VISION_STREAM_RGB_FRONT, true); - s->vipc_client = s->vipc_client_rear; -} - static int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height) { const auto line_x = line.getX(); int max_idx = 0; @@ -140,9 +122,13 @@ static void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { update_line_data(s, model_position, 0.5, 1.22, &scene.track_vertices, max_idx); } -static void update_sockets(UIState *s) { +static void update_sockets(UIState *s){ + SubMaster &sm = *(s->sm); + sm.update(0); +} + +static void update_state(UIState *s) { SubMaster &sm = *(s->sm); - if (sm.update(0) == 0) return; UIScene &scene = s->scene; if (scene.started && sm.updated("controlsState")) { @@ -205,19 +191,13 @@ 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()) { - if (sensor.which() == cereal::SensorEventData::LIGHT) { -#ifndef QCOM2 + if (!Hardware::TICI() && sensor.which() == cereal::SensorEventData::LIGHT) { scene.light_sensor = sensor.getLight(); -#endif - } else if (!scene.started && sensor.which() == cereal::SensorEventData::ACCELERATION) { + } + if (!scene.started && sensor.which() == cereal::SensorEventData::ACCELERATION) { auto accel = sensor.getAcceleration().getV(); if (accel.totalSize().wordCount){ // TODO: sometimes empty lists are received. Figure out why scene.accel_sensor = accel[2]; @@ -230,69 +210,19 @@ static void update_sockets(UIState *s) { } } } -#ifdef QCOM2 - if (sm.updated("roadCameraState")) { + if (Hardware::TICI() && sm.updated("roadCameraState")) { auto camera_state = sm["roadCameraState"].getRoadCameraState(); float gain = camera_state.getGainFrac() * (camera_state.getGlobalGain() > 100 ? 2.5 : 1.0) / 10.0; scene.light_sensor = std::clamp((1023.0 / 1757.0) * (1757.0 - camera_state.getIntegLines()) * (1.0 - gain), 0.0, 1023.0); } -#endif scene.started = scene.deviceState.getStarted() || scene.driver_view; } -static void update_alert(UIState *s) { - UIScene &scene = s->scene; - if (s->sm->updated("controlsState")) { - auto alert_sound = scene.controls_state.getAlertSound(); - if (scene.alert_type.compare(scene.controls_state.getAlertType()) != 0) { - if (alert_sound == AudibleAlert::NONE) { - s->sound->stop(); - } else { - s->sound->play(alert_sound); - } - } - scene.alert_text1 = scene.controls_state.getAlertText1(); - scene.alert_text2 = scene.controls_state.getAlertText2(); - scene.alert_size = scene.controls_state.getAlertSize(); - scene.alert_type = scene.controls_state.getAlertType(); - scene.alert_blinking_rate = scene.controls_state.getAlertBlinkingRate(); - } - - // Handle controls timeout - if (scene.deviceState.getStarted() && (s->sm->frame - scene.started_frame) > 10 * UI_FREQ) { - const uint64_t cs_frame = s->sm->rcv_frame("controlsState"); - if (cs_frame < scene.started_frame) { - // car is started, but controlsState hasn't been seen at all - scene.alert_text1 = "openpilot Unavailable"; - scene.alert_text2 = "Waiting for controls to start"; - scene.alert_size = cereal::ControlsState::AlertSize::MID; - } else if ((s->sm->frame - cs_frame) > 5 * UI_FREQ) { - // car is started, but controls is lagging or died - if (scene.alert_text2 != "Controls Unresponsive") { - s->sound->play(AudibleAlert::CHIME_WARNING_REPEAT); - LOGE("Controls unresponsive"); - } - - scene.alert_text1 = "TAKE CONTROL IMMEDIATELY"; - scene.alert_text2 = "Controls Unresponsive"; - scene.alert_size = cereal::ControlsState::AlertSize::FULL; - s->status = STATUS_ALERT; - } - } -} - static void update_params(UIState *s) { const uint64_t frame = s->sm->frame; UIScene &scene = s->scene; - if (frame % (5*UI_FREQ) == 0) { - read_param(&scene.is_metric, "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; - } + scene.is_metric = Params().getBool("IsMetric"); } } @@ -307,10 +237,8 @@ static void update_vision(UIState *s) { VisionBuf * buf = s->vipc_client->recv(); if (buf != nullptr){ s->last_frame = buf; - } else { -#if defined(QCOM) || defined(QCOM2) + } else if (!Hardware::PC()) { LOGE("visionIPC receive timeout"); -#endif } } } @@ -334,25 +262,117 @@ 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->sidebar_collapsed = true; - s->scene.alert_size = cereal::ControlsState::AlertSize::NONE; + s->scene.is_rhd = Params().getBool("IsRHD"); + s->scene.end_to_end = Params().getBool("EndToEndToggle"); s->vipc_client = s->scene.driver_view ? s->vipc_client_front : s->vipc_client_rear; } else { - s->status = STATUS_OFFROAD; - s->sidebar_collapsed = false; - s->sound->stop(); s->vipc_client->connected = false; } } started_prev = s->scene.started; } -void ui_update(UIState *s) { - update_params(s); - update_sockets(s); - update_status(s); - update_alert(s); - update_vision(s); + +QUIState::QUIState(QObject *parent) : QObject(parent) { + ui_state.sm = std::make_unique>({ + "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "liveLocationKalman", + "pandaState", "carParams", "driverState", "driverMonitoringState", "sensorEvents", "carState", "ubloxGnss", +#ifdef QCOM2 + "roadCameraState", +#endif + }); + + ui_state.fb_w = vwp_w; + ui_state.fb_h = vwp_h; + ui_state.scene.started = false; + ui_state.last_frame = nullptr; + ui_state.wide_camera = Hardware::TICI() ? Params().getBool("EnableWideCamera") : false; + + ui_state.vipc_client_rear = new VisionIpcClient("camerad", ui_state.wide_camera ? VISION_STREAM_RGB_WIDE : VISION_STREAM_RGB_BACK, true); + ui_state.vipc_client_front = new VisionIpcClient("camerad", VISION_STREAM_RGB_FRONT, true); + ui_state.vipc_client = ui_state.vipc_client_rear; + + // update timer + timer = new QTimer(this); + QObject::connect(timer, &QTimer::timeout, this, &QUIState::update); + timer->start(0); +} + +void QUIState::update() { + update_params(&ui_state); + update_sockets(&ui_state); + update_state(&ui_state); + update_status(&ui_state); + update_vision(&ui_state); + + if (ui_state.scene.started != started_prev || ui_state.sm->frame == 1) { + started_prev = ui_state.scene.started; + emit offroadTransition(!ui_state.scene.started); + + // Change timeout to 0 when onroad, this will call update continously. + // This puts visionIPC in charge of update frequency, reducing video latency + timer->start(ui_state.scene.started ? 0 : 1000 / UI_FREQ); + } + + watchdog_kick(); + emit uiUpdate(ui_state); +} + +Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) { + brightness_b = Params(true).get("BRIGHTNESS_B").value_or(10.0); + brightness_m = Params(true).get("BRIGHTNESS_M").value_or(0.1); +} + +void Device::update(const UIState &s) { + updateBrightness(s); + updateWakefulness(s); + + // TODO: remove from UIState and use signals + QUIState::ui_state.awake = awake; +} + +void Device::setAwake(bool on, bool reset) { + if (on != awake) { + awake = on; + Hardware::set_display_power(awake); + LOGD("setting display power %d", awake); + emit displayPowerChanged(awake); + } + + if (reset) { + awake_timeout = 30 * UI_FREQ; + } +} + +void Device::updateBrightness(const UIState &s) { + float clipped_brightness = std::min(100.0f, (s.scene.light_sensor * brightness_m) + brightness_b); + if (Hardware::TICI() && !s.scene.started) { + clipped_brightness = BACKLIGHT_OFFROAD; + } + + int brightness = brightness_filter.update(clipped_brightness); + if (!awake) { + brightness = 0; + } + + if (brightness != last_brightness) { + std::thread{Hardware::set_brightness, brightness}.detach(); + } + last_brightness = brightness; +} + +void Device::updateWakefulness(const UIState &s) { + awake_timeout = std::max(awake_timeout - 1, 0); + + bool should_wake = s.scene.started || s.scene.ignition; + if (!should_wake) { + // tap detection while display is off + bool accel_trigger = abs(s.scene.accel_sensor - accel_prev) > 0.2; + bool gyro_trigger = abs(s.scene.gyro_sensor - gyro_prev) > 0.15; + should_wake = accel_trigger && gyro_trigger; + gyro_prev = s.scene.gyro_sensor; + accel_prev = (accel_prev * (accel_samples - 1) + s.scene.accel_sensor) / accel_samples; + } + + setAwake(awake_timeout, should_wake); } diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.h similarity index 63% rename from selfdrive/ui/ui.hpp rename to selfdrive/ui/ui.h index aec9a2256..9c20d202c 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.h @@ -1,33 +1,27 @@ #pragma once -#include "messaging.hpp" - -#ifdef __APPLE__ -#include -#define NANOVG_GL3_IMPLEMENTATION -#define nvgCreate nvgCreateGL3 -#else -#include -#define NANOVG_GLES3_IMPLEMENTATION -#define nvgCreate nvgCreateGLES3 -#endif #include #include #include -#include #include +#include + +#include +#include #include "nanovg.h" -#include "common/mat.h" -#include "common/visionimg.h" -#include "common/modeldata.h" -#include "common/params.h" -#include "common/glutil.h" +#include "cereal/messaging/messaging.h" +#include "cereal/visionipc/visionipc.h" +#include "cereal/visionipc/visionipc_client.h" #include "common/transformations/orientation.hpp" -#include "qt/sound.hpp" -#include "visionipc.h" -#include "visionipc_client.h" +#include "selfdrive/camerad/cameras/camera_common.h" +#include "selfdrive/common/glutil.h" +#include "selfdrive/common/mat.h" +#include "selfdrive/common/modeldata.h" +#include "selfdrive/common/params.h" +#include "selfdrive/common/util.h" +#include "selfdrive/common/visionimg.h" #define COLOR_BLACK nvgRGBA(0, 0, 0, 255) #define COLOR_BLACK_ALPHA(x) nvgRGBA(0, 0, 0, x) @@ -37,8 +31,6 @@ #define COLOR_YELLOW nvgRGBA(218, 202, 37, 255) #define COLOR_RED nvgRGBA(201, 34, 49, 255) -#define UI_BUF_COUNT 4 - typedef struct Rect { int x, y, w, h; int centerX() const { return x + w / 2; } @@ -50,23 +42,13 @@ typedef struct Rect { } } Rect; -const int sbr_w = 300; const int bdr_s = 30; const int header_h = 420; const int footer_h = 280; -const Rect settings_btn = {50, 35, 200, 117}; -const Rect home_btn = {60, 1080 - 180 - 40, 180, 180}; const int UI_FREQ = 20; // Hz -typedef enum NetStatus { - NET_CONNECTED, - NET_DISCONNECTED, - NET_ERROR, -} NetStatus; - typedef enum UIStatus { - STATUS_OFFROAD, STATUS_DISENGAGED, STATUS_ENGAGED, STATUS_WARNING, @@ -74,7 +56,6 @@ typedef enum UIStatus { } UIStatus; static std::map bg_colors = { - {STATUS_OFFROAD, nvgRGBA(0x0, 0x0, 0x0, 0xff)}, {STATUS_DISENGAGED, nvgRGBA(0x17, 0x33, 0x49, 0xc8)}, {STATUS_ENGAGED, nvgRGBA(0x17, 0x86, 0x44, 0xf1)}, {STATUS_WARNING, nvgRGBA(0xDA, 0x6F, 0x25, 0xf1)}, @@ -98,14 +79,7 @@ typedef struct UIScene { bool is_rhd; bool driver_view; - std::string alert_text1; - std::string alert_text2; - std::string alert_type; - float alert_blinking_rate; - cereal::ControlsState::AlertSize alert_size; - cereal::PandaState::PandaType pandaType; - NetStatus athenaStatus; cereal::DeviceState::Reader deviceState; cereal::RadarState::LeadData::Reader lead_data[2]; @@ -148,9 +122,8 @@ typedef struct UIState { // images std::map images; - SubMaster *sm; + std::unique_ptr sm; - Sound *sound; UIStatus status; UIScene scene; @@ -161,38 +134,67 @@ typedef struct UIState { GLuint frame_vao[2], frame_vbo[2], frame_ibo[2]; mat4 rear_frame_mat, front_frame_mat; - // device state bool awake; - bool sidebar_collapsed; Rect video_rect, viz_rect; float car_space_transform[6]; + bool wide_camera; + float zoom; } 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; +class QUIState : public QObject { + Q_OBJECT - 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); +public: + QUIState(QObject* parent = 0); - // Parse result - std::istringstream iss(s); - iss >> *param; + // TODO: get rid of this, only use signal + inline static UIState ui_state = {0}; - // Restore original value if parsing failed - if (iss.fail()) { - *param = param_orig; - result = -1; - } - } - return result; -} +signals: + void uiUpdate(const UIState &s); + void offroadTransition(bool offroad); + +private slots: + void update(); + +private: + QTimer *timer; + bool started_prev = true; +}; + + +// device management class + +class Device : public QObject { + Q_OBJECT + +public: + Device(QObject *parent = 0); + +private: + // auto brightness + const float accel_samples = 5*UI_FREQ; + + bool awake; + int awake_timeout = 0; + float accel_prev = 0; + float gyro_prev = 0; + float brightness_b = 0; + float brightness_m = 0; + float last_brightness = 0; + FirstOrderFilter brightness_filter; + + QTimer *timer; + + void updateBrightness(const UIState &s); + void updateWakefulness(const UIState &s); + +signals: + void displayPowerChanged(bool on); + +public slots: + void setAwake(bool on, bool reset); + void update(const UIState &s); +}; diff --git a/selfdrive/updated.py b/selfdrive/updated.py index 035b9a967..6ec0b4208 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -119,7 +119,7 @@ def set_params(new_version: bool, failed_count: int, exception: Optional[str]) - params.put("ReleaseNotes", r + b"\n") except Exception: params.put("ReleaseNotes", "") - params.put("UpdateAvailable", "1") + params.put_bool("UpdateAvailable", True) def setup_git_options(cwd: str) -> None: @@ -165,7 +165,7 @@ def init_overlay() -> None: cloudlog.info("preparing new safe staging area") params = Params() - params.put("UpdateAvailable", "0") + params.put_bool("UpdateAvailable", False) set_consistent_flag(False) dismount_overlay() if os.path.isdir(STAGING_ROOT): @@ -281,12 +281,17 @@ def check_git_fetch_result(fetch_txt): def check_for_update() -> Tuple[bool, bool]: setup_git_options(OVERLAY_MERGED) + fetch_output = None try: - git_fetch_output = run(["git", "fetch", "--dry-run"], OVERLAY_MERGED, low_priority=True) - return True, check_git_fetch_result(git_fetch_output) + fetch_output = run(["git", "fetch", "--dry-run"], OVERLAY_MERGED, low_priority=True) + return True, check_git_fetch_result(fetch_output) except subprocess.CalledProcessError: - return False, False + # check for internet + if fetch_output is not None and fetch_output.startswith("fatal: unable to access") and \ + "Could not resolve host:" in str(fetch_output): + return False, False + raise def fetch_update(wait_helper: WaitTimeHelper) -> bool: cloudlog.info("attempting git fetch inside staging overlay") @@ -332,7 +337,7 @@ def fetch_update(wait_helper: WaitTimeHelper) -> bool: def main(): params = Params() - if params.get("DisableUpdates") == b"1": + if params.get_bool("DisableUpdates"): raise RuntimeError("updates are disabled by the DisableUpdates param") if EON and os.geteuid() != 0: @@ -370,7 +375,7 @@ def main(): # Don't run updater while onroad or if the time's wrong time_wrong = datetime.datetime.utcnow().year < 2019 - is_onroad = params.get("IsOffroad") != b"1" + is_onroad = not params.get_bool("IsOffroad") if is_onroad or time_wrong: wait_helper.sleep(30) cloudlog.info("not running updater, not offroad")

-)vmH*%m<8gKGf~+McWnVC=`g0K(o(jN$CTN#8rRCnJ4?{rKqP z>&?apO5$Q|m#~6n!kVRTnd9i=t9x2z2gL+11h%>Q^iN9+O|(b_(L7!W?l-eaU8PHc)odmGw2fdBO>>R6M>dG3NhaqJ{kWPHc+^mQ zHg=*DVH0?ox||*-#1o2Z@hlyBstuY4*<82a4n*11`}$w4Hy1@Teq&%yF-kc$cqh~^=*;8U|ZiTHayv0_?f>%KysCFmW&L&$`K!QFPvY}AbCNdsgQJsbR2BEIa4_8AE z9hx&+?`XDbT|t{&e`NIx*%eoVAj-=`md? zOp5%NP9FkbBm{p<$G27d$8@wwAt1Lvml6ds9i6ta_g`K#CT3RaDk#Qy-=C@hQKbZh zOlQ1^3ptb;1!M!F`mw604svL&nfC8w3#BxD4~I0cLF_8mn$F==agA}fIXZuQBrV~` z$^eTTIh5QcMvqJ%pgic~0CO5g*Izipr;Aj5vm&!wEt>?j*!u zFa<>uF5GLGtpdR(shYp5IX`xRObSDpKHbG5MH0(~5vb-mTEbDLH^qcKWI;vx&$BMp zp(X={cfjeu!8%O;F{FcyA%inASW|*jb`XttZEb-nhpueku8BA7@9eUssc!&H*&MgY zK{x*TK%4gK56bz308VV%sj5rfg@(Go9STIGSA%_TQ?(hjP1Un(3qx>N@bBaFuwX zfiM8kTgKGfg68eQYHoozIkM&!IJXO~xgBB?uo7-Fa)1rcZ^00oL!EGT2(!5bOVT23 zYM`s}wu-vBMdyX^_9r(f z_U0B;rib55M_NbVgnlQM_CeaMqHrpmaX6HNnQ2K(lcRB_v$HKA=U{W$RzW$_>2HW$ zIndG!#*5fPxj6N{6471cW5Hyc?-rVKkoLu^_XAjUo_hxk(78pkx2o3<3)Z>4=x(-3fokCcNO|c2axhJA_nt+*5SnLFX zHozuw=k88IxwG^mcOr>J?$nrVL2iv~M@Z`MnJtk!OCGti6#OttDUX82;ZBbQ zU<9tNx-oKR=|=7>on60OyW@->shdUaES<=myE~D{os{9+akJxriIQ}gMQgI+a-O(% zlU8=i$ep6TK9M^E0?-(_lPYZ4BPg2EB6m{Pnoyh+xwGsNxl>YQNA474gd%q;;0_}t z5V=!Iq7kw7$en`WCdwmBj$23WBn&??awp;6GNz`#h$YQDTh`()R>`#(hR2t}u3;@T zyArCXBUf5>rKDE;UqgyM|vv-YuM-#QbSck}+KV)QD`5{4o5-CJ40XH!%Smes8iG*(wkRLF`@IE<^vInNE;L-!uOoMofck+N zwjpyFx|O~Kg6Ku`EpSBco^OF6eBFEt1hE_DTcB|EvCMs73nW`a?u^Jy;3n`E^_v^J z9m!9R+!-OC-G=K%LeTwo3l5lgo9U4|BTX@w(j#|9FzF>MDb!^Qhl<=;dQK=?Fvs@g z?$$xZcLm|6Y^zi-E@h-S21{z>&Llj2cw;Dn_l#q1>)5bC5ji%vZAg-C&N^CHw_aDS z(yl3RdoqYAeY(kbf%hRrIY9Sgi9&+rbRPz_Cw4EUa5UYCah;3%vB$;Mi%%}HzETv# z*MoDmr*Kck*~t3w&BoQ6Z2@#WxE65o?a8_T#(w+@AneV=7|tG?^gVWaGSWxbkB>gS z-fWDZBreu=2|IFU$s%`_h}>zPmN_vwOBuPdY=xr8ovl!odZ9a~fzCQ|XA6;RL2QfM zS(?b5rQm)utMpaE6j&V+;v7=a#xE1O^Ik>nq+KwJ+$laAJJE^U2|P_*?nLfvVP}@{ z$es5sxFeA}sR^;jos{R8f`jH_#|H04?hNb00XutA@Ws zFK%S*j4?5CXR%i{*B4rjzMD2Ee-hRB`po*YU+(S!^4T4t-D$epO>?`qDE75B8royn5k5LFW_8)jl@ zuA?n-XL3_aFh~~Rr2nGjVjXHSV0Z^y6&$R?^dCby*cdW6BZD<5a_9D<5wEQ^a_7L6 z4cs;HhW(vg)-?4EpedWC+;2CSy#E+}ROf|E=2gkvo$~-8yn-I_7O7cW#B* z#H>sRHkyt&J#uF{&MhN%ZiU!zp*?bEI^J;P&Vf!iyF~8Xigd#g6&Z&vPb0tq-Z$4_ zg^WL-jNB>xCLJH%z)f%yU5I-pcivTD7K_Bz9ALfd61g*-$)O0FLl7Op+kfs%i`<#s z`Yj@NCL?8$JJrRpLE5b&cMf)dM^V1Z^>C+CGziiocP6v5HFD=rbJ=#0JCo_}8o6_b z3dlI$F>>dRt=`T6O^)kuGH3>nV(=8yTZxVkH5 zkHvC)e){^$5yFU3|~v}SmK zGx9Qs;y1j{?&9NV&F~Jsx9f^J>U}kv7E^~vFT=tdF6p4(TQ8y7xtOgq3#kY1;Cr*8 zky7524oWZC!Wt^&B1X`dxfB)61(Lmymuw*xQF;$old|**@l>k}Ig`%6t#1yzA}o=Y z*m)(0AhA4nSFXKcADtXtHhT?O69YgO(*np7d5N7}rv#MW$5}op#$Um*NFGO!0Rd|X zMMkG`EXjgCpuylZP0c1^q}Z8OVXA7f+S6@2KV6sS_f%P(Xu-c(S0{^gal6cCbs1IH z`E`ksPIhYPdn#>>(`6yJW~#X_aRpg7%g*El59qDUtH<>cv%CID`Pr*4?_So$;c}V3 zXfHZk{?#?ezc}dt7axJFG|h zd*l5t?`Qe#>V&lE9hr9axGt*&oF3PeOc*KH#iW{+i(B>iZ8;n3l+&Vkyj6~WM5g#Fh=e0i6@Pv>r2kU9b((!>fW+j=P&h~@$=8T zjUt4jVX!p_9aiU`p(bL4r2>mk1F66lnNV($z^kug=$6T(5cn3@i?gk;6S%~Fnne8M z=^pbrO;kzX)lyTF4!;dKMYSD%g5L&zzK}wbMm?Z~)FeZ1Ma!hxhVz(ax9F#Xb+KC0 zET!3#)Vpt1g()Ov$D~p_yYA>Vs>LZ7ahI+ZNod02uz z6yL!c@mEN4AX_LH*20!yAviCVlLCxYQ!W47~olnU7au3JT?{ zqd8?X=RTVAJ(}|p&AGuQAwu@l&&pn*Nni74u`7p0CIsJV*kUuk#)djTzRC%ZuW|z9 ztDFG&Dknr^M*9s$q}RYq>`0WbPdZ>TKEozOVdhYOUwr3^=s zM2U&my*W8Ak>=1wdpBwHOkpP~G z<*G0UPR=J|+(KLxYU->_t3l9dBHW{zid)bZvD?jZf}ZXVimoI3l|TM!qaP^BlU*o#7a29M|cq) zMuexcJICH8mgNPuxGXocZN*D6o7LSFW)Lh;9%?H$fZWOtqTiM8_g<~5s~a34dP5ct zwV1pv*3`#~RA07#I3r6eZ4Ax!&|Qy> zz1tPhY8$Zi;0w9epmI1@QPgULn9XUVIS7Pt~*_?VD)C)EU||zx{G@c3eD_ zlOo&UMaJXy{d&Btr5bEoadfY)DgF6pPN}_BkJIFB)EhzVZF(c9+HIN97Y7b((VKyt z4SF0nusv@Ec6Y0B=)l%I4jkH;H$$fr655oK&ufA`uq@jwYRIP%`x29;Rq1P(YsI!g{PpwqSL=MeSt%vPrRG9r!dknpeg>$a zs9$T9{RGw1eEGHQ?A(w68T0*lRW8=&%VJWl$ol&<3TKQi06QxT;7A&o>u*}gIMq9^ zQN6HI`<0*>J3EoQQM8!finrG|v^iT&v7>()ncqHVc7T)4cO)oke_MZ1edf!r;tlP_ zBxBqb3TwmfD!U{+>cb;oxf*}XN7bX;HvanS=uhzcAP9Ch`g0S_T#16&ez4?PmW9_p#5u1XG zM=TEc>{GG6tEQ`8zWfeHqQkxjGhTG>i|D zVd)?&Ii1?d6I~yO{MbZIf0XMx>Sm?;dXR6*)p-60moQ<8@UpF-n_eyjg_O28FAMf8 zk&~VQHwhVrG+a(c=tEmxiJh>AnL$J(>J6T7qOC14B!)x$(@ zuJ~wMzOk))h+If*U2n&UQ6&_Gc1StP$wT^fXenW-(86s;IRLcd7LGc}(8B2_9h%&H z6m&bA)#*eEV0aF4J5HZav|v`w^bfLrt=CqXLVkFeRkrV!UzqbRx5t~Sr75BQp3+$dR1f3C-UsiL)ciGbG+jf z=4U)!rgm-o4CUcKH@TjCJ$Mtij)Mo)z93{&pwyf$k4n5+tz!`{_w`M^_64RYDT{1< z^kFy#5B(l_Ny?SeFWH#+R&;K|!b`g*T6-CBUiH~42~(r-ses*qb}=ih2ud}=hdY2? z)C#maFL6~NvXsAm%4Zws3e@F3ew`a%n(gDkh`Qq*^F_dTl;8j@@{BR8^0FYleo2<; z^~T%B>QS9uhA}&#m3{2|u~!eh@am1~@tEbo*@)gNi$++54Su{&WM*vh057HAiwS%i zFa*BHU-dK@5d)ll7BpnO;ExULwOIP3s2a#oSpGbLjwmkkcm;%y3Zegcx<~lqkeTqS z!8t5#4gp?!1?DuhVJO~CB4J_Rb5~5NX3l}U3*wqvIDtc zRGwwxmTF87&vq@?n6BYKh3kDYm3NiK=bzt-g%8{Ne2@MK^E}&IKrNQn+n1XOyo_nR z5V~@MT;Z^nN=@Oj=N1aC7;jZ2k1rfQUOmHq!2%5xs3QLG%U+kO-|@=&^hCMr2*Gey zvp~6582I$a7tYYB&Dj-W-40kGttR3I)4IgA{bT-8ZPxNankN}qBeqN!U{X=->OGU8 z4RT#~>-My@A>58UEWhw|7>c$=Y%#(d-EMRT(`2#4k@u>+UEsi5*w=9dM9gN{&X-U5 zBW(l8iSA&5JA(9q*-ZZ=us9SgjCO9e1Czv4S#4Gd5&!g&dEh=qXiGCOA&bAGcepO} z;3GO%73(7bi1Urt@)w;+h+l!W?mxn8rOyHFCeZQMxy(I>^MUyq&8yX#?nY9}Y6@s3 zA?`tUsc=kHh})CrHp)?*6)2d=Tygty94;yH{Gu?ZT<5cVfeTb#Ii2H|qB~zjL9IAk zOuuS44?_sZN0z}dgiBPDPmDQ`A3rfr^wk80^R=J^D}mF3>rtKSmpvfrF7bbtY`Rq^ zbNoVZp%fL0$^S{=rw<=g;1_Tt12jr>KNIZfflfKmSB`2M@ZPejNFksP1H6nO5qwBTrFsW-3Yn{+uctdw-dEq*twebG5I<{yX z*BV_Un1r~2?-u(J6^Sqkdf{lRKpx7#5~mCNqVARd<0qq25{||pRU1%hA@B!Y4b_N@ z+eDktrNU*erp2sK)7W_}Pg+Xr+}3s;P#9n_uH_C!e;Ov!BovrMgf{s#Ux-_RsQ26_ z0|CxQ3(P?Rstuo>C~H!L7U*LY$2Cn%+?O*hW;gkxt!8NJVuYfAo?=4+m5kS!-g0T z0GjqhTfZ;Nf`n53Xhf=k+gYHj!tH=qByju*CV&F{vyp~3WYm@L>KB2>1cBR!qdee1 zF+|*4oB$I8;mdH89%IfIVk`_n?XXIW6QRxVXN*uogE{_eg_N_ZwD`2sE2mcp-HKXY zT}lBI7VcI+eK?o`C~fAgkT5SLLgIifjY^n?(*SXiDY0(ROJqHDk4vS&E7nREIzcqu zB1sbJ7HSn#w?M1Bx&@NN)-9AGy>6K{Ar8PdcD@VWCei`;W|?sdv#5XUVs|j|B7&Nm#*N|uFYQ~mNNQsF04Uq(;DWwHW2Bsv<)3C zbqg^!b58>WHlUy*N=E2VJi3&HPl!XBZiG9d8<-+KyD zKX2ynu}32NtKe1zP9tIKD<|v28O|o>IF2J>c>Co;zPckrXSSnkU+RQt#6N9Naa<#; zmFL(LtJ5tT#PumSfB%G&eRZ&Z{xrrn9V$p?pqhw-=W;gt4H31m+txpA#Bc9%_@?7- z@dH52ZyN@t9pv0$$02{%x#YZ2)ZtD!VPnx6Tbwx@Vd#kA}pnMRP*8(6^HwFi6%a~Qj z!9&XqoD{GRqIF*6HDbsz_(Ehhk(M#NdEO~uk48Eu9JOX0V7c_cE@tWA5gW@F%FmaKMQ z%ZAksZmd`BpvG?14r*Df+QGT4svTNesgfXt{iq#MTc(mArA?|G)L5h1LA4#K9a3AM z+98eYsU5V%30ikF$h{Lu+c$~Hk(_9)%dF9n`)!=GAnE^7;ayUB65wj zaX@TKw5hIfp{|XtO}a)WOQrU75;jU&g9Do!$HE$Ik85IWY*Qy{g|)$WXEoCtuuL?_ zQrLjn+=76)G|roly|l461I8m|v}x@o*lSv0^c}Z|-W9T4wN-C(yom@KQjikmT+~pU zQo^0%nJumik9wwAsg{~`_(Fy=$M=8RDoMsgAmVMAb9;;P7x49?wK{xyMp}VWui)>`yqb_ zP;sWDQt7J42MKH?uPH>%W3^JICtVrduFx4OLb9e}g)0!ncsiADKpn0SGX{~k5n_kJ zNQ%C(AtBpWaadj7zCb%|#OuPQVa{I3u%*THvZC`Kapz2trM;V<-0Zf0FpPCB1K0-Z=UX(x70Qm~e+EVlS3#B&1C``6WaU8xAp3M_lIsFrgG{9ih{jn1HG_HuG0beS=T z3Q8e#;*yXEnnu3}R8~wu=`TTy$ik00hXh#M0+M;+XPrxe{7w=mipt-0{vPuGSNc0C zCLrNoJVAtWLydy6ujm938INv1sl*ytM%ZKxk|GP7Ww0V-Q3av^yiR4ny9U2cjYO}x zrudDA03_igEaDeo)18rB3(m;85h<_!Vo>miR@4a`hQAugD_Kksq;WV@?9)pGA{d|P z&jWJk6=h0XACo`phQ6UBv>*MTe${zzDMgYja}7nZ1G85IAi1H+%a0mGmMN@)fVz`d zDg%C90 z+*op5o=JzC)2SGX1RzE&&uJ)1>x5bk)F75jAu8mrn#O&VWucR$C}=2Ei()9KKB%OY zalCCU^3O}sgT#L$l~z|k6TwkcEvGAkM}9I)Z&6CYIJjz1)slRAzrlTSL6ZE<@Eph# z!8eeszZislx$R$cuOBk0Uagf)iHfqtnxzuk#5(a6e4-!3I`Ow=9j=e+wMQ`% zF>7^-tP$ab?F588)(NVNb$)WC1CFd0i} zr-4akg=)cgK_W}wfUiut2#7#|HN?3AnjZXN=}o zGg_(Uh&KO-f0v|T;qSGWOhvV(puIesWWMg2M7H#rG;8%Wsn!B)QmOmZ{EGfI$@MzQ zQ~4Uo)2-E$XD~I!pk|7UNz+z9lc249b%JtBHVII7gcO^Exl)Hrf>DT6NA0Qp_$qFR z1iMOQQFq8fq5%eDoh}+-rDMe>QT8-)k?1H_3KXeayHcqErAXy)0Z>V-`&Ek7`6|uo zdQE7ibu0y>l`QpX1VbtIvT=|WT5ow;EfhSJi3CrUdX$^;FQd6iZefTBnbf-yk(xPb z2>M7jh3g(HIkR;RmSbrey8ZO}4;rTy);Cgtdry6?A$+|p1m&n|ArMbN3jo!s4`-KA zd3Ykzb$GI+;#e7uViTx63#c<8Fjs*I!T4HB2+CGe0uW3Qnex`KbczWh^ls5@T0GRY zQ>rMkXfUg>G}BU)IA~qOB1R|LxY(E?S;mIcCgY9KO{TSOQVSkaO5BoM7YUZ#S1O2G zuvR|Y9IkXI!Y!>sH=nB=Dy`N#tPaA!vaJMim?K$f9%>6KmO+Jz>l`YHDIFT9);cr{ zQ#(`=*DlOPT~NStLV{E0+udbp7;IVz=oUQJQz&?*t46%lYJ?Q!`qS19>U6$3)TwNN zs1vOsMBZ#i9lb!XT&TyB6I)|wVbt2Of>O?>~)d9>+@nDQ5P$NRP zC8eeb1Bq7Ic#rt{LS3A#3WE4xj%b0MqvstMXT(H6du95;C7<4CJ|q{q0>MQvSr82S zrijz)a)Nlu`Pub7m0fKRCt*rqILIAzaVvhFES{=|f}mvNW%0tx`I4f@uhlCr=IblP z`Zr%+HpTKqe<6qhD5228BP;!4vMe9hfpi4_DyBB4 z@Vi~+f?d?{h~QplzMbH%=jt>3GSLC%x9BGe4t5`6{}Dk0vi|Tv56Z<|fmr4gKphj2 z{_+9$CKN^R{LL5D!5(o60IOXLVrRXiFzxWjm1q7o%{y}ujr;881|1Ko`KM1#wqL;i zSiU}BinvLEVtbED+)N=mAy5RqecZ+xdMrzv-La%Vu}rpF zmtbE3;Ma9~bpaV|58TAy5QDC0_47q8mA~!6H7tpByNRXG=xl zPeL4cIhoQ>EmxJ|^%4x({@)iZGk z$`FdH98IrGkT|}qWUmxMup(s#_D)ZA*RZf5UAGZGe{BvFB&p-c9TeWAv7=W3Ut4WwgqdLnkw_9gYuzQES ztSEB*(xkSN%+Y+adiNsM@Om-zGd&Ck^t#6r8NyAm@*D@wIyt2PE%Bm|D>NbGLBMRM z)H)nq&ZtR&M2n-(y}E;h!0zmP`K?$$!I*q4Ao>ff7iIf8U8h{Uxr+UVxmoFrsB?6< zSyy!}qvLW3wz35A3?dudgm5|7}xYumk<}U+iDS{@bRu0OCD*lsx#KWVSVDWsBlj>*(VEGJTw4 zY!~JS;$WJR0mQH6UgiobVotg`g0x-j9np{Ah&V8CW?VKGpjRhrai%9t*)YOwCv1Ae zIL~nOfyqKD(-e$y9PA)W0WLl=jmtwt+sD}6A4XXy+yC@)Kx&bJ|tsD`^>*VGm zHUnQp5jTlA+JJ)|9-=UvW172~L9w9#(+yXtz<(T;v|unx&zFyQ@s*x>6P%?|*})h2 z_RKLxvoOyU%ad%+1{_=0kkX16pYiR$)1Zxe`F7xG(37Wgj1j&7+uZm`EV!r1$mnev zj%`A_fuBM+(@&Rt~8G-q#E*uvu%8XYcP zKH`S_CciC4hu05x`CoX&Y;=YP!mH8YO}@lG%km+I-`nVLj&_!l(cy}&@vZ>>f}_WL zbof`Xyw1z}d{K_D$lN`YOZtmTnxo^ts>Lmkj^3427JpW=e2!0C%!TRd-DY+xo=wBA zr9k-(#;oOLMKl~?1R;j;=%~U|lN0*!S24L89itlDyglBm@iB%+9bE6$6@CFB6?>mA zDolHQV$URw1AvOZZ37wzMpe}B5So-vDvifZv*5!J$reBX`{xCX0i>R7^ z;yx@27o$_KYhHper}IG@DT>Ojo3k!Tzs0udWe0?YWuI{irQqJdmv)mXt z_*^`K&e7*;`3#F>zIazXz?*G!Ho+ZURCEra!SVA7PXyfI&vL!F-4K@Z&Eh`4hP_~e zjsi2jR&&VBo%~C5ech}C$1d`Dh0hBJUPb?|9$-EkT|kTo>TCt;9Xj9wvEyM_TwGLm zVsCW00$cLY#a%`JqBqcli)WaOM^JH|z+C!Mh~{6QUeJF5CKH7h&jt2f_?s`M2oQ=I zF7x~H0srE`kkMs%3*+)jKDvacQr?RGjxIOL2UuSLbXTsa%r|&8Y!ER0VVO%L-SSJBR5^w0av2*SS+V)%POayEW0Mt?v~0Qn(*&P&0d7lcFo z{F0+TF_32EW4Qpj=W@0B4G-6&{)>`&c=0bt?qdNN8sYVMokiXDd0Jc}`YpAL^`ZI7 z=OsA1tR5;1vlZN5E^~<1=>2Av(;#@*yll{2^J_>Y!~z{IN@}E#D>V5Mj}R6!^bQ(- z{X%tt-iHc5-cgC)A&eE~A@Bur)EKx%pCJCL7j){U{GnPPCIU%3@sQZ?t{@Hq)dp|d zPQe7g7pVReO5frhe8qk{N6E<@IvSlZt8Ud;Tjh|o3NrI?^HO3uTx~{|#fk(QVtZP> zEc2tg5;8OT`b;p@2%mr^KeZ(ukVH>SCeut3YG#AtiR zA{M6ECz2n`SH~4*lF=C38cbT$L;Ck={sOTc!;B5b?FCkY+YK=|U)~mY?irE9Up|$2 z1&)IgnB=KP@S}XBUV;o(=*Ec|NtbsJx3k&w1hRZbKQJ`V2K=BYi_*@QInAeLI={%T zb6P>bK3abus~8X$FS9$$vS46&OtV8?e#VS__)x)X5u`of&4LjQoY1o6RElW6sAUu( zaW;@UEyJf9j2LPXH3sO#H2#eOCFzgT0s@9k{Z!rM&krC`tpul-M~Zr;r+MMyW>#SA zW3gR8*2S+24C}S{^+&#(J<@_n48l-EyFOuF#lDPQoJJ!*VNOGj%8nGX2Krgh^I;Cb z`FxL7egLnFzp%Ih9zu$_`BR1Y?Gnqx9AlH_2P~^3UWYgyBHe@Ru7;n7%PBe+3oMo( z#p}_#yXs!_*M|}vb~}4{yelUkH_ucB)@Udx%NIgT;`Rw^J%|*_#V5=#pNnVGjr8RB zk-8njDaZVZzfc_L6p*G9tUM3sF`R!Q(~yJjb7(VIsxbCvb^5o(1eXk^8g2!J3TULj z-%!i%Ht1jIWG@9C(op?zgvq87V*xV@hBbOt=pCP`*)$iL2gsCK!RRa4k7Hh1MMkSI(9{WX_d!cyzY*7QXtxdH=kC>lNu`hy)AKafxqNkiZzD{V0EP0 zC2uih&q^>&E$5&PQ}JKLZS_oa!L3=UGxp(N20{y0xXVRS?fbe~eH3z>%f9ZZir-PR?-J$n!B#b|g1s-I_7&*$J zzAt385DvK-k+u(c|5`k5u1Pb-G&aRQC011uUzESYyt4+A6un2)q*A|u1gqj4gAG5h zJb_tau7*+zMH8b;d{G1cf+&&F0Keh~LjWEM$-h!(o;;zIM-}7->zI(I(Gh7(M=y^M zQ@IT=1RfU)Y(gGJ$5@7-c$Aoh=U8ijM*pZALsK&zaITi4@nnO}#9x}}N8{N=K6{c0 zh#3YZ<6-CD@Zfv_#Q{u*{;l^Hn8okP3S$!cjM)SAn5JLsJIn_*A5fgcRs#B#7$Co4 zAzQ497ktxJ1o%mxl^@WhUobKWt;p1>ukQ4+SV2v>MmPS30Sd6+iVDj#{UvqmW%L`y z628i7$Tn%Uv}9pWn*9v@68(=|4KAxyINPTU&Yb>P7f_c`STqj2D_DPt+A;0vm+$)VvzzX{3 zPy8cxQlpdA5__-_?TlWqFPdW^g`SW@b%(Y9?+>WDVrwMk39*XM#;Cj|#b3;rVtXW4 z5c%^Isst&8FU#APzeKT*IYd$JoG|fYssSHALPMi%#mDkmOgZ?AJ;28j>eRY`k*UCF zHk&J~Nm>EI>^%X0@UPr#;nx&P0T%Wpe$H~td-Ugp`Vv2;P~cbeLnLEO#qLY&x-<{* zjaiDqmm>=^KTXL5ML$bO`zJi1wZ|!#f26EvFy>m z*rtnJ79RlTC=FE-OX4O6DQbY?NhYG>WdsdiGdibb`w`m}aQ(boPY~k|Sg~w?X1PU&8u^!Zg&b;v1gKopY}!2K)nzrOmz7{ahIWGScad+VrPNMnlT%nXpv<*8H)4BYurVL4=$OU!N zXJ}EnOR!;v)L$&ikJw15mVLl34ikak!8uVxP54Bj1hd)b0%A%V-_ZqB4{Wq(miQ;N z8M`cl^_f;QR3$dzP|mTBTw~3ZNiVbnL;D1)@dw*-DF~PO0!k8PLEROQmlf1vrTb{P z6#)PZ(@(MH3s3VUs)6^@M)SWcmZ!iR)FmBJ^GX# z3|mwTpV7YxGIfxKuzb-}{#!0I|Hh6mzlMq6h{hF-8&#>8XGm(v&>$=~Qb?dEVH%kg z^B4IoCpemZ%Z1YGusy?Q!RAh*I;0-f6(5(-kbZ+^hYma{preBLPf)T*9i}wX>3xrqS1q}?Gb?4U_RtrDGne=>cbcHi(yemk`^x{Q&F4C^{x}2zwBOpQd z>rXg6!W6JpnZLp0x_P)O)#nAB^p!VdG5vu3j&Oqncd;)fa`IW7D4M4L^rB-50Kp=^ zy;Ipr_13x2kuk^V3bDa}0jMYx>~Zk~`6F|%N>G}XCSFZn8W(9c4+`?P%{`=etqXoA zu9wBL%G0J+^?7;+by)w-7o-yDFJWd?AJ7=oFR_?o&713Q=tc8fqc~fZFB$=M$K^~x zT^2Kpas6?Zqhay>^Rod7oRPSJ^ z(Dc5;0;l-|)f?7k4Ya}h!OCpz%Bji{TLqFnSfNTl<+@oU$A(~R4PX}5MX+(wKPwnd zH0h+Xmz5SdZCI%{$tzU|Ix=Kaef$RNHB^}z%WqKC3`$7i?M73CkIkaeorQC1Qs!nD z1f)nRbU5M{;wxF^mqegm)Ikkd` z+zhRcBxtJS$KnxY3;jXnHuD?XjpaN2^+M+n=7V;D>I0MCl*}Ibv%uO^(t@jd`IE93 z831WOf=0K3GOAKPKWLsolfv@*aieq2ur1eJc{anQ??JZ|-OprOBD6ocyYh$%{?U_~iP9MNfJTnM{lJz`)%tJdY` z97aD?;u6yr%)<2-wi?g6I%2ZsF@Do>ZUAAfQ@^2kkm9eKgb_;{Wt9mFE^08Mbd+!4 zP>m)i^NDWCJ2Gkgp6f~Y7!gM*%vuV`7<$^ueEo(E+1kh>21ovUCk$l@`V@98BLFyb zf`}fftWN+&PiV>^m&zcg^T`qiTYmnqF)%PK>0H>iK$aJTQoZdlEc*Y8+zAwuqnZ(o= zo)3VSov!HkM=@GbDJWo*E~W~%Ov2 zYAp5IZ)cF+plJ&hYbVePA!+i|7&uPy?YEBV0QkJyk!c z6ueL+3Isl(>lwKsvSq41qU}zFfHu45~(4^xEHb!z`iL{#WC3~eFGlauf18*9@41XG6 zY92KJIecn@ba>SO%J|g)#d+2MX7~nA=?igl3X9Eilx7P> zt&XuzCjj%?0?BsBx=h*(9b^NHe>#u|2mo!=K=Mx;GDE01Y|L=Tn$LieeOYh_;(#57 zP=rcPN=%+rBzsG?jVbn0ivkv=Xz2iyh3CyQm$zj6idBvUp1r9N9!E=hFg6avC&eqQ zD1LVH2P{-zjGaJcQ&bKkUa_LTe-u*~8AJ+Pc*GC*XVLcs48k}7!w=ecI!n+qa3hhf z=IWoLFCSqG{pHL0=bw*t^)k+^URd_?`6aFfqm2AvQNI7EGvyB}GkY^H@)ho#kt@Q* z3y#Mq;+>Z^f{P8#k0k)z8W7f)Zx?RDsgs~SKe=_-H0-WHyu7OeQx594zHy>=v%bWs z4h10kh*Pso4NLcZEL_kYgnJ5`i`;zS%M!~+e9R4wLKc&kix)UdhzlM&uV7+fX=+{_ z*^qRyCV);>xPnB-@Kz!7d0eg@ag0dg#-z!*BwmZ$46~fUBQ(D8ceeh!nQdiXSXsWH z1*%!4gRav-%XCo0gw@-Jwq{K`f!Z2afCV?{Xc?$Ls|RNG=0<2JIAy{jmW${i-^=|k z?_mgCozSegr_+^G;r%DK#7Kj{{!?VHUcE927bjofOSC5A{&HnfPl|~WC0&r2`<1hzKV-GYwRz`e~qavjYrH07jHLrHmv3Cu1(ow!lol5;Nj~DA|qkZSr)F zIh-UY0T?=xR<{zN(+Mf6ZEzEGI&Q@FkrPM))qs^7!8F({sF={rl0;4mJu?yZ0O#Fn z>S)c91j;GwjxHjsTnS}%cHKd%ua)CEaz^((M^fJ6W7!_t_QpNSHstak%zUI#u`g>) zkyo^Ao8>~>!4hdk)c3XV@=_ZRFohrJ8pg)9sk5mPQ~0&AVd_lU2EI|ILwdMQm^yW) zRdP>SM|B<*+?R&h@yO1yicx&HXqaG9O5ub8k|m4P;SEkcj;pmQ8Oh{iQb)Hfg=_2eM&#b|4cLXQxEM((IJzurPZg z)EMHj-Gw#x!c4`##T;b@QugPjS{KURUhlxL5a0$rvV<4a#Txg*#v=wgx)7G7<fHyaeY7}%AXo? zxi+BqsZ!yir&H;tNQFZbt~C)>@k^x9nkdu6FOhasE_FrpOTx`?NUiH1s}GU$E}uL| z4C0qegDwDPc~KWGW5|eog3FX9e-I7w*AWb)`uDryFYKu=;5Y|bFOS}-Uq`rF0=Ll5 zq5vH`tZ)j>I*%mE?gf2V9?DSX>UIJ91l`W#da9knwAE8P=WR~ze{1LxQ1i@hpU`Xv zYR{p8#Z%qvQ;ZZF?>^Z85#~qOuJOaiNbxhzC6K@-e+N*##r*1;S5h@CK?6=vphi*)*OTjSlm^;eWP&C;_l#kQ)c= z4rnCD8<)MsLZGmIgM%fGWe{cm916p5RlJ&-D#quW-Zt9s?0hxbJw2pz&@R!Bg;7UBZ#=U(`5JyT0GC3#*p(=#i7K)J5NX z3FPV^CVr-#j#1b(Ralim6>#xdfnWS=Ib|ya+0W+NFhAE0(C_EtIq?;Yw#r83=Q}UA z`vCTn?SXvjt#&`(ijEXuj{iElk0T2_%N~H*DOcnGT1?3wjw~Iqj^>l7kEc1;4gTYo z=g+(c8oUFiDRnmB3JM-7m$pP7sm}6q_H*3Yz&wZc%4snUqGKJ#AsU$W=5bkwisD!d zNE0o%D~d}d<1&s0hYb=W1r1J;qV0z4;)rbm>2CnS2%)!mVtrz=BYl=-viy5G6_yj8 z&))2n1R~GM7|dHZoEME)4hW(N1&*dM>58_-8gZL~ukQ_RU4i2oR)K6H5o6snzGdZa$J;ASSA9vnv_49#&Y~pmB6!9(u zz48PVz%OiBzqZb{UuX7nneQ9@X`hyL$ku1A9Gim;FF zT@AH08dzs>iMAxQz5H2g$0XPE{J|84V>%aLVbm^i6;ytBv^E$DCw*LX8-mr8Y=1hL zO2IO7|9}7_H-<=bhU?8Z(RwS8o#YsKo7*gxv6C93wzlRlc`?3$gR{;h%h)BCb@BC) zJ*LA#D_Spi;uPfE`E2NHo^kmkwT5!ObAhUfiSB?*5wj;@;E;ZGiOww0@EbiD8FuCl zBOGDn;cIYQ=GGQLpD+4y#6{D*J74T}I^+ILYxh=eWx#%ih3mlFl5tNXdiYlefR^Wr zC-X)B=~F>|`qYAJ`j4J)i4zqhU52U*nQ==8IHt*$;Xx&o<6fw941h$;gG^5oNCz};{xso ztaTP}J$u7c&E?nj4evTW!*F{+R_eJo`~-TPAXXJUDQ|Ot7<&{TDn2YGEqqxr7nUJU zU-tX_U|Yo%!jH9XRA^%lh-~yK3eYXGABj?9*wW&TH);40xWcV^4!&a;1up(_04Fj( zhKa$i30#84*9k{6Pf4N=Cq4H60{;b&6CCn!yLb=o=p3^V3`!>!W#4}fg*B*^L4t`^ z8s@IKafXR(qm*GGY`7|VVOt*_9}UTUa)`j~D83Q2%^e6rGs;dHGTnkz}&v}%Mb+6hs(&sqX=$O$^)y`QfCSAtTs%T0D@;&zuJhGkWZ18z~>K(l82q-s$T&h zr0|~);O+t}XMr;xK3JvlAbYKCtJWs1wb)0m%%0+Y`ZQ2vsFssVyab|Dti-C%XXyip zh4{m4UFCrw4Jf88H1#bdboSdWx&7wfDD&6QDCR^8_^IdwmHhW8qEQTco`_1&$K+mO zmslPmqFEF)C^+(==$Bj!4n@@Hbq>iMHK0+npm8WlC%;^h&LKY?)ewOk&R2pF1YB6* zWsV^v=tH#NpA7LZ^Em?;Et5u)JC5}c(JOcXWxDhd>Q#)MOq|Cx26DcAV6-VM!a|8w zW1ke}gI%2&#(o8W7|)a>Yqy1T+*a8EMRSZmtGQ#p0-DS%jR|YDOo)-8WK8L)b#WmZ)NJUX59ARd(4bqbnmo z=Rrc7IogkR<%u8OAl?L%bgMU-TKI~xb$Otqyd<+_!npz5Fr)3rV~HF9Vd9P&(~B@L zFa~4%Y6*z*J?c<@o=l;FLO*hZ18o`yh&|>X8;dR5QW|yigovC+9q4O_ogY&$mI-#_ zHG)cg)JF<=!l)(@oDAZdYOo3K65SV@H3Z_7loLzT zB0Ee{YBJM=@5-`IUYDeQu++ky8)CGpDdH_m$l<|^Xu!G>`QoCEr4)HA;q3~izlpl! z`&f2wqDY7s_F#kZDoXg+MQ(7#g=d#%bL~uI^s3v3Z&;XQgSZD#H{V(nYMqQcV%23% z#obr1v|2zC&Ev(cftM9S)EYj0sx{%ur+qa}mLifs%t86$hdC(2WvI_HA$XXimykM4 z!X-owvv7tuO29A)7)uxCzyi_29GL0iN^v3y7z-69 z!D5NRBv@XYFbSTQB}{^^AxM~-V>;VduD{A4xvUO!IVPWWv?MoNO#O9!dpY)2`a$7G z`0M+o-47VX*so6eomiS9@s&E~*GckUmM_W6>$r8#of} z)AS+s7bvzlD0`^8B&vZ2*FhlxAMJq9_&g{e`I$L5 zK{9Co_l?!34;r3ktDN`vG&p&{L6^_DRf?R}$*(J=VPyFvD@J34nYwG}Il7{sy0Z|e z@9l|_GK5(MT}=YcQk4)igq+u_WbKqNe&>>OH*vx8vuSNq?H(m+Lz?DrOQ#Jf?dYU9 z4QboaNv;|)?19Z~*yOId6c)RUF@iZdJD245($=O2cUWF5ul(bANGbv1le7##v;q2y z-_WbZw$~t}Vh<#Lr2Y&kVZIx$8db7H_)x7DoRert+h@D)xm1)PEH>DLLZW@ttqrfn zI9e08vYaUwnO^FG;p_8hd35Bv1a$szl zU!%Ir(pB2DRf?A)zo&MzA~7J=EE{P{YhyBH&C|=2bgw!eN3?0#tVxDbEih`oqE~_9 zod1&eF!`Z={{kjz*@B^PFbEJDJ|@Auu@MY2Uj-c8{lYLa1k}88al8rB!$6_WU$2SN zUmemVjcnADUH|$@N+fjwDE^5N^Sw?)(L#_;kLLq>lq) zvdlSx#9-X-*RYdY)P7jvlXB$wb#ZRlafUM+AaR+;t zWdW~1H!vOg0JBB-1L^f^sI&4X{O17@Pn$iM94+7_2QQV~0xo9Y=!ntI%DzD-P$Kl4 zz$x&8P$=-$pi%fIf{ImUJjV$IZW zFubo#?`zBZ+V;M7ysusFYfrykeuY zL!_KKScQ+GX;>|1rQ&ish{D=CaQnf)qb8wzVDe*r4SirYte^5A zP5_+x7KlRQt10Hp`6zV%X?J%(}VB)nLo9~a;T@3$gc%GN^=gawn31XRs z^;nDfVmO(z<#Q!<2vfT+NIXI?=@YC{QURm+O`m8lEhJ4Y&4L#K^C69EKL{0ERS{UQ zj}H5NysC7tnwk4RGT{XB3-E3TUwp&jAIpqXm zcTQrYDx_&DcmvdorcfZSrif`hAx)L1OT*x{l3SYUzK=wS86_db&FBbea!y4^(=!@E zHaV>zq{+UtPE_<*Y9|J%(+<*Xh{+@GT`CEj=~?$JIm)UwF?^qnuw7}TN~TUr80!UT zit7HvIGPe=l~)Q-rOO=Z=6vNS9NUbO?^S6dEM_Q?`a;rfJNeMF=NrcN2i z(h(gKFtxCe#x0_$>Et?1AkCmg5lBI@dO!-0Qv=fUycUo`)G7ff&}tnZg{)NpQlP8` zkOJfsfHb{U|0e*-sQ)NbTKmVQCY66QHL3ffiQaQ_G=Az+Gm1Y-+B?iJ(>bD_((F<6 zy0oOyk0MrQqI9M;nmKap3^jg~a8e;h6KkmAHa=e%eV<6(NAYWk=ahXEIjQTTiMkq* zv~$gB&Dn3desl(GKQFhdn zevhKBQtwf?TJ0VMN-FngqAKrX+LtB4Q+lR~U#r=Z0Ll)Bdc7W{JU{0$?$>f!K z6e6k9V-p>no%r;!F2dGB@ssmISgn`;EyzbSG#?v zFLA+9If#3hj~s|sN?Q@Ot3;XOLI3m(UrLf`gTc={!q|!=Z{RVa{mz5c(!g@q;p`!_ zY@I65O5%J0skQvfi)+!5{Jp=d)fg9R=7^XR@)u1;K#!RHvR= zM+tc6c~bzmkf=214YE~hw~F|lG9_jS+}n1#y&hg^t+IY+(Y^ZO35wcVeDMT68t`FG z-4ylYhyLgPDC{h&-`N5`2|^Q&^8e8(Jkjt(!p04ib&;8AguvFywCo-9>0mMc(ksjw zxvOKbMmbMO$puZ`6qqMKBj6FaR%l8Yz%sQOk)96QtUJ>T_*j4;hiz1I>$+|T8$5U^Xp{FYg>CZO zMSHM+F*Mk6!U_2NRa*4cWs>yF1H|~L%Vvg^NTgqm3|ji3%Os}Xxon0c9Vq9Akg9*w z3R5$WT!wD$jmsowp13qM{laBZGY?!QwdQ?GA?lvD6lT@ymVryYUo}X}K5ZG?^vjk> zj32g4g1%lw<3kgoKFpfBGZeFrT0uIl6zQ>UAFLu)jGv)V^XFnAMM1 zS{S{ER=mAvSZ1HFl!mlvWH-(v*FIqRFq!u&1C)Ng(!}KJl}SuKUYWGu^63wk+QiJu zm7(h$M|kB9N1Jz-_4BPsO1@f|JgXy3GQ*nJCBCMHPgdG`-u1#SXhl-ar+#YkIm%Ft z?lL~Adw&TV&V6LcFBLA-$|WcH5@ky2yfTFkQ89$M1ca3#r!2C6hm}dcGb!Pu9XgX( z^9E%gl21?#(((^bHtTxxat5sS`N_Z}U!P1``td19%=T^V(~}|Mz~r_*?@6f*wPfmuY^QaUp{Z3jqZtLHh4DIxDlP0EKn=~!;*ksa@ zZ%tlW`jC@)X{yk)XQMWV-kIzHKWvgFuS_Px&-2JcCCR@raXCXHahiY43zG%;91l!s zVyUCqde2Krx7q8GLN|R}GVm+jmXzwsrzK~^2*-||K`4?m`h*HUhH#YGK?D$oC(=QZ z-NS}G5U7-4!I7r|Wp05VnvRpqJbWneN3a~1fCV!&f`zpJjnnL5Tp^5-m4HjBP#jfd zqS3G#5h8O`3<+*)2nlly8ik20ZRlFW(Ky#2j>h?~bS}Sbo9qedvMWTr>#b7QF7L}8 z3gD`~58iq9g$_t3{$$oKXKi?vE?J3M(f4}8vOE52+CC-y!JuFT^ZDz0-K8UC%Ves=)IXi;oKL?}D?+U2edRY2^@aCTd&AqL!mtlBc zUk`hmt`O48>mhn$VLeoEa_B{97B7t$scxOXVr9+X!ZmtXEKnQMqa>?*u87@WeP*P zH68b*yFmR2Pa5;d@V4xXy7L?A(;ZG;?fgsN9_jS!d(NcFPTNg(RUy55*&Pjrv<*n0 zf+m54my%dHY$M?Yi6lVm^0W*e%*k;ZE3-qzTf-G4_VC1NY7FC3v+*uL7Q7%0HI&PS z1A@F4Fia(KL7xsCTyjXFf?~-|V)fyWBGa>$)Jt(cRed|e4yJ?qa;SyUutSMlZJla7 z-g(_mhtBR@NeY-Kj|3_T)Z!l{k+CK0pl-u=JqZQSPlZOdd!AFm1!YO0Dvge0+`^>% zzat@n;!q)N&n9jpe6)bEo1TPEE`|fB#5&pU%-KPo>0>8hcffcknFOl*sY*grN@p@~ z#tsB?%Gpp1VA^m+fXB{P7KW>6Kb<1%L)%ZuXwacTZ1)p|U?TeE(7-sJ4Q@&}kwZ;v z*r7r_d~RWwjQw=zv^Fj=4Em=7_|^rb>cb&L!|r7T#k8t#huGc?sS=N`K*)p~D&!3K zjY($`=EK34$@v=7fGdTGO5x&liRB1B_qwneIG&%wq1$CaCRyiDE?>^zC6CPvew>lC zMsb3{1?9v66n9}BZbBC4Zp-4?_(6uz+sSwWWnbt{za)#s^9Lt;T&QW#pqX&AyP|c* z`z}sr-_Ts1N4r*_fT( zcjwSPuEL~I`s$c%9V`YgsV6j#@PK_)&R}$7Hs}$;`SOD2eT695AqA?T=oi4y8u+%H z!B@tW(>F3$OncMxJK)yho?uHH{AnA;&PwhcyG5{*V;`~(S;;v)us2`KN*ReJ zXKZ?r?W$}CanzlDRPmOk`wNIn!H4PaEBJYu^~}fd!@6}MHJ`s;@+%#N7iyNoJ^>yD6|H^b};F@2$~NEzqL``!|VyK5ujmbmmHSe z^N@S3meUPRi}vy@F|LVOiHR@S62A{!c3iT>?Gm2V&6igIBY7wYTA9Q_3ALhFr&iP| z=G0|EPU6;0X)gEXlolBK*8Ie^1DX0pHTT|Q{?js6#a3lS*_N>O0OM z#gZ(LCG12y&|5Yd+VLa;*?yk((2|sPX>&fZx?cR2;&H6xUJ0e@Q)Qdh;rfiF~-1S8$>Z2Xhb-$BzHlV zAaocQd*&mR?o3dN!=^T6%vOvEyKT_1|Ez?BIL;+}2cSQ+V88fGXYB)$C$C0KrfAsX}4|yznh6Zq1ZJ&YM7Oe81_B5S712s=r{4>xq zyf)?BdKqiJ1lqu%UsDbD z7~SK%_yk&;;7HABo0wvWqGjCqj4AEXp7MbnC)A5{9tQraql)a(mC47Km^^5T%t3e7 zBLh23Y4<%n@w|k$Y>kYGISBBpog%pdY>yn%`!I=V8Azs+sN!CaoY{MI#OR{|XcA(I z79~e>7nUmfA<04_V{!_u6(vta&iKIQy_}J0tW)@=C*$qZ>wZj3a}Tb_shQF9roG8I zImOh#Y5{`$H-On54hK`HZ+PTPWK6N;qBNqa!!y;@OwH&Pp#a!{t zoC*e0(Hxn*I6b3Rk=~?pGKmiB6^bMCFXc`q`E$>q>`DC#fm~{q23)Ra%ZUFOtG4Hm zqI(6Kz{1GUAhnVM(n^WiSJjDCy0pUroi3khrJG>hW*v%Y%>)M^sd(U~^GS^q!RQ<< z8TccYCIQ(|L$Vf^^bCjrLow#^Vu0dNY|$}sVzg+jByc)6N@2`LO!WXM@_fq0lAugZ zGWHcCw6+O@R1(WzO85KR`g(e8GnERk0V!F)0xD6>TANw|e@TG`jGK_i&qt)(L~F+H zr!4(u6cbP_h;)uIGOGS?A_zWMV_l^m9V#opbXkpw1&S>WpkM81`N$?$<2O;L)H32z z@*wJIrIvw!*e;37&L%^?3h{uzeiTF{in&h?s#)=qc-#^suz)(T-mQvgu(&u$i41%l zfS`lX1n@$|s)_U@Qhg){wa5pT9I(vVDi?LJ=n32)v2vlwi|2Yn-tna zsDF?Dnc2N(jDuEtlM|y$nMTo@h~(Us*~%r>)Gg$M`p_VBqBf(b%@}Gkgxc)i2Y8!( zWeQcqaXg3SFe^O!xgr4zU|+SK6k`vjQ_Zqrq*qLYS7-;ynJ-SA=vLqA-DDTR*=VP4fvlR~u0&Z$I|Wl5#^!`*{uZK5h4?0#-l;@nt5(3*R4 z6Bw;X!QI7$+fxnp~nFa`l01A6(*% zw&-47(x4x~h&%pl(w{B*(;v+6)`fm@p{tcBh}G4I#JMbOoF|_#b?#FMN+BJfU?9@K zaA`z?BLp~r(LM}Dc|)?{WHx6s2o+F2V#uw*oU1^LKYk(gz9V?`Rr}%o9b`a?5BG{p zVJaH^a&8l=awDTH z5*uYi&s#gf%y4%9mQ8uw;zY}#2;Ur{resQ3TFfiLLXD1?#nVmnR#iViS5_3rO|a`K zoq)EV-NWxf@eTbHKjFVW<-Y+^YfBbkwlj@)5xyN5WG{v4=H>>e3GgOhX?%jGaMI?k z_P#URtK7sGRk#}GOdvva6C>0ONqryY3Em53Tct*Q;jZ#-MVyu1jdoXiFWy=4-S}wL zcN4u`*G({o4cDeXBH6!PIO}D6R!LyH=aocq)o)Rg8S?(QB|*YFyCl;6EiB3=cZP{3 zoH+zy#8fiP-Ug955k^IF52I0{dmwca@w#buFb#&|6Qf4hg-$2+zmDS|!X3duDm#i3 zbqBkN&^kfyrZytX|A1dr^*m-j;wA?tg_yGJ9TY2*^Chr8H!(i3xDAuSh>j_%5H|7T zHNp{8W%k|ALYos}nTn4DJ?O7!xitj0<2Kl#kNOA>(;hFK0fr$~sBq+AFr&Q->3nTnP zNM1w|hfU(UIDSMDXFfzbyEuMC3dgrwVmO zCpbDZeuAT!<0m-!IevnpWaB45QfNG1&PrZ+Zj0)J+A;v$t5PeW@F*@utOOWhnsi0* zgv=ul66rmpE1yWzaxm4=P#YP+7F_w9_{X>&S;k%zo50?LP8q|!2>5_l#xf}hD!cv8 z<#OBujs(0XTWaAd!qNSS--vhY>zROULQ2OK-Y_x*M01vTq4pjlj;e&%4C6RwXFn@_vmP~&E zrO+5l2-Xpc(gfvb93?m4gr~zLWW9rS zeY+ek2Gij~lyDC3m2edn!cz+m;m<9MKZHZJ1o$!OA0^`1Mcd&7Ug#o9ob-GNXKi5~ zue&pNEd#+Q<$Q7pA7-hP!@(t#KG@q{NUnX~LyOR}`5B~6%h}0PN7>A2-Z1gmxL=cs zc2B0hn=DLkj{6AL!<@`kf~?G^Dz=+-GT(IyRzo0PYMy{;Oq?&P+3S_rjrSH|h&1_Q z*qjrcWro(FYSrGp#K96k^y95i?1`SzR6>ImA`D1o{BIj#CX@i$y;f4x zo_0$}@l5heFECZ>*1lZoaZA%kM0JV0zSQ4RNMD9nGXc(2igLNeuDD9p1?6*|D5^y9C zLV#cO=G*OW!JyNR6l`ngG@qgDM5RzRXKw2m95*h3v~$OeSII$%rD1=B#6UGrCf|6R zL4jv78~h9n&>cSO-*!o{$jvuOO%yjpBb(tt&-SC6kBv>y_XS_Fqyss*iu`Jt%ISu+ zE|onqKF))A8RP*Y@q?8(;sb6a7(`omsJNH>syIcIn5xxA3D2WtC0Hk7bo5Zw+G1%t zO6HRyWW6fbqD}F%Hb{u)w*=pU*NE3t29UQ_653NTsWNPmG#o4Nf-#BJ)cs7sx4=tw zz@4uY^yXZ(c7?k8nSei_HBpxh8%_WQ%ra+_ahYY+asCohhW*FO#>f8SWw+uWX4(Po zRP^O+Q&ptD6;<(-8b8g}D&AAg50YGc_ArT9vqsh3Pipxp^?qWd2kysP#c@Bn(uDWp zRn6UxJ+MOp!^2N*W3beHSL{DqlPjYk-{e)P_&~`j&vBFg^7RlZB;s{wH zir#z*YdPoir#rj4D5hOVy7t0T+wYPh}m>$G<)Oxoh#AaW@mgD*0YFzf&F$Mo2XeEv%(1=$`haYhD-ol28R+Yjo z1~eT9x1G(Mz0T!ug2#t%3-8+n-7_iZL=$pT4=8STXJ>22(BLpZ*x|j|3M$&!+PoOh zRUjF^0(W;ijmz7Oh^6z%#BPtFUX0RH z9la>x4{ea5G0ZNEx{Ef9N8F=B=!b?=Q6)L$gyDyBK`DJ+@SO7@O}Hwd2E{7lemyAf z>fpBCACm-F%gFy%jYY;p;dY*KqeDgY;Z>5>V87n(f?=AXn$>b*HqkQm$hr)VO@7lg zNhHMdjMf2TRYt;Y&d!=dEe0XKSV8;$i4aWhe z1XNFeQ>rdrh618o8ry^l3RU4vwq2|&gnzTEi_I7X(UU@RV#%4}Qun zju)>PTmo)xtu4fzyNKSm3u>&``pX51K|_RoT-a8tDh#DNUoP056o@Hs8GRz#URexO zRag&rmt8m#j0D_lb}<}Y&u_yag(!k@rWgU~kTR*-yfmZ`6%8qhbEr_?GMEl2O;rx@$P(3%*k$#_Cl0f0e6TZRh)m_6fjtrFePfxP2ZC& zDA|PE)LqVt5+y)srmd(kUf_J{wy2q>6zxKyJs6Ujm8WU|uy06t4eQWy8<&<2LYE24 zGnPNSQscy|gPj6y8V&YgHGWVt@7o2%g%I25#GqDrk|LT+jcBi6~lKvg+< zBeu0+^B}k_6l|m(^l2ad|8zDiZWH@uZxc%_m5+G!cqCVYL%}Es6Ep+B4^J@~T+1#$e#=c1dqb1D<)QH72BfyU(pHhX4O%hxCSO&%>LGr+c{f4QLcWG9w zdO??FG-@SWnvqx`+R}{34vh0aP&98-q#2o7VU~s@R#*>dMg@0fT#?CSNT&BAffWl^ zGh$eRxjTC`!A(~nS*BnR^MqCrs+6zR$dOFWn{mm zWmi7{4QYd{Lp(^K%#QkIooidycqAUfi!MtIIS|T1hC2a<`LaJ*LYog2<+V{faHf35 zWirB4ZUC(UFw_gpFvLTifloTT3ksxJa8L6Bv-6&$#rw}@v+e_}i*Q*M;7BIxV0a#I zV8L1H)1-Wr9~+C-py58JlfIzxId^?qozYr;w;R-=wYKBFu&kjAzs+AnA?J8zEc@?Z zwGexBvtf$6EhDu@Q`XOIh}FcwA2mTZJH_*bp450v>yeu7Aq$b~gGs*97`(9mit*beeQv%j)lrTd6RsRWIPNMVBVP*l z=#+;F-5}&4a}ErH22Hs#3_#R(VNIhbNWM7g$54(SwNp+(Pt3N`i0G`MzL95x1x;k#~JH69JLapJhLyq@M#wG%c3%Q}Dz za`g_voOiyuj%@oU0%aUU24$;`+A9iHd3v0QEujt>yzee1v&<3ahoQ&iAZI+SVWnNw z6*bv{*EwH2N#4wiC(D}6s9ElLCzU~EGVUq^C|%u8v9>o_hs_F4@D1j*OMdlMW8GT9 z;^X#;1Fi#0TS85{npJ4UV9GhY4BD$9Sgj+>fMmuc=A)qGoKBk~JIxGOgAwPr&s-0B_3(uF9C)-Hu+g!ptqI~v@d585K0%5~RkG5;3+itfD0Z8xOd9R}B%EfL*gW=MubvPOU ze;(JP^5z{Wda;GJ0v(pC$iSB{tJJ4oc zHSS$!r8c9QVcSZ&Ek!PdDU}`==;-&#oj+%0J4t;*L6La--C@zYFD~zk9(_Sw4@WfO z>=*szXvFe~2Nrp?+Gz#*NWD{=SMjks8@(Jtwyk(a;t4Oi@OOX*1SkMe%Hq2C@p906 zI4xmMp!f-{QCFwkIjhzkcl!^=u>M?}FURADw-a_Sh4+iW_~F_7`WEKz;0|dv`B^zW z#E>1$i;rxX_g#70Ee@A(;Dok<{P73c8IaqvpDkx4qyf9P4@9GQHhOq58_cK0TR8rF zIa>}Ea2r)lNw%vv8%)c$cn2NdbPJd;UiKf}j3@V!CBOhzgW($3aD6) zPGKSr`Us>mfEzf@>3a``8hY;>Sd_ml>Y57pLyH}uvmYQ63pHCKx z$*4GnLyz$*B6PGEm6PXqkR@%a;-@Io+X2jW00FMDUUwG-9CJYL2u9{Ok7vC>zj$^B z_ZOq`lwwi4pG@%feSXa?b}_jV??A617&|Xs4j*2lLqP<`gsbOZxFQZua@TJML*R@j zch9b5m%zKZ%hj-npZgC7%k2lmJq`){vv(KPady2dNU^zM@c>=s*;R04t zz6kfOVPX9kE>JPnN27A~ibO&2?#2@Vjqn_j-*1V=b_6(k#;FV>BeeSq>QJf$KV^>S} z5k)DBx82!X+Mtat7;&+Te$_oI^@0TnigV6_wCW9d*HB``*263N3m(=ZjL9P`L>Lrs<%iOd4?}pRo6Rw}d1})HYx=pv+Mj#+Yo2;uTgO?5!+|{*vBH`et7; z)#2?83lVKq#7(F+dbK->*ea4FhUK-NgxYpZkVJqb7|__Aqk=Hy$QP`N3U1(J&jB*- z;CsTTy%7T-GA5SjRPZD-$p;*qs`DpsE``b*I2C~&7X%RucdH@_uXND0z*dO$)Ocz0 zBd};=B6f%DkqLcA?gl?h4%r3<$DLe|iB+{!tgtIF_c?xD8SQTS+M_9r|pLiJvgNGv{89GgH)%Xmoj3+p`Y_rD61`}X+ zm8x*UF}qM3!9fA-D*>mJG!Nt$!9&uVC{PQ{RZLrx1!Ng`CTDgG%gSP$#O~?sC%2pd z+*?5R6bDpbn~;+`&mYopB>2G!%|Ve!3#apDxv%3SU5JW(ri0 z;*#I#(NObh$uiCyTg~mNhpW`Az7IG5{*{qY0&NYt8M}&lPRqLk&NQZuwyF&JES>Cs zgSAca1882eI@N)S)4Q*x?NivK4I7i*CKMiS%?)|3bDTp z3cQ6(C4PC37SF-;AO0BHu9D87^V_Sp^a{Wq1Wf?}hnpvC!>BxqXF3y1zs>aGPk(Z8 zlskhs!k<6;pzcf_hJa0JoOs~&f=-L5ne%1uv?9U9FB5`8{!9-YG-t8zw`p)YiQKk= zwn4;CE-wLKa*_{QV^-=STm!^H_tm#cYD7(VJire~RUbYnZf5~vQq^}wYM1RAkW9P; zECpIQSVe0q>Z$u^Gt7Ds!Ye=`0kl`PG1RXkL(vEy}{bwkXt%JXjfr zLsTLO(2Qcr5JlkwB+yN$B1~c>()G~X(9x*_jm0!{%*smJaz-)ts3un=55CoLiwtep zmYEk&JG6!BraRi1tOcm((gb`lnUBbQG*?AGD$*oYqOoG8P`@fN?&`wLI=eXC60?C{t@%emNmta*-u z_|=R|ImlT71>Al9io-mdyks#*KgGElmTkz@rRZ97P>{H-ZTVZwFL%ge5c>pCo~o3s z78mmbR!0W3?l@n5!D+4Gfo?!Wug8h02d7&{ImOtn z6F44gTQ3lQGNp%WoMdG=Fp#(iQX<$gEGWZaK4_AgE&lRwYqJ!)-pL%jq3o5Ev{P22 zP&ZORB0pM5R1Y{^WNu0v3Ox(9b;R-wJ_XCdEMh1jefeG2YF&5Xj!lvRL; zFz0qIh<^ESn}D*Xa?DQG(0EX&@SN|=*BvQHMTi{Akd;Ln<4N`97l&@FOvM%;YKaIU$ZDI3SNJA38xexT8ruc9c3LH@ zDPBYXzNe{{9tKww=U0lf3{8WLnHwTg#ES~DfyV;A1sZt047TOlBfm*&2)CI>Q1Xc5 zgN*jMwR}vke^Oa`K0WMI*|DyY+$GL>^Y9AoIAP+eBpK0RO*u==gGlXr4uJ7^VsUW} z9)p2}o{@l`H8q!{t5qsF5)(=ek`)KNA-#VKOAAx5Fp-M}J#0RS5(|uh+^jUR23+&A zRobLwpAf5Y=Z>XR3X!j-;O53{3R?;v67@?4(UsZcrcCY=XL9~5Di9Bs9p7aT&0Ulo z;ze7^ejnV(Bx0c{UPcETOT!2YhCTn-$UJOvXjwdHoqDKH&Y*HpK6BWS)r_E@X`}P- zu5Xz<)Ty5GYH~iKeicWs9wBbEW2|O;x}(5LE*XWgfR%?hJK8Eb(Lk({>~Yk*Oee6b zt_Weczo=N$jK;Hzv?51(g>_(^+qpqv=2`qeuc@xUd?TnlkSa})jy1eX`Dy&0$S_DvKAY zQEhz2BF$H7PgTVb*jlA23*1CkikAgnHdpb5O$T*HjBoqq;Uu1%XVR2`hvZlRs>-l> zNKvA~+7PO7s_;2-sY$ISC7e-a(&UT|lP2d>moz=2v1F6eib|U7F<|0a$84LZFKV@s zG#gUP#~UTo^i=9J*Lx}5BcegstT34o7YDR%Z zk-ftVGl8QfPN~Z%dRB1Xnq}rnR zwZwCZEQ*}eU(rNejmXMH&1&OXXaz`WbttN%rV)=iCo!U0uezb+ zMad#}nifTk%&|vMGwm*F8MTRdve`ao-3uWaH%6p#QQa}3#z|>b!24P9jw60bS143$ zK%rvOQ>Y+kYK}q$7bdSkA!Q9UCbXC86eTK{&!HcYp_XizdToeobK<5GDM93y^n~sM zfW?zrx>Rufp}G~8Y&=@hnhqFSR@0#xK9-B+aGhL6AGVqlh{KptrXY{76znN0_>jcv zYGT5i%P_f2qI*M&c{edo7DgFTW*N@HtzvMQER~#IVG{f;1G$pDW#GI6q2*WQ=~f3h z3!JUg=i_Z@VR0~rz%40Vm0v-6ovn963Fy;VTbjX|oGnHB{ERK7ys?_ErJ&7h0nxl{ zli_qCOmAn(1`EtpeaUBIpQ&YXO7gU-w1}l;l2&rGIJ0W4F=%OimPt&rvuuWgpOtt_ z^3Jj*EyK(*sTp3DNzJjclr%j6!=ZF=|JT$sBTF+D53HF&*RZh+ek~VEVOBA*44k_N z+9N=Nv@8e9;HDW^CNbt;nFM80MdL#g!XoCGSB9bjMCYX-9p~QQuw?)&Un)nz0>npW z%|lsEITCsUOk5H}5_yn1rj=4ru9SBw2orsll}WARSSd)JVPzn){3?^4V^^8vJh#dK z)H16K%xYeh7N(9>Wni+LDy1O}p0F6hD|9WN%8;mMQyHK%mr4^emSDIDNgkC!OtYw( zBxV>?2Gu)`_<5>P8wwIoAIivoecdC6v8Lw-~Yk=(+Q+$hCOvYVPD*07=sdXf{> zAT7^_GRUjgPzJ1)3uR!EOem9<=0OFC*}kpiKp7$qOm1JR=RX-b9#FPKIqs7!Oy1fE zuX9P>lQu_^^^`~qPah6%DLSz@X(3uY+sWjc<~nKOkltg`2bLty$>1efPF`A;X0DHu z{3b&($!<#CHkvS-4AIZWYpQ28!9#s=MXF;oX%Qj3%2!y@EP^c5TDESZ(c%+J9o^RB zGHD^3F_{!Pwy%-qF&TK*sz!pvq*Rl(G(rv&_d}W^WW>;#u!Ib#&t77&ES8fdu`CLR zUlq@1!oQH^PabynG;f$GrWw=?I>fYpHZcPFz52PHZ zEJI7Ft>S1YoD!^IX({MRo|Xc7r%21EN-(t)p*jLu=zJ4=KDL%-|BDpa;z8A3*95jL z+2`kMS<($yTNbtnZ_5HVVQz7=`1_6GC)rz0V#MFlv|0vNm0@)rP{cHgOH`&FHMbEUYeq;t$4&}N>or~YQ?8zC8`k7sVxMEkC6(oH?>Bcqc=*^_X<%{jx6g- zv#H^IMIZ_0m%`L>zZ3>DVFc430n0W@_4!|#T*m;jFnJD`f@E1>3XtQ0X?mUsrVzDU zFa=u822)7dHfuz-WGG}AVU|jU6Q=34tgrycSW1o`xuq;=W|-2*iEIgOk{za~X?|F< z)C@;Vk-fu=&!JL~6i=*4T9PZKh}D@WooNjdOHRunV@wGrIb)hwL)EaxxHlr+nBvzG z&vC~TImsT=L|u(C{IL|+>cua~AyZP0JXXjeOMuXAA>JsGOfrj|Kd?fh41> zQDUA|rs%79WeQizEK{H)w@ee$?6NR5-_;H?tPxOlU-r0R&7krb=9p$$uR4(}v#zI1 z^D4S4l$98i4p%KY!8qKp7}H6N5bJqoTCz0r%%-NeXEyOzM4f4-MY$*WXNoC_0Rv4F zQKD>bCRu2T81c}!W73zJCR{Y7`+3-CT$nr`P0AWF(rgiGY}-~apM#Z_p_c69^_Xdv zax-q41#ikuQ-l@#GzD8NvQ-Tq%iHoeRKmeZFw_W<#P;o^5J;b&23tbV=xmeiJG}e& zJT(*RF}y2Okav}v#nzYri??sqODC)NF6>5NrJ`|U~?1vD)=~g zZB-vGr?2WmA)RiH77 zQ=2-RJ!Xy%cX*JMh;yvON zhFGmhM7CqWvq@rQ-7;aXpFG?F7(!U#SHjtHWWmKg0XJ8w3F&4=J#B0^dL{BvWzbYj zVD5C)KIDQ^$5){A#S@&uLlV|i^$97-+Xz~Q74P+m7VRLog2YXF6HOvOgU0}%; zbJ)`EmB%G)9!u~8>;%tYy|(;DetuHSCJV7|?hUnVKZ{+M;D(Si25i*{rknftSNPDz zdK;B1NZ}}C^yYlg0s{o*%prCCvr-&!9#wCk=_ zOE>BrJU4)vCJ9x=HD8vz`IaBQuqNqrR$i7f^YQFezz>)O&ASD{yg4I z;F$nc+^R+?5{*P_Yi75~x9jSSDv#S>kIExwx2MI^r-{n>J5!!)v? z4AsOgl&4Ig4gUAdYM^o!*DMN-Uj5}3%DS(74e?b zU~+pGB#*4U#hGI2&HodL`kQ4w`=F8XfKm1HpkbAAkaR0GwWjOjx;1W*4e#Ub!(_RD zYb@FG#4!3!7)#bQgE%TwWty_JGYkmb7D0?x3t?`*8a_;~&z58F)(B@GCYsqC_QM@m zt!?6fz_}BQvXkcuk3g&SzDi*l&gTj$w&{H$wOG^*d2klijmo%(B9iMmE*_fa@ z5?K_tFcqY*C=As!h|uz=hDID@+j7!!bwcCj4e5ZO0Bo5cd|$=+Asr?UY(wv}*S23Tf&m=GKu zqD%PWjQlD|5SCThJ(+yHegSq2`#uBmkC$-xbon4D&o1VZ;Zo_ohKsSEk+jm#oR=vx zVy-ZG<71D*U%M2aLr00;dj#xjIBFtSLJkQRm^edpPN#;eIf8C+HVWKsH#>ZWSPhSz zAzIym(<@he)C@@_519#|_;{HBN*(_~u*{J%1(rBWhG3avWC|>GZVTZuN5>E>cW6w( zHOV%2Pz>qij));#`f!+lN*oIlP{{*f2$wzzhEVB4Uj7D5jhtlxNbbVNwI|5-jO0K9UTfRC@(=?7VuV#6^~XO;ox|QEi$N1#c6W# z@ZjQ%T3ZW`5K9mGxv_n9><|222R`~fZ5Hx)hjQo#F8sWSz~Z{>CU8Ev><%Rk2+zh3 zci?E01;soggYA8GZvdyHCo`K!Yq6L6{+(t9W9B9pbqJlsXepmpZGPU_HcS{zE6%Sc zcOSYJ^JnmUNd6Pazv%?7W5*?8;KQ#Ae^=A%^Adhi$W8RTc-9v{FfwYO&X?0E_%rZx z1CLxn^KjBzQr~?jXCrcT2e+d~Z0)Uq`KgVt4NN!E(C(5Zs9(BH&g9}a3@9-O!kl14x`|Y4KuO%uBxuq+xTZ{@u z`E3=^9GtzytJ~f*pk^wMOKBK4(>ge!MZ#LG)~n&rb>-5YwE!MmktfWU>RTC;6J+2Ax zo##Qnn~c>BIF}w?bS6*3_9Y`XR zVFTIm z_85Ly$+V{PRlMg?N|L{XlBcz^vd^ztWglWS>KXHp9VyZ~hCMma0lI?q>1;qeB}>Gd zyijw6@sY_|0lBWMh(`qhZUEwwIJhWL?|0ZOZtZ4)Mo7f^czfuY2rG*7aFiqX{(REA zDHrc1c-R==o#U+R_KWs?uauXT_vg#mB{)wa8KW;L*mzpoe$wXdcZ*K%y6oL_;Ih8+ z{?)U?SM3j-QMWfUB3&UyYabZ6wBg0019!_^yn77Wr+e>DF22PP^&M`hxQ=w?Yx@Ny z4o**Ri*vljl#}PnONjN%i^K9_c?E%;1vYPdfUQNgd;2e!W0vWeqdw?wsU1@2@kpv- zUXt=#XjI%y7qQ8!$|?#CHq})mvb(F-ZQy#bV3X9@-(^?j5N)>&5d3|&0YbO|uR=-e z#7$6wEqN76VsCDO5^j>Ka1y)qDwNc=-2`XdqNO(SRr#cL^i??V*4_Xk*y9^uM4SC8 zoOst?g%NN6t1$BCfK{0J1HmfHHBJV#3yHg|2yZFa6?B*R-rp=}CyL5QPa;^s7uT}3 zlfD%Ml;cQ3eiLECi?WYOUX;C>3 z^O2lWn{&4SD6jLGtlK`k!*fI9(5k^~i=ECUm(U)hifwM3Ov~}BV{?$x6sn*JUh zFL1`L!opj@3+3WLBU7}J#oe2lBH*4Op=4oc5X*gr+!=g$m~xq0+d-UMEa;A;VA>%* zAe5n~uI8tG&VjFAB}>?1b2Al1d-1Yaq*l@$6!>lT+sO>_L?qiUgVK#jXSO+Vk;sF2 zMI+fVoY7z$X5_@=GIBsrCpPK%Q=K{veLJ8*}<#g@7=eL3@1C0>p-Vqm@ZpIDBRA8yHz;cad<1-Vp zrAcnxRC!YtUV7ZU9<0dZg0WGROx7z8DT%W;;fp4*6ig@y20;}pK1U>qciSCOuQ{K| zR-mzY?f{vU*@;PKw9%tS1D19`Hr0ntW`0xPbdionu^4ks6d1l;(XJHs6LbR zAjuiCuuE&=wduS=h+b?GcdIWufvO1sg4>O^z#F{m7U#>0k8s{OxueT=iHAk=^#UgFW+p5@ zw3>>v;Tu>ml)4dWde*sn3QHhP% zBr&$hYOolV&iDBPX8!1HIbJ%EZ=tF+Lf+4pi^XK@CUoyJ34`(5?!Caz9R#zNy@sY& zL<}x|`*9W!TYi|IkkF_@h94dv-$SCGliAUDx?B`epA)p@Y|t;~Qju3!JC@)tnbgBc zIS1S0S&uk5FCpDCFHlUb!dLXV@p3sF&bilKl@qXEW)Ga{3rM(5r~xDory!gD^sg|!-c1f?lPNXJ5W5}pN<0^txO3n`D4Cg-0x!?&MR(kvK@Y7sGIuL_AVM3?3XJ$U zrqjbw|1FrH&gbj?Xi&WV_@Z-q^09r^d3$o$?wq`Q8ActR{Ing$y*oL3`|LQ3CCJYC zSLdhgcZWr%b2+D{;d0J10%svonZu2uGgrwnz)Z(jbXbVJv!GV*LLrb?eNdPyATS1w zrG8zN;}T*7`uROxzpiPmIbZB{I^+ILYnyUxZB$uq6Nuau#dYXv&=aGFy8?0-iv-r6 z_6hG{7kJp~f#*n~_(wg8YW3iysoHV=mO&1uZ`kn6ijD$c6EN4(?Fx#m?NRrp z?AXza-Q168Q2f@8*beQ`SRG?$0g)i42^Cm>#k}rehA0^sE@5;NT54^!1CDn&=HtCj z%*HpMrWU0ejmLvd2m1?q9vfjGm@wsnSLoWQy(0wslpvSbjv4=4$OI zPSq4aOd~S8isZCW7}bc-p2c!nFN#}}l+&=5l*Tn7g=y9!k&&6O8P-~y4PujQS}jar z2)K02vgUj>LdS$>ba@P&%pPbK1W}C$?HDXN19WiDsOV@+V>0DX4kCmoWZalWWVUe9 z;nOyL3=!wM5s3{PZ*-lfHqnnJ$Y@o%m2lxH&;*Bi(k}XpX}_AF@9Ai>N0?R1xr6ce zb$6|zt$RvYy(QT?nB&Q+Iv;p*Wi|cQc04;)V@WPL@>avQ@DLD;`36Xkv7q~;9pS4{ zNK8@BKMnTdZ5_j_DIeIeN+WkQyz5MBRiCxCz=ZY|Iq$nkb}eFQ2df$i8b>xFR+Yze zv86-bjY#Y+1Tq9CDgys*0Af^$SO+s?Uhx^%t0JpFiFofH9+2hu9hYw-f?0Bu#Lpl8(nb|DNRUL!Y=4wa16m+0Gn@wo-L-OBbl?ef+%Gz(-5KsM z;ATN{`}+a-$*k;#m1o5rW?x~2PqBrvtzNAxQlD;)>mW>x8fDW`O{bE<8u0uu(iDEg zXOiZv1o*Y+(;;Rs218OcNUJYux2DA;GX2seW51d-zmca}onZ^-L}4v4Cj_%?-6M*N zUJNGl4lbW%(Ob^I+AnW#s>a&`%6_|$1gz5}nhx&6d^v;yM+a|aogPdepd6}ri}1KZ zwh=J+d3MctklMD}>5}Hsky?;E9&K$vjtxt_X4wmY7fGr;ewTH=D_1g zJz3ZN$%^jtH5CkVDOrO3QTM(xCt;yrflWfY$H)4@!UI-t`$`g2uzF&f-9;m67OtM0 z=l!BNXg#Fk`eIe*Ty%Rk!FH2u9M|R9ip=}ut`t2;4}S%(Q?Q1}#%sTLvb6!3)mxkp ze%&(Y%I@f5d5LB2c5yM}!vjA`bUI+&cZ%@@7FBwaA+APcF~Y|JI{U>K8t!dT4D+|S4=uDcp-pe3D#2uGzNeqeZ zUa<;W9$>GBmsh-Jpw&z$Rd9N2fg?27r5Sd5;BgAQ(|5>qhXlJ9?IG3Pfk;u=?{rLY z&_yQb@294^2YmWxx@VNf<^bxkHV(L?8Qdu*(A4Fim)U`hu9~|u=yUgs7h9Vh+V{pd z;Um&RG?^natQ2HyGZ>szx)2sQ*s#Tc4qgF1Q z=C?Gz(0N^Oy!kEp_xortJI9>XPLP^;k=dUvF9w(jG>~utF(qvm8tr#dQ>tLFE->!V z4ifMhyD1U)CAxr=0;XyEv^S&@$rrsMV*1jO{V2NRrU<0Uo5|&6`yQ3v*V7XOwfN)& zGqn{6`eV+mKQF&S*t}X`{B(fNPnswUg2g2sVg2UXrl_NX(S=+_7VX~cJ=(-R7Yrxk zt0(kl1=X;lQJa?94IUnFjqnp2V0Z{A2p&U=H~fI$iYe8f?Rl zD#_k_Io9e(=uu>Ls1#b7$F>PbpiSOj6?{yi$etw(2Royij&^m%=!2Ah8$)qp!!G$+81;NM4)ASLZ93~LzcCVSoV^|-d!nbJL< z)*kwO9F6ViC$*=+F6sACje$Bydp>3~?}6dR=ydMn(4)#g9Ws>;q22%=G9vm-576L7t{tE9B{BZyo0DP9*w|SM2_YrNsYl}bXUSH z=`E9%xkciHadI9WFdAWIj~9)w_we9G*9FWz6Y@uCBO=>O0jDcg2(1oCYak2ve$x(Y z77qoJ8yApJ8uSx0NsGRUUzIhB4ps-(e1IZx=n-uPaY{@NIhw7ReG9x2mZu!`jYt@k z!;5)DfxH#j+hiJbr?-TzkM1sa>tkmR0gZ~j-VvZV$)*Q@Mii6Vetmux*EJvN28&A(Gxcpb zniGWN;`HHiMAkFu%x1pUY*Bgj=ke4$XF>9rU@ON!ZsA{};h{b-o8gYu>p_2jLTgrb z=MHLeV{jDtcfBFB&Cf}nulKe`xJN;PA~M+SUt=G z7GiQY-74KDT{AItiO^4XGl=Fe&FfHqt6g`Mv9mvk>0f2+tZ1CAOvm+0JcP5?moy;2 zSi~JNae1pRx8T!N#o63>T{++VG=lbFt$n`pSW2uZzGh>hM#0lgxO^u&5NNoIKc@YB zNwsD@j@_0b+4*OK7GJf;Kqe6oHa%YvU^#n|@aaz1_I zZ-R|`v36BlzY(@@YX~$Tn-yh;Z!C$|rAFflmfDwd)|FYi+jbV^a7a?8{QHR3hlPgn zW}1HGWg*Cbso$(ZLNqNGVD>1po;Ka547lOcx$SgdlHB`O=3<3?$v-%?)<9P2;cAAg zfgDK&uah&7#eT}8vfiaz3k-7J77{2D?bWmwI!DvYMH*5z!HxTiC&G5M0vZzW zq?y5+7(#0yM?f++GYR1R5P=cmVe zi_w%Gq;PbQ0R1A7nvNE36qid)#o|v>=E1x>gb*(l0Jh49--}^)e1qQ})P{!m?GLWd z1A{sH#lkP1VqsSWR#m7u=$GsQ<9ANpwD1c@Se$+@h!`P^fPUu$^ac8y+8H5QISBVo z3xNPRDo2bK<4((Qrv~|md7e!lxJQ+_4`RTwM zBozCG^8&_yI#~EeF#AK9k}aU_@N%pl*I3bqC2c3L03_mA>T~wRCR?sqTo2~3IS5Sx zvUMaH3FxeM_B_mNqodQ-P5>mfgq#CGw>zJ0lENu<2TVLbbC{nv2>h_-B)vmRjShxuOsDNuI93AZ{ z8ZU6SXDiBtMW1AelZz~~C{$4wqvGV8U-ETxI^3jMcbFyI+Iatrces=3{AkeL9!|P_ z{KEMLi8ZNVu3gy$kL1CTV916pZ3nQ|iKQW+0(0uH0!U;opz9P8q3sH`L;+!lU;|Lc z9eAD`kIA_oWV4cFY(Kpa)Hai=z_j!b1S}Q9YEe% zd}l87m?wsLkg1=vd(GA#Wk86hKd?$i;k`w?pqne3ixcFa{6N;r7AYFlul> z`LKabKR@Vjs$Vj^GvOTap+%#@WY&lw69|pkVlc9ZjNcOXLxnWp$2DVO{d{ zKm5(#!1()3n#Gp`@O1D?LZtYC)kD0gP}y4Y!>2Smw94<0J=S}g-fX$RD;Z61ir(xT zaj#pAw}1VwO#zgj%57w+VvJFxawJhjOXdBG2%>*o`aEvjpzHhKpXqKoAW76+C7up zCeeaZb4J>$fx!Vz%xPwU4sex({xhAdnV|jT!sbZ3rcd8wY3sEr4`FXXSsGhd#AOr7 zQ;`F@RJ0Zf#{hE>&*sOp(A1lE(<5G#io5BTrWu|-HSI6Uah3+ofwtlE#$|8)Xfs23a$$HL`Bh;PCI!Bx|D8JnO4QSp%v;)=VqR zI@{GPasl3%(y0$u2A;f51TX+SdiCnm0^wn>9>JG-d>nY`h36 z(NZx?+%OT$w)kz-rod3}BjUE%yl}!R9G)+kfx%z zd;I#jdbsOltLx_uDb@yq&>akM6Z^xWwXqxzzFWe}#A0@&!xjxnCquq4ot3^l7KJ3xbsa}rN<_lbIjfaHjhZo@wSb|a~~_d97Ax2W%Gjd@=tS8-%SnSR5UXTDxG%GcQ;pzijQ&>UjkLjX*U8tG;18DrZ?R zgGeeg6}J}@H#}{nMg^L=U9WC{D+p+d)iua{$%Dz{hIY5fJh+@R$`N}jS>l%WXgpGW zFW1D|2b;UWGSz3Yl!b-B(}jFYxscWR*YZJ+(lrGT&cNfD283cCq;i0RL$(@ z$5wsx2^D9Z7(9_vNo+1{SWzSCE|rTPK!}aZiu%iTtZAE@SbXxd`(I_hlzIQg1ou&| z=U9P6f5;P;wYF&uoCen-G2m^64~>{Fo>=oQVebUPC6{yKkzfeaX72P-GQZZAXK4mA z$oqa&lSg}IG{%xWb;$d(JDS6xnMT{7ZQVs{cpPB7&ecT;J8zvUvQ$LBkXY~sKcpSl zNV`8m_HpW-^o4h%!6tZn%klhra0#Y9?hkBij%55GKFhIC!^gOX>>|lW(6I@B78Cvh zUMUKOug;hX>R#Z|C4}pV@fE}w)4{#Ii4mjvf?MV zDuWm8m8jKhWqi@1gLuGKHG`tw%2-r89SHSkrn(<)H#+0ZZ7_N5n?bW3KsJs?qss=8 zKyTJuX5V@|ezbu#YU{%Yt>K9%M#Pf6fN=dC)aGca%vm%bi1G#!I*AU~9XjyfO$kRe znBHCzBPuO|hUJ>}?w~hS;%pC`XKaGBJ*9~@Je_+*grXT3&UpQU%|Wrllq(vQEO~C$ z@)2hopfs{kRr=Yi$Xg~kwFm$6|(8nb|=6VyfqBRY&>^KKPoB|Hhqor^1l=-=b18_WB} z)$S3S6yxPsAbkqs)|Kbw;J0(tWu7k#MGK((fN z;Knw9`!Ey;#e)GY{@6WU(&A6rfU*^I#~gwV6*f-jUg7UG4SNc(gL3Q?gdx&La)2XC zm;^8;=~w)cMh_rJVM=zO7Af>0okSoZ#mVPT(%2zqK-kHym*X3jVZ+DtqBHM8)dy|l z1o6pNqzPw3B_C5EMssS+{*WdXF8BCLT739>FVdFuW&=eO*lfiU&b%C6_Gj?%{aeey zZ+*A;tr5Izn1=hGV3p_n364~+j?Fe_J8KT(M59rc`)!1|236SiUw3DN?s)MGAJWux zH1M{})&|_scTX<9B_U$o4*lfTcZ&`|@KQu$)%m7zn}f!|6>0C`gxwI|Cdt6|;1rT+ zmITSB1td0MyBgWxM9yl=9{F8pb}cUVZMu9$BwG8(fY_XP6qcfsK%7cUXG;~9gq+k8 zjj9Um0`kfiIG8{?{E8mZut?9Ku4KNR<6}Ho;ME(Ggc@3p3~?LVl&E=umq@H@O$Q@r zJS7yin}hNAwo>A$W&%?O*D-Q3v!R`h4$-)db7Etm#^bFGGbA!lXwBozZG|DaE{#+c zMg~#HZ|*9pQwRgWq;2+0T2tQ3tT;q=+?}oM_vbjDmVK*c)p9^KTYl=HJY^g~ilW`_ zo9BWzpFqP(5`F>=)gAeia`bNB;-*KsFIX@1jrxhx5>I~Ux5SrD+80m!G}B5h2v{{w zpZ@SuTin$l`-BFoUbjA_$#w_xcVN+*_4Vp#bJ39` zT}$=)62vlWZ^+s)#j@akzixhisW{c(pWR8)FBQGNG{L{Vw^0&s{u%D z_aV@KHi`dee*b0hdw=jN|Lsb!e?egX6+-{@t(q5AlHhuL2Ci@K?fq?VED{fnBUFSA+CIkYPk6TD%q!$azTRj|_;elD}O1 z+duu^L!iGkK>uKV6T|uQg8YhITBFYYJ5z>#vSo>e(3b}Lb)L%S1^MlKM*p)(I<+9* zgsuDY-<6nuFu!PB4gU83AxYTI`X>1MRg|PvfB(oN{iy{x)!-lho+VVlOX%mOWdC4G zc&foCKeJf>(FFhRD(bII@NcT9zcs{J zHll4uiT;JjAG7ZVe`&(S|0;+S7Zys1{=g7V4Deq!N!xjlW0Ula`9)4o!kn7G{HekJ zGn>^nA(=lnNxx&l3$gi3VG;gY=X8xZ{TB_;^ zydNa+qR!D#_{X+lJ?&FP$NUIO`K5vGTdbdkAm5mzif~ld-w!~jUYhxTFlni}Ch+V) zbnv3OYEhg4T>NK~k4`S+7uKZE!TrPxatvS%{&)YIK%MMTL}J8v=j%JBro+ zH3R+o7ArdMeq*5jjm3)A?S)DD-G45SKh9@#Z<7ANf7hmZ3nxy?_*YI`Sfc-8vZ+cGwb4Hqkbg42 z$S#`2n)a)vXo>CQ*d%>pK_+2g8i4$j!TuXdC2GNcG)e!$_Cr*q&kOQ{d`ACd%JQog zBIO){DpMk8AW7u1783{8sx7YucE#jg& zs4p-js3VGAhsbqi3D==nU-ifg*HQ2F$jmU$F%GFzi0=P{GK~7vA&wpoAk*kMCU{O0 zViLS3e<&~~H{U8|unQ_IY;!ONN15#-Vei0ctSsd8LVV(H>yhHQQI?BoKD>w;Pf zpgKfmSUag3(zt0JMAo=Pkc8$KRmvGwpVKr+M9+Rw%lH5`Yy7MLxoz{@GncTS~t%Iy}N)sm$o%v1WBm02^3zpJ41<^&cJT?O&V&Q+vD44*^l5Jp_O&mta^mE!U zhY_pWc}`jgL=fHdg!XijqcZ_y+H;NxE(b)2t_ZY1R0tp!5zHW?5d|UDJ)#~HMa_XQ z3F;xH=d_hpi@nH6frvFp9pp@p=~5&Sozsv-d}K*lXIbmKCbmYX1x~uIMXdgPjgwaW zmabFN?{$bYvi1hel0z%Nnx0)6YpGS|o)i zv}t9IXdOf_gL*llCp5QJ`Wa5zuSF~iW9)???TsX&=QWhQ$kEtAXD!=ADVr!~6ItVq zO*8>8i_CLKr;m2&t@SB9y!JEbLPYx>_OC|MJxwFdq#^S5nc5; zWS?En(G3A)=2c|^Xj2zL^nm8Jy3ngyVL$F?M+FYETGSC1IrCYiD8?Mb&uJ`fo$}1G z-kh$BT!F>+b4b(60ghe@pyxOmv<7P!zQmjftz`|c*I8th7O`5QEiw@HjfmSKmVZ`o z2CyY+8vvPZmW`5WXWWMC+GBFcmohCwE3I(@NZx_BTP*8^G-(aRbdMf5oh zS^fc0PK%@vg*KgrAQ}**%(?*4h$b396x!555e zkD2Ic-G-yMfN>GaWaypH7Fa_>m6MKZ5z9x1I4NMUPR}56O0!rZXE^DC7O`rz@sO&X z1c%gG5j~=zETYFWlswMS*yj}ixnh{3xd1ZjejRHek5G2|HTPoK%?468!QByPEmD-1 zg8M}?@>L??fyFEGRUiFJ@XaRsyTcrgh4YY4EJWxh051<+S#9RNm`3q>UY-n>1vV;UFh@+GEz{>jaC;X%=gS zeTI|HX_4U(CJY97tKjo2eNAgw<}Fwv51AgeMIOAd$l#4dtU_L9TLM>=Ocsc&;lfir zd5Evm9=2}v!2yAY<%pH6-KbeCch(_NX6*x-C5h-s4Ov^#Sx$ORizKgd^m+h!Ur^py z$stYIt2nwQfYx$!T>zO*M0VFScM9Aqv{nk-O#$R0I<1K;w<51oFGwWDHVkW9l89c= z&?ur8HDs9sq9HAkLKNCG${`vMS?fX&B{k6iqR^&=7@`4@)#$sKU?+!S$%{DDBW`X& zHR_IV(g7`Exnr7>0v2oO3Xv0<#S-xjtA-KdkQyeUvtLw6b2*M43Lw*>MTmNrq?LG~TCg9+lV@*aG(C2-{??;rm8|gg z6KXnBp*La-)o`dlOEaw_(lkONOe1t@roF1=g(~Vs-k=5(3u*<5)HDdak#2O;cxkk1 z8+OP}YS=f*k#s{XFQmIj8^d7K;OTJ*iV+78C%LPi;*i!VYfYn~fxnu;#4_JU@yPE1zv;N8UGE#Cfl@7AO1_%cxo<8qu~GJU1ls|99yWi`tq z7iv?;p_`KkI?mCP0b~+^0NQk<+G}ZznkGdYyl!BvAp3{RydW~H&9S@(k$}ZoNyBAe ziE@uA)8JX_WQg>$F+}4bUeE>(qvYoU$ShWslTK<8YyQ8;Nx{r+l^jV|G>f$s@xG+8 zUdtiXFrqOHSu_2rC25VYR!$RJ3%rAzbV!R>79ZoJ<8F~zPMULzc)zR4o#2qljp(W) zDv1V{CXN;Y$gC+4b!(y&qSrK(1JQa-l-t13SO9I}XjcHavg^{^1BeFM`N(dcCbHVb zS|&iLLk{TI+}U+Z0AnKt+(n2w0wS{<8#pNtdH4m0^y-W(7WlH4OCtKD`N^?*Rnu6f z1uw41T#ykwi@J{(29fv8X&vA^4su8ZUt<;=X~(oZR(HG1NkQvcipUIm|Cnx&Nkq>) zsjQ-=b(y1A0?4!&M3*#?HHJXsv=$jaG|0WqIpd;i0C10;iyeyH69Q> zqltzP4J^vpMAjYyM5i>-gNW|a7LD6PIXLUb_!1WEDC35}7EGsz!utcp|>ybfQ08fKwRb_+-noCejORI?u zOlVI$Vz!Z&Mr677Df_FFW>%3xDAgh+BWV+tD$4Ckk%@47jBcOJh>WoIxSOR8ksNE6HH%f*2RJEk)lx*@)$>6{hz{{|LW|U$96c03W*y8k0kmmv zh3Iw7t%-7OqO&Z0PHS2Fn>s`;v-TA?%T0(}bF++dNy;2X?X^~OT9YodRaFU2>Uu#U zv#kA$o8=rQEd(NnUeQnv(W@G=2H~bz)dXT3QiUVhuOVyw3ax||v51qLRMsL%M4$LW zl_xdH!yG*wKxUH!(TpZa9pLDp077&|6Zzmi5thmo81~G7~oHQ7CB=ujZt+TEr?9k`jSPlA}WbWD-|7DR7sS_mV^`^K2GNWPxp2 z@fBqyjeUp?YbZCu(S-n7@l~a;io=L|+BSCz+*dVG)+Vy1x@&GDS85__Sg%iOJri^+ ziD>N$)q2sg2T^}u5o+y10NKu7qT9?iU7xdG)$$f;u&cP9P?fZ$-@uTkds*JDLhIyY zwMFEEGsa2FylqDjzs49nvSgE6YZH*8=`Z&_*`TS=izH~)wyjC86oV0gCV{VNDi2T# zF#Qv8&SUyDq!o+?d3!XtnWlu=erdUVls2&2x9zT{mFBojS9RMSJ;c!?0c5tbSGB?( zd12lNW*zGQZa>!mYJ{GkL8Tnim18YcOs(bKbi+|oPlDk>i1=|PJ*~;D1M`fd`!;L5VDpXE-A)(4tn{7g=UOJI3<*B~HT35b?BA9U_+vmdI*q;z@3up6sl3 zu_;2o4Pn0)wu|+L10F>8X(&6x(ft~-as$zj7D*u*5an#5l-U4hnc#FlWQv^Qr1M(D zGRG8&Ec_MLUpc38pangm8#I)SaWtVJD>o3W&>|^B1EQQwWEDQi1O-i$MD&b?tYwC+ zm9n+0kp)_1O*~NL=xGgE`wM6x19}t>(Ll>uD335KH~(F+=~@|xqM zK*Xwv1s1ukS(1o$ea%_))tnTFSj2URB$;JIXOu*=tRbsV$2e)uEn*HU)KF~5BKEv9 zQ%dX{hxpAn{4AVF@=BM#xLcLz5{H*L)V~^L6!?`cKhE`vAN-o%qY7A^R^dqw&vR%L z-<#d5kU0)daX8N*ep~1aU!UdhB8Qhayv*Sh4zF@(=69of>gN5h$*iu|Grobt7>6Ak z;`f8P__~|JAr5zPIKtsLhXoGJTyK<5y}Z*7{!JfIIj;D16*h5*-}*7_InC*3I6TYY zISyZLd6yjoj%#o=WR&0Jja^DmNoH}fR9eA67_ zM>b4*fa7;|;1~SjhD&~qdCzcomP6=Y;%ieMzZdb`$5qNT4)NO&raXRb0lz&EdrV2- zCksZf}PcYuW;U*68#&}a6ua!RmcYxo7Lras=_dWO@_ad@7?iySU+XzHJ39D0}d`Z9-jv8%_g{WSG~73(SL;j^ah7cnRtdzln1vho*jk-x^uv5bvTqfwxH-3NHD>4*7Y;&v1B_!}A>C zm6R*^#fV0BUcLHPnQy83&pGs~Y}Y;x%@;YE`Qf!t$3Lr5@Omh`pvja!^cjWV#bJ0M z7T&~U%3opms~qB;U3j6EDUa9vocx?hndJ~K@G<2#98$;(hbK5Z$)PFV&3G?|!yN8( z$m8V>csqglW(SiWZ=0xBe%)ckfbZuP`1%lsCO_nMa{6Hok2vIyd{HqR;}BoWJHgi` zKfVrFuY4o(%yNitt>H^$CjZKtl*jjm@NJ_Z{-Vh+hbBMdl7`#}U*lUc;|_gOuE28m zR!xi_xZcE}nSYh#PjYx8d6W-doH6BlIiI8>KRhFT4e3uRi;^6g_TfqIRh(`yX@$2lox&&=JcH$;+bjF{+pF|@#0x*lOOek^l7$dpTmBa93JF0 z`7eA~A$Wpx#Zh%_pPnoH;;ahs08Zi$)pak2>MHn)C)V&x3!d&f;gIj(8v?k|XWr$* z?FQVv2y#-fE{A@OaZ~;{<0m_+H;oeJ;&jB4snmjl=pCsH?30e zGv60x_?kofo;ZFy{4nq9j&Zmi`!5dht9>)PA3DYBdi){~eq04Vq|(jn#UzJMaCneI z{0PB3um5IveTVP>U*p~Jr}%oFL%iP|FLTGc))5Z#dT4}0tOxNTa;(?zGVlbikGeR- zyQ6h@Q27t5#Ggva6P}$1@E%C z%GY=e3+7jZS23S|N%1B)?BcMS!z7189OB#71->qGxR1jb4i9jMuU;SKYkbf81YhGz z)u;G+p2MpgdOR=g!y;1mW-r6lu_)72E)+qcn z-kRQ zd0h)p`0MFcI->Bqy^%4Bu0-K$yc3c5J+?3*%e^-_ z@Hac~wGR9(4*abS{A~`r$-+g4S>gTcc{4#ZOS}EQQwlEgP8jXKo$+x47tOUH)Q_;= zdWhw7hWrTQX8%&nb(y!*ke?*^DErlUvE8oJyluBDbuMMMD>X0L_5N9D=RIDFG2(nd z;&wk0$geV9yi`0aeJKk6^S?L{1Ayt+#Vm=C2o&cF1{eh`QX=NQMr9jV`B91D2h^WfnHJn&~3#|8@cpEHhyKJdR_91DKn-(?&Nf8c+` zI5q&l|AujF1c3jTacl^H|CDiT41oVVwI~^6zFG8xP3G7@s%f+Ze}21oE30$A$#>7RIqL z0p80vHYmV%0Ot(~@FB*rVFCUD#<6h$KEgOQGQdX}$3_Ntf$CzG1k3D8DDn>3@ZEz<6Q>+EyfQS_yxx24gCKwe$L4EpBZ2MXSMm> zN$U{LYxEWjp0_i;{@bpCwJPsCs_Y*GK1L}7tCyX+Ff$Mz}dHjd6^Vs~G>cgnJR^24%?eypv%0&oGYpWj{CI+iq3%VBM(J zH=ehJaF6y`O~;skgC3S&&p7%uU0+@n)2u+80q9ye&H4I|#pvIm5x52^aQY{d}7JHsIhHci^999?Y8? znCGt@@~mirOPw(<_;ADmN>nEV`Z@O;&Q|Ahnp zD+m7O*F@XjLb&uZ?*~a;e)=5p!w&pO2mU7x{KpRb4w@&T+QSD3kMjRxgbVwze?h-K z?U4V4z?adu&F2`X-$pv$jN)%`;9Z1^d@(++W4|RG@)efHz6Q|S-?30AXmj9O36E-r!x9h9*z7q5JC5QZ58l!o-9rzI8f*<=_wa@Xq z&pG6uVtMRGI=KDJ1AjtQ3d;Kn2TvPSN>qCrbl@K&JgOd_a>zg9kpH1W{thxG%AOn* zCu;n^pM-_qu-+Tzwm9zK`HTa9+JT>wIE_oZF5Soc%kGZ0^F0ncMYwD~yq{goJck_e za}NAgQY4eC&w2-*cHkc+{9ane;+!+Vj9+uef7gL~Z-};MjRWs+;3I?!|KMD1p6&U9 zL;kn}|BeHH-hr?BC1F3U55KB1q@9fXY>+r#gn}LiKE^!9n1`0l^7CcFMY(Xkw7~uJ zqJ!so!o@g@^WhohX{Y_0TnBzc0l44t0O5ik=RD}|2MHHEIDcNlJkPQ`Zm>iCHWG+x zSMPD)Jq~=rfgdGY*t7oo%8>PJ&;N4B|Hy&=1L0yG$G$SgJa4%t+WvM2{y_&mL%8S{ zxG&Jm{9kj(pLgK@O!!^I^WS+tNXs+%dF`8`$IlqyjourrdA6N!QNK8cq;4obWx}KC z>*Egm_m~I!>m>6$BjsuRX0-qBI(XL8Er+OllZ1=<9q0O;Vg64LF6>W!Ndf2=&pLR% zM|jlya!K+B_mAGg{BNKRE89QMcW77rgh$y~Cj2f+NiHY?wEvGudGhnL!kgr|nCJbz zgXdWX{vFBB#)X2PI^^%BqaR^E&P9*0PKxj-`wtKvwI2JtL;f4gkMq^5%zxD(|Br;< zMgMgzC_(sV72SdocFwb((GIsWj`RGLJidL1aM4ej{#Nl&x0Rod5-!Fud|i5o@!yp= zUxb3MIPm{MxUi?p?TSWN`MH~JWkvaIn*)E?f$t_<+W$i)=JxP$hy14r7xw7;DeQ;; zCgf>A(*=@IND5_!;Mo!=CzFbjbhMfv@>j(e}3! zF8Fa@66YsHhx|tfj~Wl3B3!N$zOU><|N4%D=PKbMU)=+ro@8=6Hh&*SwS4!`IX`=C6%}N7c)a z1OJc%KjgswfN)_C?l1SM?7g2j%cED5AMI8<#zSfcSqaP<-m72@cj<_NeBL)9QZ8ZqP%!+0rUP9DNp@8!MW2)1$%EIT=3xjY%iDheT0j4HNT()vA+E@%i}qLF6KEa_&FX9E)pJ9kGE`y z#_w_9F$exZ!iD{KUS$(!{&~Wq?D=B{&;NGdKNmQS+ql2Bg8AP^3+AYD^*QhY;lfUj z+h>A#o^r^ab>M&Jz;D?YZOK>fGsh zDNp_}+U?r+ih87W_yc7}jP3bV!lV4Zhj6hD#Pe(|EdR7a{(BC5Ib{^Z-$J4QuV#niSm21mFliarkH!r zuF>|)Xl7%{TbJ7y^NP7g(^4*7oSN9>S0u38uT17kMXy+@`f1Xsl=8WBKIa#!3d&`w z85Q%3ITa~pCVWri;g98u8?%BuF8(x&KP}=B(xQQcX`}@<|38Y9u z5+o!+LJ}k-K|-ZUf`lYUNP>hUNJxTKsoN@bTcvKR)NPfztx{L2N}W#czO7r+{&dza zSJTzZu7V%4khqORK+U#P!iHKcsKr8TH7ccPCKcI&?84aDk$X%%@{$GFHndqnwo$fC zonHC_{qg3>a=uvfE9uGnhkb9Nlua|RF{^qX)fx3HsxA6UwMBoaw&*X_7X78_qQ6wr z^p|Rl{!&d-ca>VQ(p7DXR@W{vY>s`1I;>yKq($#f531Z{N}?uZsFKM(`u==w%&*GS zHl$8gEBWG>sokP^L+N1-YZ#+3=RNK1?QQKXG>E0|>wjR&=Kk~p+qMn%45f!QZ|Uzz zd+F|ncWl1DZz~zFW3U=;F8IZ<>Ui3(R7#bt%{|HOS(Vb3PSXGwZ;qwY)$vMcPdY59 z#M0S9rZ|?)W(tLL)vrwCipP0qfuScOxcr+$5TmtS(|6GE)(^L=mJqic2b)wQBG9ZqA7Hi zrzXd#VzZC-$mXkaZOK(KWA~SK`^Y$v>JB5ddDrRB_DSD=v@|-}GaYVH63yi+J&y=d zSkO5+UfP4qW2r%0d84IrPy^{*lap!cylL4e<1MKNDDl32)re$`DF-JjrLl@XIk_cM z5iJp!c%#CipgPBk)XR2kM{*mDO_hAMM^uq?d$+$kpY`MIp^N*KNR2<*go_J4SLKjm zZRg<)72KBEQX%Kp3T-!vaFZ5L^B{XN5A1rx&sO8HttA@Gv*A`1r+!q*KI&I@l&bmB zyf3^VDkCwpx9khQDAjO9G{>ncZl0=^w&e?jE!0xRDy6Anu4h+Gk=tphm)1j0cw4?mHj~T7OF6W)_Eet%(#TBX^K`zN9;dOjK=b3CN~T<*2MkAgaF|re7-Nbh2W}t>8vW0}H$HrSnE2W7CtD_z1alb(1V!V{& zLojS{AxHBCpN8$|KHk%sr!id&nN+RZ5PQ7Q(E_zKZN<<-@pyPXq;lw75|h=^s8WwF zX-w%!PKY{Et-dB7G=221c>6?YYSJI@3%;0I^bmKyK;@Vk*pJX}U{K`X8F|i&@{{#U3&1#f?^l>9Ji+kD{16 zj1JrCt5US30{h!j4`nL(OtHGTn5TA4gM7S&n)aaBuRN3~$ja(~jNoifCG*o0nKDYN zi&5{ym6+UH%qmam!7LtE6G@RaQ{-IAXXv58LGk*gaq6gY$d!97WhzhDEsy$plVXVF zy68-8_xCCvjAjd^Nk7#1%;gi2ZtL68m)<-uu=!y%l!wgD7xPs);EF!cp$1~r_wrO7Zn$t1Q4ET2po z-LjgW2uzHphV&(wH(2e|t6pOXTh|EJNz;#C87+wQ0X3cMbS5p22xw7U&5lzBvU}Z6 z>!kPRi@DOCV7iZTO=;0ZTF|m|mmHwBsm5#?q1#g13YoFVz8%e}YP_>=A~WXGtjmWT zBB`fl5gBqNt>1aifZ0aQL@3TFQs(vY0vq)r84*T zIPFTZ)6zI1R3HGeu33mIUc+X=0*O?CakZ z@9A;uCuRQ$DD*z9O$<^co&$6aVs6jBz`0%eH7LEaW$1bdFS1foer0cu>@01eWtM_P zZPMU!UnQUG&+MfwY&<5W$#N!3&X9xf&|qk2t8>#)+y7#;)XGGem*}jH6b>vI^AkDF2Cuzs&D9)dz=Y>f*hqM zSluO><8pn~U7DiSwv~36kD?dR5MHy!(#FSW3Ku(WUW+xS27+s~TPg+lY_D0}#bXnC z@1fQnG|$Hir7=1kFiuH=>}Ww&97A@Y`lw~Ddjh&i?{&}yS4|{5TBvb7-X_-KnP>tw5){OANCL{Zo5Df`3CXDhbj6Pe;(9#T*SUdiq) z_=DrV=quDeloMrdHnwzF(8fDbn|IM5M?-tCCKg9N{iRZQD{U{UYR#o{skZ?{xnuDO zUb;iCzJuvr%{~cr3ZX`((2mJ5?`pT|aTsS1x+JkZGr-YwAiFIZ;xuae7r+84{UEs zZ7mf_6*=w2a>n_1%q_HkR6Pt2V2sz z%_M?@Jh_+;Z^C)IY`N0h?BA@Ft@6Z3&f~>BbkdPd4)hq6vE*YoKE%;}Yt2+DnZ0zD zuJ%~{6D_fx9`+9%u?P2s^yyh>wT`Ajn-P5;&_>%HI;bV<#m2W7TC(Uo>+Lx5becv2 zanmF*N|Cc~23Hfxn9B=Sy6qMOdQ#1*~Ow47q~Z^9LTSYxt_?9>Df^#F1HZcB)dL zo}*685~^b0uA&Q((GXr&g|* zV&ZL-PG`S#MqHdi_iv}+ycQI>X_Ximsn0&bOWKG+iL>>dVlMI&ux2aNnaSnUk|bC^ z=JPdY1udHk`LW^zW+Z@l{pT&wplgvh@6jT!|WG#Yr>#D z<&j%|Xxqp~ZUH2W)ceACV%*PLu9JtZ)r}maYTcspM^PZe&gNe=4`AHt3`DSqoojypU zraw~qm#)FM9PSTtG~h|AZK_O5U|*eH^wqRFDMssZand1{m-lBXbTqG;i+L|B*q89V zy|!F_l7=R6dr#iV+bcSh@|e1vCD^r}_)G&v8=a&>?fLKP?-7S)4;J^(LN-nN{waF= zD$Ei&P0N-_bBJ-1lTY!Y268dxbx+X)2jWyu?z?M`$vVVPC2xzUM0?m&&JJ!>)-LoC z{yg5(>!pInJk=wWjrb74cw~39NoJv#! z;A761yh(y7CZ5_V?wQzP;s{Yb7tt#R8E#iWP1k=PCp2TV(!HD7n{c7KH)?ECLwMVy zxUVe+Z}mKe9JX6GPnM|}4u}esWA+YOx5izAIhMQexG&C_wvqE_vZQlwI#%Z5$`gHB z=lJ}<7qt`RDsKBN^*8+bM%x>&@m$l3eNS!B>f`!wftsys(R$g^L5sD*0QpWjR7AvH zQEm`xI$phN)yP}F>2x8#D@$kl`OpcW-Qx!2Ih;B**W*Tg?hEcV!cDsUTmA{nlkIfK zpjxq>D&>$$>w?W+_`{LW& zt<_SWcvwk3A)*^QRb?f!M~x%Y-f2}RZX#`yF?qMUwm3I8Q0o>;yJ&j;VmCedmJRLG zaCmP_eC=|RO!HptDkqpN>3Nfwda@|o3gSy#xX6YpHyNU+hAr`C(L?i@0-e5F7S%fd z;9x~81=L_EJ5hUXFZG6+yM(nR)*GbOEZraBC$S>tZZ$8;a)^hnaKANZIIZ%A107lF z=K#c_B>GlEvz#0I^qswUs&;DBbz0vjgtDU%izSs>T#22Eijm*xo$ibAJp^(u~1(`9j% zD(-{ohxms2jE*7t3X0Jwb`n@4#i(KNm5|ZRMK|Vz=utg%O40rPjTL`%V>&%HJ)NdU zt0qfD>Sxux>D}_7)0#SsI$06}W$hMJWN6qKZVWa1a_b(xwzS@EP1_e*XwvpY?p|^k zJZ!;B$LMDObS|w~adV#@_rxd&Z^q;F+;JWbl^gOcd#k>je3QGA1<%_!xp#u50t%}Y z6^(Fku&0v;Lh8{N6@PR8Hu_boAXk_4y47!uoj6A;JzA#`4hPOYd>k zNBQx)9SC=#p|Jw&hyJGxef+)$!fp_=fWN2J^zh~%oKdUlAc$~j4 z%-PGjMqGs7pnt+A5bIi?3;J}OQ=#cEQA1{$ksV{`tZxoNi3W{ejnw;_muuH z6xF3}|KRy2Lm%J!^cIxD3D!dZJzO_X<^n_c@gBkx3rfP2H?MCcePMr0iR-`6Pl&|O z2bT!%qzK|6G4JB{)z#AvVdPNPrtF&?`k(4hjyq<2`P9^ZmqY*Ezoztmo4$t}{+Rl$ ztZ$b8)U?w7@Y-nm!PDi)zxj96z%^J3=WhFIyF>r674+R{`WVB99htTL|K3j6pVB|HAB^9xAq;JgqWW|A*OdNG>HEOpkH|0l5!D-||M)(o LKW-=(m)`#ee?dgF literal 603552 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 z%0D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 M=y!qy2j1-e1;8@I+5i9m diff --git a/selfdrive/ui/qt/text.cc b/selfdrive/ui/qt/text.cc index d44570d99..0708b30db 100644 --- a/selfdrive/ui/qt/text.cc +++ b/selfdrive/ui/qt/text.cc @@ -1,22 +1,36 @@ -#include -#include -#include -#include #include +#include +#include +#include +#include +#include -#include "qt_window.hpp" #include "selfdrive/hardware/hw.h" +#include "selfdrive/ui/qt/qt_window.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget window; setMainWindow(&window); - QVBoxLayout *layout = new QVBoxLayout(); - layout->setContentsMargins(125, 125, 125, 125); + Hardware::set_display_power(true); + Hardware::set_brightness(65); - // TODO: make this scroll - layout->addWidget(new QLabel(argv[1]), 0, Qt::AlignTop); + QGridLayout *layout = new QGridLayout; + layout->setMargin(50); + + QLabel *label = new QLabel(argv[1]); + label->setWordWrap(true); + label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + ScrollView *scroll = new ScrollView(label); + scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + layout->addWidget(scroll, 0, 0, Qt::AlignTop); + + // Scroll to the bottom + QObject::connect(scroll->verticalScrollBar(), &QAbstractSlider::rangeChanged, [=](){ + scroll->verticalScrollBar()->setValue(scroll->verticalScrollBar()->maximum()); + }); QPushButton *btn = new QPushButton(); #ifdef __aarch64__ @@ -26,9 +40,9 @@ int main(int argc, char *argv[]) { }); #else btn->setText("Exit"); - QObject::connect(btn, SIGNAL(released()), &a, SLOT(quit())); + QObject::connect(btn, &QPushButton::released, &a, &QApplication::quit); #endif - layout->addWidget(btn, 0, Qt::AlignRight); + layout->addWidget(btn, 0, 0, Qt::AlignRight | Qt::AlignBottom); window.setLayout(layout); window.setStyleSheet(R"( @@ -44,6 +58,7 @@ int main(int argc, char *argv[]) { padding-left: 100px; border: 2px solid white; border-radius: 20px; + margin-right: 40px; } )"); diff --git a/selfdrive/ui/qt/text_aarch64 b/selfdrive/ui/qt/text_aarch64 index 67ce52e1318ad545eb8bb6f7611e9187e61dc061..f4f770afdecd64ef05bc3f41cedee9ffd0e32dff 100755 GIT binary patch literal 785800 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