diff --git a/CHANGELOGS-DEV.md b/CHANGELOGS-DEV.md
index 1d3f2e968..036b34f8f 100644
--- a/CHANGELOGS-DEV.md
+++ b/CHANGELOGS-DEV.md
@@ -1,3 +1,8 @@
+dragonpilot 0.8.0
+========================
+* 基於最新 openpilot 0.8.0 devel.
+* Based on latest openpilot 0.8.0 devel.
+
dragonpilot 0.7.10.1
========================
* HYUNDAI_GENESIS 使用 INDI 控制器。(感謝 @donfyffe 提供)
diff --git a/CHANGELOGS-REL.md b/CHANGELOGS-REL.md
index 1fe3b8af5..826ca5e13 100644
--- a/CHANGELOGS-REL.md
+++ b/CHANGELOGS-REL.md
@@ -1,3 +1,8 @@
+dragonpilot 0.8.0
+========================
+* 基於最新 openpilot 0.8.0 devel.
+* Based on latest openpilot 0.8.0 devel.
+
dragonpilot 0.7.10.0
========================
* 基於最新 openpilot 0.7.10 devel.
diff --git a/CHANGELOGS.md b/CHANGELOGS.md
index 4875523ac..206edf39f 100644
--- a/CHANGELOGS.md
+++ b/CHANGELOGS.md
@@ -1,3 +1,8 @@
+2020-12-02 (0.8.0.0)
+========================
+* 基於最新 openpilot 0.8.0 devel.
+* Based on latest openpilot 0.8.0 devel.
+
2020-11-28 (0.7.10.0)
========================
* 加入來自 afa 的 Honda inspire, accord, crv SnG 優化。(感謝 @menwenliang 提供)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8f54cdf07..6a9f715b3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,7 +28,7 @@ Code is automatically checked for style by Github Actions as part of the automat
We've released a [Model Port guide](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6) for porting to Toyota/Lexus models.
-If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84). You might also be eligible for a bounty.
+If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84). You might also be eligible for a bounty.
## Pull Requests
diff --git a/README.md b/README.md
index 772272183..517cde940 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ Supported Cars
| ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------|
| Acura | ILX 2016-18 | AcuraWatch Plus | openpilot | 25mph1 | 25mph |
| Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph1 | 12mph |
-| Acura | RDX 2020 | AcuraWatch | Stock | 0mph | 3mph |
+| Acura | RDX 2020 | 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-19 | Honda Sensing | Stock | 0mph | 12mph |
@@ -78,6 +78,7 @@ Supported Cars
| Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph1 | 12mph |
| Honda | HR-V 2019 | Honda Sensing | openpilot | 25mph1 | 12mph |
| Honda | Insight 2019-20 | All | Stock | 0mph | 3mph |
+| Honda | Inspire 2018 | All | Stock | 0mph | 3mph |
| Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph1 | 0mph |
| Honda | Passport 2019 | All | openpilot | 25mph1 | 12mph |
| Honda | Pilot 2016-19 | Honda Sensing | openpilot | 25mph1 | 12mph |
@@ -85,10 +86,11 @@ Supported Cars
| Hyundai | Palisade 2020 | All | Stock | 0mph | 0mph |
| Hyundai | Sonata 2020 | All | Stock | 0mph | 0mph |
| Lexus | CT Hybrid 2017-18 | LSS | Stock3| 0mph | 0mph |
-| Lexus | ES 2019 | All | openpilot | 0mph | 0mph |
+| Lexus | ES 2019-20 | All | openpilot | 0mph | 0mph |
| Lexus | ES Hybrid 2019 | 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 Hybrid 2018 | All | Stock3| 0mph | 0mph |
| Lexus | RX 2016-18 | All | Stock3| 0mph | 0mph |
| Lexus | RX 2020 | All | openpilot | 0mph | 0mph |
@@ -96,11 +98,11 @@ Supported Cars
| Lexus | RX Hybrid 2020 | All | openpilot | 0mph | 0mph |
| Toyota | Avalon 2016-18 | TSS-P | Stock3| 20mph1 | 0mph |
| Toyota | Camry 2018-20 | All | Stock | 0mph4 | 0mph |
-| Toyota | Camry Hybrid 2018-19 | All | Stock | 0mph4 | 0mph |
+| Toyota | Camry Hybrid 2018-20 | All | Stock | 0mph4 | 0mph |
| Toyota | C-HR 2017-19 | All | Stock | 0mph | 0mph |
| Toyota | C-HR Hybrid 2017-19 | All | Stock | 0mph | 0mph |
| Toyota | Corolla 2017-19 | All | Stock3| 20mph1 | 0mph |
-| Toyota | Corolla 2020 | All | openpilot | 0mph | 0mph |
+| Toyota | Corolla 2020-21 | All | openpilot | 0mph | 0mph |
| Toyota | Corolla Hatchback 2019-20 | All | openpilot | 0mph | 0mph |
| Toyota | Corolla Hybrid 2020-21 | All | openpilot | 0mph | 0mph |
| Toyota | Highlander 2017-19 | All | Stock3| 0mph | 0mph |
@@ -108,11 +110,12 @@ Supported Cars
| Toyota | Highlander Hybrid 2017-19 | All | Stock3| 0mph | 0mph |
| Toyota | Highlander Hybrid 2020 | 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 |
| Toyota | Rav4 2016-18 | TSS-P | Stock3| 20mph1 | 0mph |
| Toyota | Rav4 2019-21 | All | openpilot | 0mph | 0mph |
| Toyota | Rav4 Hybrid 2016-18 | TSS-P | Stock3| 0mph | 0mph |
-| Toyota | Rav4 Hybrid 2019-20 | All | openpilot | 0mph | 0mph |
+| Toyota | Rav4 Hybrid 2019-21 | All | openpilot | 0mph | 0mph |
| Toyota | Sienna 2018-20 | All | Stock3| 0mph | 0mph |
1[Comma Pedal](https://github.com/commaai/openpilot/wiki/comma-pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).***
@@ -136,7 +139,7 @@ Community Maintained Cars and Features
| Genesis | G70 2018 | All | Stock | 0mph | 0mph |
| Genesis | G80 2018 | All | Stock | 0mph | 0mph |
| Genesis | G90 2018 | All | Stock | 0mph | 0mph |
-| GMC | Acadia Denali 20182| Adaptive Cruise | openpilot | 0mph | 7mph |
+| GMC | Acadia 20181 | Adaptive Cruise | openpilot | 0mph | 7mph |
| Holden | Astra 20171 | Adaptive Cruise | openpilot | 0mph | 7mph |
| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph |
| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph |
@@ -149,6 +152,7 @@ Community Maintained Cars and Features
| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
| Kia | Forte 2018-19 | 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 | Sorento 2018 | SCC + LKAS | Stock | 0mph | 0mph |
@@ -162,8 +166,7 @@ Community Maintained Cars and Features
| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph |
| Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph |
-1Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built giraffe](https://github.com/commaai/openpilot/wiki/GM). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).***
-2Requires a custom connector for the developer [car harness](https://comma.ai/shop/products/car-harness)
+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).***
Although it's not upstream, there's a community of people getting openpilot to run on Tesla's [here](https://tinkla.us/)
@@ -239,7 +242,6 @@ Many factors can impact the performance of openpilot DM, causing it to be unable
* Low light conditions, such as driving at night or in dark tunnels.
* Bright light (due to oncoming headlights, direct sunlight, etc.).
* The driver's face is partially or completely outside field of view of the driver facing camera.
-* Right hand driving vehicles.
* The driver facing camera is obstructed, covered, or damaged.
The list above does not represent an exhaustive list of situations that may interfere with proper operation of openpilot components. A driver should not rely on openpilot DM to assess their level of attention.
@@ -269,7 +271,7 @@ Safety and Testing
Testing on PC
------
-For simplified development and experimentation, openpilot can be run in the CARLA driving simulator, which allows you to develop openpilot without a car. The whole setup should only take a few minutes.
+For simplified development and experimentation, openpilot can be run in the CARLA driving simulator, which allows you to develop openpilot without a car. The whole setup should only take a few minutes.
Steps:
1) Start the CARLA server on first terminal
diff --git a/RELEASES.md b/RELEASES.md
index c3a5bd0ea..367a7e661 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,15 @@
+Version 0.8.0 (2020-11-30)
+========================
+ * New driving model: fully 3D and improved cut-in detection
+ * UI draws 2 road edges, 4 lanelines and paths in 3D
+ * Major fixes to cut-in detection for openpilot longitudinal
+ * Grey panda is no longer supported, upgrade to comma two or black panda
+ * Lexus NX 2018 support thanks to matt12eagles!
+ * Kia Niro EV 2020 support thanks to nickn17!
+ * Toyota Prius 2021 support thanks to rav4kumar!
+ * Improved lane positioning with uncertain lanelines, wide lanes and exits
+ * Improved lateral control for Prius and Subaru
+
Version 0.7.10 (2020-10-29)
========================
* Grey panda is deprecated, upgrade to comma two or black panda
diff --git a/SConstruct b/SConstruct
index 1b863beba..758d494f3 100644
--- a/SConstruct
+++ b/SConstruct
@@ -5,6 +5,8 @@ import shutil
import subprocess
import sys
import platform
+import numpy as np
+from sysconfig import get_paths
TICI = os.path.isfile('/TICI')
Decider('MD5-timestamp')
@@ -128,6 +130,10 @@ else:
# change pythonpath to this
lenv["PYTHONPATH"] = Dir("#").path
+#Get the path for Python.h for cython linking
+python_path = get_paths()['include']
+numpy_path = np.get_include()
+
env = Environment(
ENV=lenv,
CCFLAGS=[
@@ -159,6 +165,7 @@ env = Environment(
"#phonelibs/linux/include",
"#phonelibs/snpe/include",
"#phonelibs/nanovg",
+ "#selfdrive/boardd",
"#selfdrive/common",
"#selfdrive/camerad",
"#selfdrive/camerad/include",
@@ -181,50 +188,14 @@ env = Environment(
CXXFLAGS=["-std=c++1z"] + cxxflags,
LIBPATH=libpath + [
"#cereal",
+ "#selfdrive/boardd",
"#selfdrive/common",
"#phonelibs",
- ]
+ ],
+ CYTHONCFILESUFFIX=".cpp",
+ tools=["default", "cython"]
)
-qt_env = None
-if arch in ["x86_64", "Darwin", "larch64"]:
- qt_env = env.Clone()
-
- if arch == "Darwin":
- qt_env['QTDIR'] = "/usr/local/opt/qt"
- QT_BASE = "/usr/local/opt/qt/"
- qt_dirs = [
- QT_BASE + "include/",
- QT_BASE + "include/QtWidgets",
- QT_BASE + "include/QtGui",
- QT_BASE + "include/QtCore",
- QT_BASE + "include/QtDBus",
- QT_BASE + "include/QtMultimedia",
- ]
- qt_env["LINKFLAGS"] += ["-F" + QT_BASE + "lib"]
- else:
- qt_env['QTDIR'] = "/usr"
- qt_dirs = [
- f"/usr/include/{real_arch}-linux-gnu/qt5",
- f"/usr/include/{real_arch}-linux-gnu/qt5/QtWidgets",
- f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui",
- f"/usr/include/{real_arch}-linux-gnu/qt5/QtCore",
- f"/usr/include/{real_arch}-linux-gnu/qt5/QtDBus",
- f"/usr/include/{real_arch}-linux-gnu/qt5/QtMultimedia",
- f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui/5.5.1/QtGui",
- ]
-
- qt_env.Tool('qt')
- qt_env['CPPPATH'] += qt_dirs
- qt_flags = [
- "-D_REENTRANT",
- "-DQT_NO_DEBUG",
- "-DQT_WIDGETS_LIB",
- "-DQT_GUI_LIB",
- "-DQT_CORE_LIB"
- ]
- qt_env['CXXFLAGS'] += qt_flags
-
if os.environ.get('SCONS_CACHE'):
cache_dir = '/tmp/scons_cache'
@@ -238,6 +209,9 @@ if os.environ.get('SCONS_CACHE'):
if not os.path.isdir(cache_dir_branch) and os.path.isdir(cache_dir):
shutil.copytree(cache_dir, cache_dir_branch)
cache_dir = cache_dir_branch
+ elif TICI:
+ cache_dir = '/data/scons_cache'
+
CacheDir(cache_dir)
node_interval = 5
@@ -261,9 +235,28 @@ def abspath(x):
# rpath works elsewhere
return x[0].path.rsplit("/", 1)[1][:-3]
+#Cython build enviroment
+envCython = env.Clone()
+envCython["CPPPATH"] += [python_path, numpy_path]
+envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-deprecated-declarations"]
+
+python_libs = []
+if arch == "Darwin":
+ envCython["LINKFLAGS"]=["-bundle", "-undefined", "dynamic_lookup"]
+elif arch == "aarch64":
+ envCython["LINKFLAGS"]=["-shared"]
+
+ python_libs.append(os.path.basename(python_path))
+else:
+ envCython["LINKFLAGS"]=["-pthread", "-shared"]
+
+envCython["LIBS"] = python_libs
+
+Export('envCython')
+
# still needed for apks
zmq = 'zmq'
-Export('env', 'qt_env', 'arch', 'zmq', 'SHARED', 'USE_WEBCAM', 'QCOM_REPLAY')
+Export('env', 'arch', 'real_arch', 'zmq', 'SHARED', 'USE_WEBCAM', 'QCOM_REPLAY')
# cereal and messaging are shared with the system
SConscript(['cereal/SConscript'])
@@ -316,6 +309,5 @@ SConscript(['selfdrive/ui/SConscript'])
if arch != "Darwin":
SConscript(['selfdrive/logcatd/SConscript'])
-
if arch == "x86_64":
SConscript(['tools/lib/index_log/SConscript'])
diff --git a/cereal/SConscript b/cereal/SConscript
index 0ab943db9..c0ade46fa 100644
--- a/cereal/SConscript
+++ b/cereal/SConscript
@@ -2,6 +2,7 @@ Import('env', 'arch', 'zmq', 'cython_dependencies')
import shutil
+cereal_dir = Dir('.')
gen_dir = Dir('gen')
messaging_dir = Dir('messaging')
@@ -9,12 +10,12 @@ messaging_dir = Dir('messaging')
env.Command(["gen/c/include/c++.capnp.h", "gen/c/include/java.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS")
env.Command(['gen/cpp/car.capnp.c++', 'gen/cpp/log.capnp.c++', 'gen/cpp/car.capnp.h', 'gen/cpp/log.capnp.h'],
['car.capnp', 'log.capnp'],
- 'capnpc $SOURCES --src-prefix=cereal -o c++:' + gen_dir.path + '/cpp/')
+ f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
if shutil.which('capnpc-java'):
env.Command(['gen/java/Car.java', 'gen/java/Log.java'],
['car.capnp', 'log.capnp'],
- 'capnpc $SOURCES --src-prefix=cereal -o java:' + gen_dir.path + '/java/')
+ f"capnpc $SOURCES --src-prefix={cereal_dir.path} -o java:{gen_dir.path}/java/")
# TODO: remove non shared cereal and messaging
cereal_objects = env.SharedObject([
diff --git a/cereal/car.capnp b/cereal/car.capnp
index a0dfcdaea..8a443805a 100644
--- a/cereal/car.capnp
+++ b/cereal/car.capnp
@@ -73,7 +73,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
preLaneChangeLeft @57;
preLaneChangeRight @58;
laneChange @59;
- invalidGiraffeToyota @60;
internetConnectivityNeeded @61;
communityFeatureDisallowed @62;
lowMemory @63;
@@ -94,8 +93,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
startupMaster @78;
fcw @79;
steerSaturated @80;
- whitePandaUnsupported @81;
- startupGreyPanda @82;
belowEngageSpeed @84;
noGps @85;
wrongCruiseMode @87;
@@ -113,6 +110,9 @@ struct CarEvent @0x9b1657f34caf3ad3 {
driverMonitorOffDEPRECATED @42;
calibrationProgressDEPRECATED @47;
invalidGiraffeHondaDEPRECATED @49;
+ invalidGiraffeToyotaDEPRECATED @60;
+ whitePandaUnsupportedDEPRECATED @81;
+ startupGreyPandaDEPRECATED @82;
canErrorPersistentDEPRECATED @83;
focusRecoverActiveDEPRECATED @86;
neosUpdateRequiredDEPRECATED @88;
diff --git a/common/SConscript b/common/SConscript
index d17b35fed..542e10d43 100644
--- a/common/SConscript
+++ b/common/SConscript
@@ -1,14 +1,4 @@
-Import('env', 'cython_dependencies')
+Import('envCython')
-# Build cython clock module
-env.Command(['common_pyx.so', 'clock.cpp'],
- cython_dependencies + ['common_pyx_setup.py', 'clock.pyx'],
- "cd common && python3 common_pyx_setup.py build_ext --inplace")
-
-# Build cython params module
-env.Command(['params_pyx.so', 'params_pyx.cpp'],
- cython_dependencies + [
- 'params_pyx_setup.py', 'params_pyx.pyx', 'params_pxd.pxd',
- '#selfdrive/common/params.cc', '#selfdrive/common/params.h',
- '#selfdrive/common/util.c', '#selfdrive/common/util.h'],
- "cd common && python3 params_pyx_setup.py build_ext --inplace")
+envCython.Program('clock.so', 'clock.pyx')
+envCython.Program('params_pyx.so', 'params_pyx.pyx')
diff --git a/common/clock.pyx b/common/clock.pyx
index 9702e488c..81333565c 100644
--- a/common/clock.pyx
+++ b/common/clock.pyx
@@ -1,3 +1,4 @@
+# distutils: language = c++
# cython: language_level = 3
from posix.time cimport clock_gettime, timespec, CLOCK_MONOTONIC_RAW, clockid_t
diff --git a/common/common_pyx_setup.py b/common/common_pyx_setup.py
deleted file mode 100644
index d8f653e67..000000000
--- a/common/common_pyx_setup.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
-from Cython.Build import cythonize
-
-from common.cython_hacks import BuildExtWithoutPlatformSuffix
-
-sourcefiles = ['clock.pyx']
-extra_compile_args = ["-std=c++1z"]
-
-setup(name='common',
- cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
- ext_modules=cythonize(
- Extension(
- "common_pyx",
- language="c++",
- sources=sourcefiles,
- extra_compile_args=extra_compile_args,
- ),
- nthreads=4,
- ),
-)
diff --git a/common/kalman/SConscript b/common/kalman/SConscript
index 3d7011fe2..d60354c98 100644
--- a/common/kalman/SConscript
+++ b/common/kalman/SConscript
@@ -1,6 +1,3 @@
-Import('env', 'cython_dependencies')
-
-env.Command(['simple_kalman_impl.so'],
- cython_dependencies + ['simple_kalman_impl.pyx', 'simple_kalman_impl.pxd', 'simple_kalman_setup.py'],
- "cd common/kalman && python3 simple_kalman_setup.py build_ext --inplace")
+Import('envCython')
+envCython.Program('simple_kalman_impl.so', 'simple_kalman_impl.pyx')
diff --git a/common/kalman/simple_kalman_impl.pyx b/common/kalman/simple_kalman_impl.pyx
index e65efd577..16aefba2e 100644
--- a/common/kalman/simple_kalman_impl.pyx
+++ b/common/kalman/simple_kalman_impl.pyx
@@ -1,3 +1,4 @@
+# distutils: language = c++
# cython: language_level=3
cdef class KF1D:
diff --git a/common/kalman/simple_kalman_setup.py b/common/kalman/simple_kalman_setup.py
deleted file mode 100644
index d0781c9ff..000000000
--- a/common/kalman/simple_kalman_setup.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from distutils.core import Extension, setup
-
-from Cython.Build import cythonize
-
-from common.cython_hacks import BuildExtWithoutPlatformSuffix
-
-setup(name='Simple Kalman Implementation',
- cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
- ext_modules=cythonize(Extension("simple_kalman_impl",
- ["simple_kalman_impl.pyx"])))
diff --git a/common/kalman/tests/test_simple_kalman.py b/common/kalman/tests/test_simple_kalman.py
index 630875998..7b327918a 100644
--- a/common/kalman/tests/test_simple_kalman.py
+++ b/common/kalman/tests/test_simple_kalman.py
@@ -82,3 +82,6 @@ kf = KF1D(x0=[[x0_0], [x1_0]],
kf_speed = timeit.timeit("kf.update(1234)", setup=setup, number=10000)
kf_old_speed = timeit.timeit("kf_old.update(1234)", setup=setup, number=10000)
self.assertTrue(kf_speed < kf_old_speed / 4)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx
index 13872fe00..cb1753a04 100755
--- a/common/params_pyx.pyx
+++ b/common/params_pyx.pyx
@@ -2,7 +2,7 @@
# cython: language_level = 3
from libcpp cimport bool
from libcpp.string cimport string
-from params_pxd cimport Params as c_Params
+from common.params_pxd cimport Params as c_Params
from common.dp_conf import init_params_keys
import os
@@ -70,6 +70,7 @@ keys = {
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],
}
keys = init_params_keys(keys, [TxType.PERSISTENT])
diff --git a/common/params_pyx_setup.py b/common/params_pyx_setup.py
deleted file mode 100644
index 28dd9ee50..000000000
--- a/common/params_pyx_setup.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import os
-import subprocess
-from distutils.core import Extension, setup
-from Cython.Build import cythonize
-
-from common.cython_hacks import BuildExtWithoutPlatformSuffix
-from common.basedir import BASEDIR
-from common.hardware import TICI
-
-ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
-
-sourcefiles = ['params_pyx.pyx']
-extra_compile_args = ["-std=c++11"]
-
-if ARCH == "aarch64":
- if TICI:
- extra_compile_args += ["-DQCOM2"]
- else:
- extra_compile_args += ["-DQCOM"]
-
-
-setup(name='common',
- cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
- ext_modules=cythonize(
- Extension(
- "params_pyx",
- language="c++",
- sources=sourcefiles,
- include_dirs=[BASEDIR, os.path.join(BASEDIR, 'selfdrive')],
- extra_compile_args=extra_compile_args
- )
- )
-)
diff --git a/common/realtime.py b/common/realtime.py
index c883ec053..9f7315007 100644
--- a/common/realtime.py
+++ b/common/realtime.py
@@ -5,7 +5,7 @@ import time
import multiprocessing
from common.hardware import PC
-from common.common_pyx import sec_since_boot # pylint: disable=no-name-in-module, import-error
+from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error
# time step for each process
diff --git a/common/spinner.py b/common/spinner.py
index 53e8ee521..1232371d8 100644
--- a/common/spinner.py
+++ b/common/spinner.py
@@ -4,17 +4,14 @@ from common.basedir import BASEDIR
class Spinner():
- def __init__(self, noop=False):
- # spinner is currently only implemented for android
- self.spinner_proc = None
- if not noop:
- try:
- self.spinner_proc = subprocess.Popen(["./spinner"],
- stdin=subprocess.PIPE,
- cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"),
- close_fds=True)
- except OSError:
- self.spinner_proc = None
+ def __init__(self):
+ try:
+ self.spinner_proc = subprocess.Popen(["./spinner"],
+ stdin=subprocess.PIPE,
+ cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
+ close_fds=True)
+ except OSError:
+ self.spinner_proc = None
def __enter__(self):
return self
diff --git a/common/text_window.py b/common/text_window.py
index ff8fdb1fa..c9901754f 100755
--- a/common/text_window.py
+++ b/common/text_window.py
@@ -6,17 +6,14 @@ from common.basedir import BASEDIR
class TextWindow:
- def __init__(self, s, noop=False):
- # text window is only implemented for android currently
- self.text_proc = None
- if not noop:
- try:
- self.text_proc = subprocess.Popen(["./text", s],
- stdin=subprocess.PIPE,
- cwd=os.path.join(BASEDIR, "selfdrive", "ui", "text"),
- close_fds=True)
- except OSError:
- self.text_proc = None
+ def __init__(self, text):
+ try:
+ self.text_proc = subprocess.Popen(["./text", text],
+ stdin=subprocess.PIPE,
+ cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
+ close_fds=True)
+ except OSError:
+ self.text_proc = None
def get_status(self):
if self.text_proc is not None:
diff --git a/common/transformations/SConscript b/common/transformations/SConscript
index 0f7295225..adc9642a4 100644
--- a/common/transformations/SConscript
+++ b/common/transformations/SConscript
@@ -1,8 +1,3 @@
-Import('env', 'cython_dependencies')
+Import('envCython')
-d = Dir('.')
-
-env.Command(['transformations.so'],
- cython_dependencies + ['transformations.pxd', 'transformations.pyx',
- 'coordinates.cc', 'orientation.cc', 'coordinates.hpp', 'orientation.hpp'],
- 'cd ' + d.path + ' && python3 setup.py build_ext --inplace')
+envCython.Program('transformations.so', 'transformations.pyx')
diff --git a/common/transformations/camera.py b/common/transformations/camera.py
index afb714718..e1fbcb546 100644
--- a/common/transformations/camera.py
+++ b/common/transformations/camera.py
@@ -178,7 +178,7 @@ def img_from_device(pt_device):
def get_camera_frame_from_calib_frame(camera_frame_from_road_frame, intrinsics=fcam_intrinsics):
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)]
calib_frame_from_ground = np.dot(intrinsics,
- get_view_frame_from_road_frame(0, 0, 0, 1.22))[:, (0, 1, 3)]
+ get_view_frame_from_road_frame(0, 0, 0, 1.22))[:, (0, 1, 3)]
ground_from_calib_frame = np.linalg.inv(calib_frame_from_ground)
camera_frame_from_calib_frame = np.dot(camera_frame_from_ground, ground_from_calib_frame)
return camera_frame_from_calib_frame
diff --git a/common/transformations/setup.py b/common/transformations/setup.py
deleted file mode 100644
index 32546192d..000000000
--- a/common/transformations/setup.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import numpy
-
-from Cython.Build import cythonize
-from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
-from common.cython_hacks import BuildExtWithoutPlatformSuffix
-
-setup(
- name='Cython transformations wrapper',
- cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
- ext_modules=cythonize(
- Extension(
- "transformations",
- sources=["transformations.pyx"],
- language="c++",
- extra_compile_args=["-std=c++1z", "-Wno-cpp"],
- include_dirs=[numpy.get_include()],
- ),
- nthreads=4,
- )
-)
diff --git a/common/transformations/transformations.pyx b/common/transformations/transformations.pyx
index 12d6e2ab5..ce80d90d2 100644
--- a/common/transformations/transformations.pyx
+++ b/common/transformations/transformations.pyx
@@ -1,18 +1,20 @@
-from transformations cimport Matrix3, Vector3, Quaternion
-from transformations cimport ECEF, NED, Geodetic
+# distutils: language = c++
+# cython: language_level = 3
+from common.transformations.transformations cimport Matrix3, Vector3, Quaternion
+from common.transformations.transformations cimport ECEF, NED, Geodetic
-from transformations cimport euler2quat as euler2quat_c
-from transformations cimport quat2euler as quat2euler_c
-from transformations cimport quat2rot as quat2rot_c
-from transformations cimport rot2quat as rot2quat_c
-from transformations cimport euler2rot as euler2rot_c
-from transformations cimport rot2euler as rot2euler_c
-from transformations cimport rot_matrix as rot_matrix_c
-from transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c
-from transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c
-from transformations cimport geodetic2ecef as geodetic2ecef_c
-from transformations cimport ecef2geodetic as ecef2geodetic_c
-from transformations cimport LocalCoord_c
+from common.transformations.transformations cimport euler2quat as euler2quat_c
+from common.transformations.transformations cimport quat2euler as quat2euler_c
+from common.transformations.transformations cimport quat2rot as quat2rot_c
+from common.transformations.transformations cimport rot2quat as rot2quat_c
+from common.transformations.transformations cimport euler2rot as euler2rot_c
+from common.transformations.transformations cimport rot2euler as rot2euler_c
+from common.transformations.transformations cimport rot_matrix as rot_matrix_c
+from common.transformations.transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c
+from common.transformations.transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c
+from common.transformations.transformations cimport geodetic2ecef as geodetic2ecef_c
+from common.transformations.transformations cimport ecef2geodetic as ecef2geodetic_c
+from common.transformations.transformations cimport LocalCoord_c
import cython
diff --git a/opendbc/can/common.cc b/opendbc/can/common.cc
index 162137e0d..d3446cb52 100644
--- a/opendbc/can/common.cc
+++ b/opendbc/can/common.cc
@@ -97,18 +97,17 @@ unsigned int volkswagen_crc(unsigned int address, uint64_t d, int l) {
// a magic variable padding byte tacked onto the end of the payload.
// https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_CRCLibrary.pdf
- uint8_t *dat = (uint8_t *)&d;
uint8_t crc = 0xFF; // Standard init value for CRC8 8H2F/AUTOSAR
// CRC the payload first, skipping over the first byte where the CRC lives.
for (int i = 1; i < l; i++) {
- crc ^= dat[i];
+ crc ^= (d >> (i*8)) & 0xFF;
crc = crc8_lut_8h2f[crc];
}
// Look up and apply the magic final CRC padding byte, which permutes by CAN
// address, and additionally (for SOME addresses) by the message counter.
- uint8_t counter = dat[1] & 0x0F;
+ uint8_t counter = ((d >> 8) & 0xFF) & 0x0F;
switch(address) {
case 0x86: // LWI_01 Steering Angle
crc ^= (uint8_t[]){0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86}[counter];
@@ -176,11 +175,9 @@ unsigned int pedal_checksum(uint64_t d, int l) {
d >>= ((8-l)*8); // remove padding
d >>= 8; // remove checksum
- uint8_t *dat = (uint8_t *)&d;
-
int i, j;
for (i = 0; i < l - 1; i++) {
- crc ^= dat[i];
+ crc ^= (d >> (i*8)) & 0xFF;
for (j = 0; j < 8; j++) {
if ((crc & 0x80) != 0) {
crc = (uint8_t)((crc << 1) ^ poly);
diff --git a/opendbc/toyota_nodsu_pt_generated.dbc b/opendbc/toyota_nodsu_pt_generated.dbc
index e09310e4b..ce38bf50a 100644
--- a/opendbc/toyota_nodsu_pt_generated.dbc
+++ b/opendbc/toyota_nodsu_pt_generated.dbc
@@ -424,14 +424,6 @@ BO_ 956 GEAR_PACKET: 8 XXX
SG_ GEAR : 13|6@0+ (1,0) [0|63] "" XXX
SG_ ECON_ON : 40|1@0+ (1,0) [0|1] "" XXX
-BO_ 1653 Date_Time: 8 XXX
- SG_ Year : 23|8@0+ (1,0) [0|255] "" XXX
- SG_ Month : 31|8@0+ (1,0) [0|255] "" XXX
- SG_ Day : 39|8@0+ (1,0) [0|255] "" XXX
- SG_ Hour : 47|8@0+ (1,0) [0|255] "" XXX
- SG_ Minute : 55|8@0+ (1,0) [0|255] "" XXX
- SG_ Second : 63|8@0+ (1,0) [0|255] "" XXX
-
CM_ SG_ 548 BRAKE_PRESSURE "seems prop to pedal force";
CM_ SG_ 548 BRAKE_POSITION "seems proportional to pedal displacement, unclear the max value of 0x1c8";
CM_ SG_ 610 TYPE "seems 1 on Corolla, 0 on all others";
diff --git a/panda/board/boards/uno.h b/panda/board/boards/uno.h
index 96eb6268b..91f65a246 100644
--- a/panda/board/boards/uno.h
+++ b/panda/board/boards/uno.h
@@ -72,11 +72,9 @@ void uno_set_usb_power_mode(uint8_t mode) {
bool valid = false;
switch (mode) {
case USB_POWER_CLIENT:
- uno_set_phone_power(false);
valid = true;
break;
case USB_POWER_CDP:
- uno_set_phone_power(true);
uno_bootkick();
valid = true;
break;
diff --git a/release/build_release2.sh b/release/build_release2.sh
index 9378bb723..f47686a6b 100755
--- a/release/build_release2.sh
+++ b/release/build_release2.sh
@@ -35,7 +35,9 @@ else
git checkout --orphan release2-staging
fi
-VERSION=$(cat selfdrive/common/version.h | awk -F\" '{print $2}')
+VERSION=$(cat selfdrive/common/version.h | awk -F[\"-] '{print $2}')
+echo "#define COMMA_VERSION \"$VERSION-release\"" > selfdrive/common/version.h
+
git commit -m "openpilot v$VERSION"
# Build signed panda firmware
diff --git a/selfdrive/assets/offroad/circled-checkmark-empty.png b/selfdrive/assets/offroad/circled-checkmark-empty.png
new file mode 100644
index 000000000..e6740f110
Binary files /dev/null and b/selfdrive/assets/offroad/circled-checkmark-empty.png differ
diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript
index 8bfbbb127..5284785d3 100644
--- a/selfdrive/boardd/SConscript
+++ b/selfdrive/boardd/SConscript
@@ -1,4 +1,4 @@
-Import('env', 'common', 'cereal', 'messaging', 'cython_dependencies')
+Import('env', 'envCython', 'common', 'cereal', 'messaging')
# dp - Add read dp_disable_relay value
if FindFile('dp_disable_relay', '/data/params/d') != None:
with open('/data/params/d/dp_disable_relay') as f:
@@ -7,6 +7,4 @@ if FindFile('dp_disable_relay', '/data/params/d') != None:
env.Program('boardd', ['boardd.cc', 'panda.cc', 'pigeon.cc'], LIBS=['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'])
env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc'])
-env.Command(['boardd_api_impl.so', 'boardd_api_impl.cpp'],
- cython_dependencies + ['libcan_list_to_can_capnp.a', 'boardd_api_impl.pyx', 'boardd_setup.py'],
- "cd selfdrive/boardd && python3 boardd_setup.py build_ext --inplace")
+envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"])
diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc
index f20d3775f..5c98406e0 100644
--- a/selfdrive/boardd/boardd.cc
+++ b/selfdrive/boardd/boardd.cc
@@ -56,7 +56,9 @@ struct tm get_time(){
}
bool time_valid(struct tm sys_time){
- return 1900 + sys_time.tm_year >= 2019;
+ int year = 1900 + sys_time.tm_year;
+ int month = 1 + sys_time.tm_mon;
+ return (year > 2020) || (year == 2020 && month >= 10);
}
void safety_setter_thread() {
@@ -107,8 +109,9 @@ void safety_setter_thread() {
capnp::FlatArrayMessageReader cmsg(amsg);
cereal::CarParams::Reader car_params = cmsg.getRoot();
cereal::CarParams::SafetyModel safety_model = car_params.getSafetyModel();
- LOGW("setting unsafe mode");
- panda->set_unsafe_mode(9);
+
+ panda->set_unsafe_mode(9); // see safety_declarations.h for allowed values
+
auto safety_param = car_params.getSafetyParam();
LOGW("setting safety model: %d with param %d", (int)safety_model, safety_param);
diff --git a/selfdrive/boardd/boardd_setup.py b/selfdrive/boardd/boardd_setup.py
deleted file mode 100644
index 01ca05248..000000000
--- a/selfdrive/boardd/boardd_setup.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from distutils.core import Extension, setup
-from Cython.Build import cythonize
-
-from common.cython_hacks import BuildExtWithoutPlatformSuffix
-
-libraries = ['can_list_to_can_capnp', 'capnp', 'kj']
-
-setup(name='Boardd API Implementation',
- cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
- ext_modules=cythonize(
- Extension(
- "boardd_api_impl",
- libraries=libraries,
- library_dirs=[
- './',
- ],
- sources=['boardd_api_impl.pyx'],
- language="c++",
- extra_compile_args=["-std=c++1z", "-Wno-nullability-completeness"],
- )
- )
-)
diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc
index 9a8b2e703..c209cc4f8 100644
--- a/selfdrive/boardd/panda.cc
+++ b/selfdrive/boardd/panda.cc
@@ -188,8 +188,8 @@ void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, int sa
usb_write(0xdc, (uint16_t)safety_model, safety_param);
}
-void Panda::set_unsafe_mode(uint16_t wValue){
- usb_write(0xdf, wValue, 0);
+void Panda::set_unsafe_mode(uint16_t unsafe_mode) {
+ usb_write(0xdf, unsafe_mode, 0);
}
cereal::HealthData::HwType Panda::get_hw_type() {
@@ -283,7 +283,6 @@ const char* Panda::get_serial(){
delete[] serial_buf;
return NULL;
-
}
void Panda::set_power_saving(bool power_saving){
diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h
index 31124495d..119c123b1 100644
--- a/selfdrive/boardd/panda.h
+++ b/selfdrive/boardd/panda.h
@@ -63,7 +63,7 @@ class Panda {
// Panda functionality
cereal::HealthData::HwType get_hw_type();
void set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param=0);
- void set_unsafe_mode(uint16_t wValue);
+ void set_unsafe_mode(uint16_t unsafe_mode);
void set_rtc(struct tm sys_time);
struct tm get_rtc();
void set_fan_speed(uint16_t fan_speed);
diff --git a/selfdrive/camerad/SConscript b/selfdrive/camerad/SConscript
index e6b672ef4..2d2716a87 100644
--- a/selfdrive/camerad/SConscript
+++ b/selfdrive/camerad/SConscript
@@ -11,10 +11,6 @@ if arch == "aarch64":
elif arch == "larch64":
libs += ['atomic']
cameras = ['cameras/camera_qcom2.cc']
- # no screen
- # env = env.Clone()
- # env.Append(CXXFLAGS = '-DNOSCREEN')
- # env.Append(CFLAGS = '-DNOSCREEN')
else:
if USE_WEBCAM:
libs += ['opencv_core', 'opencv_highgui', 'opencv_imgproc', 'opencv_videoio']
@@ -28,8 +24,9 @@ else:
if arch == "Darwin":
del libs[libs.index('OpenCL')]
+ del libs[libs.index(gpucommon)][gpucommon.index('GL')]
env = env.Clone()
- env['FRAMEWORKS'] = ['OpenCL']
+ env['FRAMEWORKS'] = ['OpenCL', 'OpenGL']
env.SharedLibrary('snapshot/visionipc',
["#selfdrive/common/visionipc.c", "#selfdrive/common/ipc.c"])
diff --git a/selfdrive/camerad/cameras/camera_common.cc b/selfdrive/camerad/cameras/camera_common.cc
index 98cfe0929..c389dc497 100644
--- a/selfdrive/camerad/cameras/camera_common.cc
+++ b/selfdrive/camerad/cameras/camera_common.cc
@@ -24,6 +24,12 @@
#include "common/util.h"
#include "imgproc/utils.h"
+const int env_xmin = getenv("XMIN") ? atoi(getenv("XMIN")) : 0;
+const int env_xmax = getenv("XMAX") ? atoi(getenv("XMAX")) : -1;
+const int env_ymin = getenv("YMIN") ? atoi(getenv("YMIN")) : 0;
+const int env_ymax = getenv("YMAX") ? atoi(getenv("YMAX")) : -1;
+const int env_scale = getenv("SCALE") ? atoi(getenv("SCALE")) : 1;
+
static cl_program build_debayer_program(cl_device_id device_id, cl_context context, const CameraInfo *ci, const CameraBuf *b) {
char args[4096];
snprintf(args, sizeof(args),
@@ -207,7 +213,6 @@ void CameraBuf::stop() {
void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &frame_data, uint32_t cnt) {
framed.setFrameId(frame_data.frame_id);
- framed.setEncodeId(cnt);
framed.setTimestampEof(frame_data.timestamp_eof);
framed.setFrameLength(frame_data.frame_length);
framed.setIntegLines(frame_data.integ_lines);
@@ -219,6 +224,27 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr
framed.setGainFrac(frame_data.gain_frac);
}
+void fill_frame_image(cereal::FrameData::Builder &framed, uint8_t *dat, int w, int h, int stride) {
+ if (dat != nullptr) {
+ int scale = env_scale;
+ int x_min = env_xmin; int y_min = env_ymin; int x_max = w-1; int y_max = h-1;
+ if (env_xmax != -1) x_max = env_xmax;
+ if (env_ymax != -1) y_max = env_ymax;
+ int new_width = (x_max - x_min + 1) / scale;
+ int new_height = (y_max - y_min + 1) / scale;
+ uint8_t *resized_dat = new uint8_t[new_width*new_height*3];
+
+ int goff = x_min*3 + y_min*stride;
+ for (int r=0;rbuf;
@@ -402,5 +428,8 @@ void common_camera_process_front(SubMaster *sm, PubMaster *pm, CameraState *c, i
auto framed = msg.initEvent().initFrontFrame();
framed.setFrameType(cereal::FrameData::FrameType::FRONT);
fill_frame_data(framed, b->cur_frame_data, cnt);
+ if (env_send_front) {
+ fill_frame_image(framed, (uint8_t*)b->cur_rgb_buf->addr, b->rgb_width, b->rgb_height, b->rgb_stride);
+ }
pm->send("frontFrame", msg);
}
diff --git a/selfdrive/camerad/cameras/camera_qcom.cc b/selfdrive/camerad/cameras/camera_qcom.cc
index 6efcb2b5f..e0cdf7a23 100644
--- a/selfdrive/camerad/cameras/camera_qcom.cc
+++ b/selfdrive/camerad/cameras/camera_qcom.cc
@@ -1,4 +1,3 @@
-#include
#include
#include
#include
@@ -2141,6 +2140,9 @@ void camera_process_frame(MultiCameraState *s, CameraState *c, int cnt) {
MessageBuilder msg;
auto framed = msg.initEvent().initFrame();
fill_frame_data(framed, b->cur_frame_data, cnt);
+ if (env_send_rear) {
+ fill_frame_image(framed, (uint8_t*)b->cur_rgb_buf->addr, b->rgb_width, b->rgb_height, b->rgb_stride);
+ }
framed.setFocusVal(kj::ArrayPtr(&s->rear.focus[0], NUM_FOCUS));
framed.setFocusConf(kj::ArrayPtr(&s->rear.confidence[0], NUM_FOCUS));
framed.setSharpnessScore(kj::ArrayPtr(&s->lapres[0], ARRAYSIZE(s->lapres)));
diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py
index 15583c776..19ccbf297 100644
--- a/selfdrive/car/car_helpers.py
+++ b/selfdrive/car/car_helpers.py
@@ -13,24 +13,20 @@ from common.dp_common import is_online
import threading
import selfdrive.crash as crash
-from cereal import car, log
+from cereal import car
EventName = car.CarEvent.EventName
-HwType = log.HealthData.HwType
-def get_startup_event(car_recognized, controller_available, hw_type):
- # if comma_remote and tested_branch:
- # event = EventName.startup
- # else:
- # event = EventName.startupMaster
- event = EventName.startup
+def get_startup_event(car_recognized, controller_available):
+ if comma_remote and tested_branch:
+ event = EventName.startup
+ else:
+ event = EventName.startupMaster
if not car_recognized:
event = EventName.startupNoCar
elif car_recognized and not controller_available:
event = EventName.startupNoControl
- # elif hw_type == HwType.greyPanda:
- # event = EventName.startupGreyPanda
return event
@@ -89,15 +85,22 @@ def only_toyota_left(candidate_cars):
# **** for use live only ****
-def fingerprint(logcan, sendcan, has_relay):
- fixed_fingerprint = os.environ.get('FINGERPRINT', "") or Params().get('dp_car_selected', encoding='utf8')
+def fingerprint(logcan, sendcan):
+ params = Params()
+ car_selected = params.get('dp_car_selected', encoding='utf8')
+ car_detected = params.get('dp_car_detected', encoding='utf8')
+ if car_selected == "" and car_detected != "":
+ params.put('dp_car_selected', car_detected)
+ params.put('dp_car_detected', "")
+
+ fixed_fingerprint = os.environ.get('FINGERPRINT', "") or params.get('dp_car_selected', encoding='utf8')
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False)
- if has_relay and not fixed_fingerprint and not skip_fw_query:
+ if not fixed_fingerprint and not skip_fw_query:
# Vin query only reliably works thorugh OBDII
bus = 1
- cached_params = Params().get("CarParamsCache")
+ cached_params = params.get("CarParamsCache")
if cached_params is not None:
cached_params = car.CarParams.from_bytes(cached_params)
if cached_params.carName == "mock":
@@ -149,8 +152,7 @@ def fingerprint(logcan, sendcan, has_relay):
# Toyota needs higher time to fingerprint, since DSU does not broadcast immediately
if only_toyota_left(candidate_cars[b]):
frame_fingerprint = 100 # 1s
- if len(candidate_cars[b]) == 1:
- if frame > frame_fingerprint:
+ if len(candidate_cars[b]) == 1 and frame > frame_fingerprint:
# fingerprint done
car_fingerprint = candidate_cars[b][0]
@@ -177,8 +179,8 @@ def fingerprint(logcan, sendcan, has_relay):
return car_fingerprint, finger, vin, car_fw, source
-def get_car(logcan, sendcan, has_relay=False):
- candidate, fingerprints, vin, car_fw, source = fingerprint(logcan, sendcan, has_relay)
+def get_car(logcan, sendcan):
+ candidate, fingerprints, vin, car_fw, source = fingerprint(logcan, sendcan)
if candidate is None:
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)
@@ -189,7 +191,7 @@ def get_car(logcan, sendcan, has_relay=False):
x.start()
CarInterface, CarController, CarState = interfaces[candidate]
- car_params = CarInterface.get_params(candidate, fingerprints, has_relay, car_fw)
+ car_params = CarInterface.get_params(candidate, fingerprints, car_fw)
car_params.carVin = vin
car_params.carFw = car_fw
car_params.fingerprintSource = source
diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py
index 268d7b0d5..260f8fc10 100755
--- a/selfdrive/car/chrysler/interface.py
+++ b/selfdrive/car/chrysler/interface.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
from cereal import car
-from selfdrive.car.chrysler.values import Ecu, ECU_FINGERPRINT, CAR, FINGERPRINTS
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
+from selfdrive.car.chrysler.values import CAR
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
from common.dp_common import common_interface_atl, common_interface_get_params_lqr
@@ -11,11 +11,11 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 3.0
@staticmethod
- def get_params(candidate, fingerprint=None, has_relay=False, car_fw=None):
+ def get_params(candidate, fingerprint=None, car_fw=None):
if fingerprint is None:
fingerprint = gen_empty_fingerprint()
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "chrysler"
ret.safetyModel = car.CarParams.SafetyModel.chrysler
ret.lateralTuning.init('pid')
@@ -56,8 +56,7 @@ class CarInterface(CarInterfaceBase):
# mass and CG position, so all cars will have approximately similar dyn behaviors
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront)
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
- print("ECU Camera Simulated: {0}".format(ret.enableCamera))
+ ret.enableCamera = True
return ret
diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py
index b7fb53f53..88110f053 100644
--- a/selfdrive/car/chrysler/values.py
+++ b/selfdrive/car/chrysler/values.py
@@ -91,8 +91,3 @@ DBC = {
}
STEER_THRESHOLD = 120
-
-
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [0x292], # lkas cmd
-}
diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py
index e04ab0588..95f02706e 100755
--- a/selfdrive/car/ford/interface.py
+++ b/selfdrive/car/ford/interface.py
@@ -2,8 +2,8 @@
from cereal import car
from selfdrive.swaglog import cloudlog
from selfdrive.config import Conversions as CV
-from selfdrive.car.ford.values import MAX_ANGLE, Ecu, ECU_FINGERPRINT, FINGERPRINTS
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
+from selfdrive.car.ford.values import MAX_ANGLE
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
from common.dp_common import common_interface_atl, common_interface_get_params_lqr
@@ -14,8 +14,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 3.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "ford"
ret.safetyModel = car.CarParams.SafetyModel.ford
ret.dashcamOnly = True
@@ -47,7 +47,7 @@ class CarInterface(CarInterfaceBase):
ret.steerControlType = car.CarParams.SteerControlType.angle
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.enableCamera = True
cloudlog.warning("ECU Camera Simulated: %r", ret.enableCamera)
return ret
diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py
index 7c4d0aed9..315c398ab 100644
--- a/selfdrive/car/ford/values.py
+++ b/selfdrive/car/ford/values.py
@@ -15,10 +15,6 @@ FINGERPRINTS = {
}],
}
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [970, 973, 984]
-}
-
DBC = {
CAR.FUSION: dbc_dict('ford_fusion_2018_pt', 'ford_fusion_2018_adas'),
}
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index 82c490a06..562cdb48e 100755
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
-from selfdrive.car.gm.values import CAR, Ecu, ECU_FINGERPRINT, CruiseButtons, \
- AccState, FINGERPRINTS
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
+from selfdrive.car.gm.values import CAR, CruiseButtons, \
+ AccState
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
from common.dp_common import common_interface_atl, common_interface_get_params_lqr
@@ -17,8 +17,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "gm"
ret.safetyModel = car.CarParams.SafetyModel.gm
ret.enableCruise = False # stock cruise control is kept off
@@ -31,7 +31,7 @@ class CarInterface(CarInterfaceBase):
# Presence of a camera on the object bus is ok.
# Have to go to read_only if ASCM is online (ACC-enabled cars),
# or camera is on powertrain bus (LKA cars without ACC).
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.enableCamera = True
ret.openpilotLongitudinalControl = ret.enableCamera
tire_stiffness_factor = 0.444 # not optimized yet
diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py
index efe696f8a..5e50e6166 100644
--- a/selfdrive/car/gm/values.py
+++ b/selfdrive/car/gm/values.py
@@ -70,10 +70,6 @@ FINGERPRINTS = {
STEER_THRESHOLD = 1.0
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [384, 715] # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
-}
-
DBC = {
CAR.HOLDEN_ASTRA: dbc_dict('gm_global_a_powertrain', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis'),
CAR.VOLT: dbc_dict('gm_global_a_powertrain', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis'),
diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py
index 06b1531e9..3cadfa2d6 100644
--- a/selfdrive/car/honda/carcontroller.py
+++ b/selfdrive/car/honda/carcontroller.py
@@ -179,37 +179,35 @@ class CarController():
# Send steering command.
idx = frame % 4
can_sends.append(hondacan.create_steering_control(self.packer, apply_steer,
- lkas_active, CS.CP.carFingerprint, idx, CS.CP.isPandaBlack, CS.CP.openpilotLongitudinalControl))
+ lkas_active, CS.CP.carFingerprint, idx, CS.CP.openpilotLongitudinalControl))
# Send dashboard UI commands.
if not dragonconf.dpAtl and (frame % 10) == 0:
idx = (frame//10) % 4
- can_sends.extend(hondacan.create_ui_commands(self.packer, pcm_speed, hud, CS.CP.carFingerprint, CS.is_metric, idx, CS.CP.isPandaBlack, CS.CP.openpilotLongitudinalControl, CS.stock_hud))
+ can_sends.extend(hondacan.create_ui_commands(self.packer, pcm_speed, hud, CS.CP.carFingerprint, CS.is_metric, idx, CS.CP.openpilotLongitudinalControl, CS.stock_hud))
if not CS.CP.openpilotLongitudinalControl:
if (frame % 2) == 0:
idx = frame // 2
- can_sends.append(hondacan.create_bosch_supplemental_1(self.packer, CS.CP.carFingerprint, idx, CS.CP.isPandaBlack))
+ can_sends.append(hondacan.create_bosch_supplemental_1(self.packer, CS.CP.carFingerprint, idx))
if dragonconf.dpAtl:
pass
# If using stock ACC, spam cancel command to kill gas when OP disengages.
elif not dragonconf.dpAllowGas and pcm_cancel_cmd:
- can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.CANCEL, idx, CS.CP.carFingerprint, CS.CP.isPandaBlack))
+ can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.CANCEL, idx, CS.CP.carFingerprint))
elif CS.out.cruiseState.standstill:
if CS.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH):
rough_lead_speed = self.rough_speed(CS.lead_distance)
if CS.lead_distance > (self.stopped_lead_distance + 15.0) or rough_lead_speed > 0.1:
self.stopped_lead_distance = 0.0
can_sends.append(
- hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint,
- CS.CP.isPandaBlack))
+ hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint))
elif CS.CP.carFingerprint in (CAR.CIVIC_BOSCH, CAR.CRV_HYBRID):
if CS.hud_lead == 1:
can_sends.append(
- hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint,
- CS.CP.isPandaBlack))
+ hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint))
else:
- can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint,CS.CP.isPandaBlack))
+ can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint))
else:
self.stopped_lead_distance = CS.lead_distance
self.prev_lead_distance = CS.lead_distance
@@ -226,7 +224,7 @@ class CarController():
apply_brake = int(clip(self.brake_last * P.BRAKE_MAX, 0, P.BRAKE_MAX - 1))
pump_on, self.last_pump_ts = brake_pump_hysteresis(apply_brake, self.apply_brake_last, self.last_pump_ts, ts)
can_sends.append(hondacan.create_brake_command(self.packer, apply_brake, pump_on,
- pcm_override, pcm_cancel_cmd, hud.fcw, idx, CS.CP.carFingerprint, CS.CP.isPandaBlack, CS.stock_brake))
+ pcm_override, pcm_cancel_cmd, hud.fcw, idx, CS.CP.carFingerprint, CS.stock_brake))
self.apply_brake_last = apply_brake
if CS.CP.enableGasInterceptor:
diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py
index 2c90d6653..9ef90b5bb 100644
--- a/selfdrive/car/honda/carstate.py
+++ b/selfdrive/car/honda/carstate.py
@@ -361,7 +361,7 @@ class CarState(CarStateBase):
@staticmethod
def get_can_parser(CP):
signals, checks = get_can_signals(CP)
- bus_pt = 1 if CP.isPandaBlack and CP.carFingerprint in HONDA_BOSCH else 0
+ bus_pt = 1 if CP.carFingerprint in HONDA_BOSCH else 0
checks = []
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, bus_pt)
@@ -386,10 +386,8 @@ class CarState(CarStateBase):
checks = [(0xe4, 100)]
if CP.carFingerprint in [CAR.CRV, CAR.CRV_EU, CAR.ACURA_RDX, CAR.ODYSSEY_CHN]:
checks = [(0x194, 100)]
-
- bus_cam = 1 if CP.carFingerprint in HONDA_BOSCH and not CP.isPandaBlack else 2
checks = []
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, bus_cam)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
@staticmethod
def get_body_can_parser(CP):
diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py
index 45aea3fc1..ef2564702 100644
--- a/selfdrive/car/honda/hondacan.py
+++ b/selfdrive/car/honda/hondacan.py
@@ -7,24 +7,19 @@ from selfdrive.car.honda.values import HONDA_BOSCH
# 2 = ACC-CAN - camera side
# 3 = F-CAN A - OBDII port
-# CAN bus layout with giraffe
-# 0 = F-CAN B - powertrain
-# 1 = ACC-CAN - camera side
-# 2 = ACC-CAN - radar side
-
-def get_pt_bus(car_fingerprint, has_relay):
- return 1 if car_fingerprint in HONDA_BOSCH and has_relay else 0
+def get_pt_bus(car_fingerprint):
+ return 1 if car_fingerprint in HONDA_BOSCH else 0
-def get_lkas_cmd_bus(car_fingerprint, has_relay, radar_disabled=False):
+def get_lkas_cmd_bus(car_fingerprint, radar_disabled=False):
if radar_disabled:
# when radar is disabled, steering commands are sent directly to powertrain bus
- return get_pt_bus(car_fingerprint, has_relay)
+ return get_pt_bus(car_fingerprint)
# normally steering commands are sent to radar, which forwards them to powertrain bus
- return 2 if car_fingerprint in HONDA_BOSCH and not has_relay else 0
+ return 0
-def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, has_relay, stock_brake):
+def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, stock_brake):
# TODO: do we loose pressure if we keep pump off for long?
brakelights = apply_brake > 0
brake_rq = apply_brake > 0
@@ -45,13 +40,13 @@ def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_
"AEB_REQ_2": 0,
"AEB_STATUS": 0,
}
- bus = get_pt_bus(car_fingerprint, has_relay)
+ bus = get_pt_bus(car_fingerprint)
return packer.make_can_msg("BRAKE_COMMAND", bus, values, idx)
-def create_acc_commands(packer, enabled, accel, gas, idx, stopping, starting, car_fingerprint, has_relay):
+def create_acc_commands(packer, enabled, accel, gas, idx, stopping, starting, car_fingerprint):
commands = []
- bus = get_pt_bus(car_fingerprint, has_relay)
+ bus = get_pt_bus(car_fingerprint)
control_on = 5 if enabled else 0
# no gas = -30000
@@ -84,31 +79,31 @@ def create_acc_commands(packer, enabled, accel, gas, idx, stopping, starting, ca
return commands
-def create_steering_control(packer, apply_steer, lkas_active, car_fingerprint, idx, has_relay, radar_disabled):
+def create_steering_control(packer, apply_steer, lkas_active, car_fingerprint, idx, radar_disabled):
values = {
"STEER_TORQUE": apply_steer if lkas_active else 0,
"STEER_TORQUE_REQUEST": lkas_active,
}
- bus = get_lkas_cmd_bus(car_fingerprint, has_relay, radar_disabled)
+ bus = get_lkas_cmd_bus(car_fingerprint, radar_disabled)
return packer.make_can_msg("STEERING_CONTROL", bus, values, idx)
-def create_bosch_supplemental_1(packer, car_fingerprint, idx, has_relay):
+def create_bosch_supplemental_1(packer, car_fingerprint, idx):
# non-active params
values = {
"SET_ME_X04": 0x04,
"SET_ME_X80": 0x80,
"SET_ME_X10": 0x10,
}
- bus = get_lkas_cmd_bus(car_fingerprint, has_relay)
+ bus = get_lkas_cmd_bus(car_fingerprint)
return packer.make_can_msg("BOSCH_SUPPLEMENTAL_1", bus, values, idx)
-def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx, has_relay, openpilot_longitudinal_control, stock_hud):
+def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx, openpilot_longitudinal_control, stock_hud):
commands = []
- bus_pt = get_pt_bus(car_fingerprint, has_relay)
+ bus_pt = get_pt_bus(car_fingerprint)
radar_disabled = car_fingerprint in HONDA_BOSCH and openpilot_longitudinal_control
- bus_lkas = get_lkas_cmd_bus(car_fingerprint, has_relay, radar_disabled)
+ bus_lkas = get_lkas_cmd_bus(car_fingerprint, radar_disabled)
if openpilot_longitudinal_control:
if car_fingerprint in HONDA_BOSCH:
@@ -158,10 +153,10 @@ def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx,
return commands
-def spam_buttons_command(packer, button_val, idx, car_fingerprint, has_relay):
+def spam_buttons_command(packer, button_val, idx, car_fingerprint):
values = {
'CRUISE_BUTTONS': button_val,
'CRUISE_SETTING': 0,
}
- bus = get_pt_bus(car_fingerprint, has_relay)
+ bus = get_pt_bus(car_fingerprint)
return packer.make_can_msg("SCM_BUTTONS", bus, values, idx)
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index 167757330..7f2eeb2ea 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -6,8 +6,8 @@ from common.realtime import DT_CTRL
from selfdrive.swaglog import cloudlog
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.events import ET
-from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH, Ecu, ECU_FINGERPRINT, FINGERPRINTS
-from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
+from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH
+from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.controls.lib.planner import _A_CRUISE_MAX_V_FOLLOWING
from selfdrive.car.interfaces import CarInterfaceBase
from common.dp_common import common_interface_atl, common_interface_get_params_lqr
@@ -121,20 +121,19 @@ class CarInterface(CarInterfaceBase):
return float(max(max_accel, a_target / A_ACC_MAX)) * min(speedLimiter, accelLimiter)
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[]): # pylint: disable=dangerous-default-value
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "honda"
ret.lateralTuning.init('pid')
if candidate in HONDA_BOSCH:
- ret.safetyModel = car.CarParams.SafetyModel.hondaBoschHarness if has_relay else car.CarParams.SafetyModel.hondaBoschGiraffe
- rdr_bus = 0 if has_relay else 2
- ret.enableCamera = is_ecu_disconnected(fingerprint[rdr_bus], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.safetyModel = car.CarParams.SafetyModel.hondaBoschHarness
+ ret.enableCamera = True
ret.radarOffCan = True
ret.openpilotLongitudinalControl = False
else:
ret.safetyModel = car.CarParams.SafetyModel.hondaNidec
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.enableCamera = True
ret.enableGasInterceptor = 0x201 in fingerprint[0]
ret.openpilotLongitudinalControl = ret.enableCamera
diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py
index db6c5db7b..1cd049065 100644
--- a/selfdrive/car/honda/values.py
+++ b/selfdrive/car/honda/values.py
@@ -1065,10 +1065,4 @@ SPEED_FACTOR = {
CAR.INSIGHT: 1.,
}
-# msgs sent for steering controller by camera module on can 0.
-# those messages are mutually exclusive on CRV and non-CRV cars
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [0xE4, 0x194], # steer torque cmd
-}
-
HONDA_BOSCH = set([CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G])
diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py
index 61fc6e53e..be1b897f1 100644
--- a/selfdrive/car/hyundai/carcontroller.py
+++ b/selfdrive/car/hyundai/carcontroller.py
@@ -17,10 +17,7 @@ def process_hud_alert(enabled, fingerprint, visual_alert, left_lane,
# initialize to no line visible
sys_state = 1
if left_lane and right_lane or sys_warning: # HUD alert only display when LKAS status is active
- if enabled or sys_warning:
- sys_state = 3
- else:
- sys_state = 4
+ sys_state = 3 if enabled or sys_warning else 4
elif left_lane:
sys_state = 5
elif right_lane:
@@ -71,7 +68,7 @@ class CarController():
self.apply_steer_last = apply_steer
- sys_warning, sys_state, left_lane_warning, right_lane_warning =\
+ sys_warning, sys_state, left_lane_warning, right_lane_warning = \
process_hud_alert(enabled, self.car_fingerprint, visual_alert,
left_lane, right_lane, left_lane_depart, right_lane_depart)
diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py
index 2224b1de1..d3cac25dd 100644
--- a/selfdrive/car/hyundai/interface.py
+++ b/selfdrive/car/hyundai/interface.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
-from selfdrive.car.hyundai.values import Ecu, ECU_FINGERPRINT, CAR, FINGERPRINTS
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
+from selfdrive.car.hyundai.values import CAR
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
from common.dp_common import common_interface_atl, common_interface_get_params_lqr
from common.params import Params
@@ -14,8 +14,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 3.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[]): # pylint: disable=dangerous-default-value
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "hyundai"
ret.safetyModel = car.CarParams.SafetyModel.hyundai
@@ -155,7 +155,7 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.75
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.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
# Genesis
elif candidate == CAR.GENESIS_G70:
@@ -191,7 +191,7 @@ class CarInterface(CarInterfaceBase):
# these cars require a special panda safety mode due to missing counters and checksums in the messages
if candidate in [CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_2019,
- CAR.KIA_NIRO_EV, CAR.KIA_OPTIMA, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70]:
+ CAR.KIA_NIRO_EV, CAR.KIA_OPTIMA, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70, CAR.GENESIS_G80]:
ret.safetyModel = car.CarParams.SafetyModel.hyundaiLegacy
ret.centerToFront = ret.wheelbase * 0.4
@@ -210,7 +210,7 @@ class CarInterface(CarInterfaceBase):
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront,
tire_stiffness_factor=tire_stiffness_factor)
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.enableCamera = True
return ret
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py
index bb6716626..e98e4b8d1 100644
--- a/selfdrive/car/hyundai/values.py
+++ b/selfdrive/car/hyundai/values.py
@@ -156,12 +156,8 @@ FINGERPRINTS = {
}]
}
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [832, 1156, 1191, 1342]
-}
-
# Don't use these fingerprints for fingerprinting, they are still used for ECU detection
-IGNORED_FINGERPRINTS = [CAR.VELOSTER, CAR.KONA]
+IGNORED_FINGERPRINTS = [CAR.VELOSTER, CAR.GENESIS_G70, CAR.KONA]
FW_VERSIONS = {
CAR.SONATA: {
diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py
index 159f5e105..3a676cd28 100644
--- a/selfdrive/car/interfaces.py
+++ b/selfdrive/car/interfaces.py
@@ -44,15 +44,15 @@ class CarInterfaceBase():
raise NotImplementedError
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
raise NotImplementedError
# returns a set of default params to avoid repetition in car specific params
@staticmethod
- def get_std_params(candidate, fingerprint, has_relay):
+ def get_std_params(candidate, fingerprint):
ret = car.CarParams.new_message()
ret.carFingerprint = candidate
- ret.isPandaBlack = has_relay
+ ret.isPandaBlack = True # TODO: deprecate this field
# standard ALC params
ret.steerControlType = car.CarParams.SteerControlType.torque
diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py
index 0a3a07539..2046f52ab 100755
--- a/selfdrive/car/mazda/interface.py
+++ b/selfdrive/car/mazda/interface.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
-from selfdrive.car.mazda.values import CAR, LKAS_LIMITS, FINGERPRINTS, ECU_FINGERPRINT, Ecu
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, is_ecu_disconnected
+from selfdrive.car.mazda.values import CAR, LKAS_LIMITS
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
from common.dp_common import common_interface_atl, common_interface_get_params_lqr
@@ -16,8 +16,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "mazda"
ret.safetyModel = car.CarParams.SafetyModel.mazda
@@ -72,7 +72,7 @@ class CarInterface(CarInterfaceBase):
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront,
tire_stiffness_factor=tire_stiffness_factor)
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.enableCamera = True
return ret
diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py
index 4e194d61d..81c2b2b4a 100644
--- a/selfdrive/car/mazda/values.py
+++ b/selfdrive/car/mazda/values.py
@@ -71,10 +71,6 @@ FINGERPRINTS = {
],
}
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [579], # steer torque cmd
-}
-
DBC = {
CAR.CX5: dbc_dict('mazda_2017', None),
diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py
index db665874b..39f429878 100755
--- a/selfdrive/car/mock/interface.py
+++ b/selfdrive/car/mock/interface.py
@@ -33,8 +33,8 @@ class CarInterface(CarInterfaceBase):
return accel
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "mock"
ret.safetyModel = car.CarParams.SafetyModel.noOutput
ret.mass = 1700.
diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py
index d63dded10..0df29c765 100644
--- a/selfdrive/car/nissan/interface.py
+++ b/selfdrive/car/nissan/interface.py
@@ -15,9 +15,9 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "nissan"
ret.safetyModel = car.CarParams.SafetyModel.nissan
ret.lateralTuning.init('pid')
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index 83d6da570..76e338350 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -12,8 +12,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "subaru"
ret.radarOffCan = True
@@ -26,11 +26,8 @@ class CarInterface(CarInterfaceBase):
# Subaru port is a community feature, since we don't own one to test
ret.communityFeature = True
-
ret.dashcamOnly = candidate in PREGLOBAL_CARS
- # force openpilot to fake the stock camera, since car harness is not supported yet and old style giraffe (with switches)
- # was never released
ret.enableCamera = True
ret.steerRateCost = 0.7
diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py
index 8cbb6fe72..937728d88 100644
--- a/selfdrive/car/subaru/values.py
+++ b/selfdrive/car/subaru/values.py
@@ -78,10 +78,6 @@ STEER_THRESHOLD = {
CAR.OUTBACK_PREGLOBAL_2018: 75,
}
-ECU_FINGERPRINT = {
- Ecu.fwdCamera: [290, 356], # steer torque cmd
-}
-
DBC = {
CAR.ASCENT: dbc_dict('subaru_global_2017_generated', None),
CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None),
diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py
index 069d5af00..be05c9d06 100755
--- a/selfdrive/car/tests/test_car_interfaces.py
+++ b/selfdrive/car/tests/test_car_interfaces.py
@@ -25,36 +25,35 @@ class TestCarInterfaces(unittest.TestCase):
car_fw = []
- for has_relay in [True, False]:
- car_params = CarInterface.get_params(car_name, fingerprints, has_relay, 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)
- 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.assertGreater(car_params.lateralTuning.indi.outerLoopGain, 1e-3)
+ 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.assertGreater(car_params.lateralTuning.indi.outerLoopGain, 1e-3)
- # 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
diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py
index 8416b1346..0e4913229 100755
--- a/selfdrive/car/toyota/interface.py
+++ b/selfdrive/car/toyota/interface.py
@@ -22,8 +22,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 3.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[]): # pylint: disable=dangerous-default-value
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "toyota"
ret.safetyModel = car.CarParams.SafetyModel.toyota
@@ -325,7 +325,7 @@ class CarInterface(CarInterfaceBase):
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront,
tire_stiffness_factor=tire_stiffness_factor)
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay
+ ret.enableCamera = True
# Detect smartDSU, which intercepts ACC_CMD from the DSU allowing openpilot to send it
smartDsu = 0x2FF in fingerprint[0]
# In TSS2 cars the camera does long control
@@ -390,8 +390,6 @@ class CarInterface(CarInterfaceBase):
# events
events = self.create_common_events(ret)
- if self.cp_cam.can_invalid_cnt >= 200 and self.CP.enableCamera and not self.CP.isPandaBlack:
- events.add(EventName.invalidGiraffeToyota)
if self.CS.low_speed_lockout and self.CP.openpilotLongitudinalControl:
events.add(EventName.lowSpeedLockout)
if ret.vEgo < self.CP.minEnableSpeed and self.CP.openpilotLongitudinalControl:
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index 75c1c62f3..c6120264d 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -347,7 +347,7 @@ FINGERPRINTS = {
}
# Don't use theses fingerprints for fingerprinting, they are still needed for ECU detection
-IGNORED_FINGERPRINTS = [CAR.HIGHLANDERH_TSS2, CAR.LEXUS_RXH_TSS2, CAR.PRIUS_TSS2, CAR.LEXUS_NX]
+IGNORED_FINGERPRINTS = [CAR.RAV4H_TSS2, CAR.HIGHLANDERH_TSS2, CAR.LEXUS_RXH_TSS2, CAR.PRIUS_TSS2, CAR.LEXUS_NX]
FW_VERSIONS = {
CAR.AVALON: {
diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py
index f74b5affd..44f65b537 100644
--- a/selfdrive/car/volkswagen/interface.py
+++ b/selfdrive/car/volkswagen/interface.py
@@ -30,9 +30,8 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
- ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
- ret.lateralTuning.init('pid')
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
+ ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
# Set global default parameters
ret.radarOffCan = True
diff --git a/selfdrive/common/clutil.c b/selfdrive/common/clutil.c
index 00d63cdca..dbfc55453 100644
--- a/selfdrive/common/clutil.c
+++ b/selfdrive/common/clutil.c
@@ -39,7 +39,7 @@ void clu_init(void) {
cl_device_id cl_get_device_id(cl_device_type device_type) {
bool opencl_platform_found = false;
cl_device_id device_id = NULL;
-
+
cl_uint num_platforms = 0;
int err = clGetPlatformIDs(0, NULL, &num_platforms);
assert(err == 0);
@@ -66,7 +66,7 @@ cl_device_id cl_get_device_id(cl_device_type device_type) {
break;
}
free(platform_ids);
-
+
if (!opencl_platform_found) {
printf("No valid openCL platform found\n");
assert(opencl_platform_found);
diff --git a/selfdrive/common/i2c.cc b/selfdrive/common/i2c.cc
index a37b144dc..95d0aedd5 100644
--- a/selfdrive/common/i2c.cc
+++ b/selfdrive/common/i2c.cc
@@ -12,7 +12,10 @@
#ifdef QCOM2
// TODO: decide if we want to isntall libi2c-dev everywhere
-#include
+extern "C" {
+ #include
+ #include
+}
I2CBus::I2CBus(uint8_t bus_id){
char bus_name[20];
diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc
index c89144d49..da799d71d 100644
--- a/selfdrive/common/params.cc
+++ b/selfdrive/common/params.cc
@@ -49,30 +49,17 @@ void params_sig_handler(int signal) {
}
static int fsync_dir(const char* path){
- int result = 0;
int fd = open(path, O_RDONLY, 0755);
-
if (fd < 0){
- result = -1;
- goto cleanup;
- }
-
- result = fsync(fd);
- if (result < 0) {
- goto cleanup;
- }
-
- cleanup:
- int result_close = 0;
- if (fd >= 0){
- result_close = close(fd);
+ return -1;
}
+ int result = fsync(fd);
+ int result_close = close(fd);
if (result_close < 0) {
- return result_close;
- } else {
- return result;
+ result = result_close;
}
+ return result;
}
static int mkdir_p(std::string path) {
@@ -237,10 +224,6 @@ cleanup:
}
int Params::delete_db_value(std::string key) {
- return delete_db_value(key.c_str());
-}
-
-int Params::delete_db_value(const char* key) {
int lock_fd = -1;
int result;
std::string path;
@@ -256,7 +239,7 @@ int Params::delete_db_value(const char* key) {
}
// Delete value.
- path = params_path + "/d/" + std::string(key);
+ path = params_path + "/d/" + key;
result = remove(path.c_str());
if (result != 0) {
result = ERR_NO_VALUE;
diff --git a/selfdrive/common/params.h b/selfdrive/common/params.h
index d8c96a8cb..8da077cfd 100644
--- a/selfdrive/common/params.h
+++ b/selfdrive/common/params.h
@@ -33,7 +33,6 @@ public:
// 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);
- int delete_db_value(const char* key);
// Reads a value from the params database, blocking until successful.
// Inputs are the same as read_db_value.
diff --git a/selfdrive/common/spinner.h b/selfdrive/common/spinner.h
deleted file mode 100644
index fd35dcc7d..000000000
--- a/selfdrive/common/spinner.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef COMMON_SPINNER_H
-#define COMMON_SPINNER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int spin(int argc, char** argv);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/selfdrive/common/version.h b/selfdrive/common/version.h
index fb8618cd8..1bcd91ec6 100644
--- a/selfdrive/common/version.h
+++ b/selfdrive/common/version.h
@@ -1 +1 @@
-#define COMMA_VERSION "0.7.10-release"
+#define COMMA_VERSION "0.8.0-d56e04c0-2020-11-24T21:53:22"
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index 9721cf39c..20375d9a8 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -69,12 +69,10 @@ class Controls:
self.can_sock = messaging.sub_sock('can', timeout=can_timeout)
# wait for one health and one CAN packet
- hw_type = messaging.recv_one(self.sm.sock['health']).health.hwType
- has_relay = hw_type in [HwType.blackPanda, HwType.uno, HwType.dos]
print("Waiting for CAN messages...")
get_one_can(self.can_sock)
- self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], has_relay)
+ self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'])
# read params
params = Params()
@@ -141,7 +139,7 @@ class Controls:
self.sm['dMonitoringState'].awarenessStatus = 1.
self.sm['dMonitoringState'].faceDetected = False
- self.startup_event = get_startup_event(car_recognized, controller_available, hw_type)
+ self.startup_event = get_startup_event(car_recognized, controller_available)
# if not sounds_available:
# self.events.add(EventName.soundsUnavailable, static=True)
@@ -151,8 +149,6 @@ class Controls:
self.events.add(EventName.communityFeatureDisallowed, static=True)
if not car_recognized:
self.events.add(EventName.carUnrecognized, static=True)
- # if hw_type == HwType.whitePanda:
- # self.events.add(EventName.whitePandaUnsupported, static=True)
# controlsd is driven by can recv, expected at 100Hz
self.rk = Ratekeeper(100, print_delay_threshold=None)
@@ -228,7 +224,8 @@ class Controls:
if self.can_rcv_error or (not CS.canValid and self.sm.frame > 5 / DT_CTRL):
self.events.add(EventName.pcmDisable if self.sm['dragonConf'].dpAtl else EventName.canError)
- if self.mismatch_counter >= 200:
+ if (self.sm['health'].safetyModel != self.CP.safetyModel and self.sm.frame > 2 / DT_CTRL) or \
+ self.mismatch_counter >= 200:
self.events.add(EventName.controlsMismatch)
if not self.sm.alive['plan'] and self.sm.alive['pathPlan']:
# only plan not being received: radar not communicating
@@ -520,7 +517,7 @@ class Controls:
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
force_decel = (self.sm['dMonitoringState'].awarenessStatus < 0.) or \
- (self.state == State.softDisabling)
+ (self.state == State.softDisabling)
steer_angle_rad = (CS.steeringAngle - self.sm['pathPlan'].angleOffset) * CV.DEG_TO_RAD
diff --git a/selfdrive/controls/lib/alerts_offroad.json b/selfdrive/controls/lib/alerts_offroad.json
index f343f4cd5..a47eb8c0a 100644
--- a/selfdrive/controls/lib/alerts_offroad.json
+++ b/selfdrive/controls/lib/alerts_offroad.json
@@ -36,5 +36,9 @@
"Offroad_NeosUpdate": {
"text": "An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.",
"severity": 0
+ },
+ "Offroad_HardwareUnsupported": {
+ "text": "White and grey panda are unsupported. Upgrade to comma two or black panda.",
+ "severity": 0
}
}
diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py
index 2e2a79173..83c4653a8 100644
--- a/selfdrive/controls/lib/events.py
+++ b/selfdrive/controls/lib/events.py
@@ -257,31 +257,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
},
- EventName.startupGreyPanda: {
- ET.PERMANENT: Alert(
- "WARNING: Grey panda is deprecated",
- "Upgrade to comma two or black panda",
- AlertStatus.userPrompt, AlertSize.mid,
- Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
- },
-
- EventName.invalidGiraffeToyota: {
- ET.PERMANENT: Alert(
- _("Unsupported Giraffe Configuration"),
- _("Visit comma.ai/tg"),
- AlertStatus.normal, AlertSize.mid,
- Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
- },
-
- EventName.whitePandaUnsupported: {
- ET.PERMANENT: Alert(
- _("White Panda No Longer Supported"),
- _("Upgrade to comma two or black panda"),
- AlertStatus.normal, AlertSize.mid,
- Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
- ET.NO_ENTRY: NoEntryAlert(_("Unsupported Hardware")),
- },
-
EventName.invalidLkasSetting: {
ET.PERMANENT: Alert(
_("Stock LKAS is turned on"),
@@ -489,6 +464,10 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
ET.PERMANENT: NormalPermanentAlert(_("Camera Malfunction"), _("Contact Support")),
},
+ EventName.cameraMalfunction: {
+ ET.PERMANENT: NormalPermanentAlert("Camera Malfunction", "Contact Support"),
+ },
+
# ********** events that affect controls state transitions **********
EventName.pcmEnable: {
diff --git a/selfdrive/controls/lib/lane_planner.py b/selfdrive/controls/lib/lane_planner.py
index 5a18ab3bc..2284ae6d6 100644
--- a/selfdrive/controls/lib/lane_planner.py
+++ b/selfdrive/controls/lib/lane_planner.py
@@ -103,6 +103,24 @@ class LanePlanner:
l_prob *= l_std_mod
r_prob *= r_std_mod
+ # Reduce reliance on lanelines that are too far apart or
+ # will be in a few seconds
+ l_prob, r_prob = self.l_prob, self.r_prob
+ width_poly = self.l_poly - self.r_poly
+ prob_mods = []
+ for t_check in [0.0, 1.5, 3.0]:
+ width_at_t = eval_poly(width_poly, t_check * (v_ego + 7))
+ prob_mods.append(interp(width_at_t, [4.0, 5.0], [1.0, 0.0]))
+ mod = min(prob_mods)
+ l_prob *= mod
+ r_prob *= mod
+
+ # Reduce reliance on uncertain lanelines
+ l_std_mod = interp(self.l_std, [.15, .3], [1.0, 0.0])
+ r_std_mod = interp(self.r_std, [.15, .3], [1.0, 0.0])
+ l_prob *= l_std_mod
+ r_prob *= r_std_mod
+
# Find current lanewidth
self.lane_width_certainty += 0.05 * (l_prob * r_prob - self.lane_width_certainty)
current_lane_width = abs(self.l_poly[3] - self.r_poly[3])
diff --git a/selfdrive/debug/get_fingerprint.py b/selfdrive/debug/get_fingerprint.py
index 2695d457d..6c38957be 100755
--- a/selfdrive/debug/get_fingerprint.py
+++ b/selfdrive/debug/get_fingerprint.py
@@ -6,7 +6,6 @@
# - connect to a Panda
# - run selfdrive/boardd/boardd
# - launching this script
-# - turn on the car in STOCK MODE (set giraffe switches properly).
# Note: it's very important that the car is in stock mode, in order to collect a complete fingerprint
# - since some messages are published at low frequency, keep this script running for at least 30s,
# until all messages are received at least once
diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py
index f0ffabdf7..90346d524 100755
--- a/selfdrive/debug/test_fw_query_on_routes.py
+++ b/selfdrive/debug/test_fw_query_on_routes.py
@@ -37,7 +37,7 @@ if __name__ == "__main__":
for route in tqdm(routes):
route = route.rstrip()
dongle_id, time = route.split('|')
- qlog_path = f"cd:/{dongle_id}/{time}/1/qlog.bz2"
+ qlog_path = f"cd:/{dongle_id}/{time}/0/qlog.bz2"
if dongle_id in dongles:
continue
@@ -65,7 +65,7 @@ if __name__ == "__main__":
live_fingerprint = args.car
if live_fingerprint not in list(TOYOTA_FINGERPRINTS.keys()) + list(HONDA_FINGERPRINTS.keys()) + list(HYUNDAI_FINGERPRINTS.keys()):
- continue
+ break
candidates = match_fw_to_car(car_fw)
if (len(candidates) == 1) and (list(candidates)[0] == live_fingerprint):
diff --git a/selfdrive/manager.py b/selfdrive/manager.py
index 9cd3e0ee9..85e203499 100755
--- a/selfdrive/manager.py
+++ b/selfdrive/manager.py
@@ -80,8 +80,10 @@ import traceback
from multiprocessing import Process
# Run scons
-spinner = Spinner(noop=(__name__ != "__main__" or not ANDROID))
+spinner = Spinner()
spinner.update("0")
+if __name__ != "__main__":
+ spinner.close()
if not prebuilt:
for retry in [True, False]:
@@ -147,9 +149,8 @@ if not prebuilt:
ip = 'N/A'
# Show TextWindow
- no_ui = __name__ != "__main__" or not ANDROID
error_s = "\n \n".join(["\n".join(textwrap.wrap(e, 65)) for e in errors])
- with TextWindow(("openpilot failed to build (IP: %s)\n \n" % ip) + error_s, noop=no_ui) as t:
+ with TextWindow(("openpilot failed to build (IP: %s)\n \n" % ip) + error_s) as t:
t.wait_for_exit()
exit(1)
@@ -386,11 +387,8 @@ def kill_managed_process(name):
join_process(running[name], 15)
if running[name].exitcode is None:
cloudlog.critical("unkillable process %s failed to die!" % name)
- # TODO: Use method from HARDWARE
- if ANDROID:
- cloudlog.critical("FORCE REBOOTING PHONE!")
- os.system("date >> /sdcard/unkillable_reboot")
- os.system("reboot")
+ os.system("date >> /sdcard/unkillable_reboot")
+ HARDWARE.reboot()
raise RuntimeError
else:
cloudlog.info("killing %s with SIGKILL" % name)
@@ -413,8 +411,10 @@ def cleanup_all_processes(signal, frame):
def send_managed_process_signal(name, sig):
- if name not in running or name not in managed_processes:
+ if name not in running or name not in managed_processes or \
+ running[name].exitcode is not None:
return
+
cloudlog.info(f"sending signal {sig} to {name}")
os.kill(running[name].pid, sig)
diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc
index 86319d5b6..ffb3770d2 100644
--- a/selfdrive/modeld/modeld.cc
+++ b/selfdrive/modeld/modeld.cc
@@ -201,7 +201,7 @@ int main(int argc, char **argv) {
// 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
+ if (run_count < 10) frames_dropped = 0; // let frame drops warm up
float frame_drop_ratio = frames_dropped / (1 + frames_dropped);
model_publish(pm, extra.frame_id, frame_id, vipc_dropped_frames, frame_drop_ratio, model_buf, extra.timestamp_eof, model_execution_time);
diff --git a/selfdrive/modeld/runners/run.h b/selfdrive/modeld/runners/run.h
index 56e785397..dea340a0a 100644
--- a/selfdrive/modeld/runners/run.h
+++ b/selfdrive/modeld/runners/run.h
@@ -7,9 +7,9 @@
#ifdef QCOM
#define DefaultRunModel SNPEModel
#else
- #ifdef USE_TF_MODEL
- #include "tfmodel.h"
- #define DefaultRunModel TFModel
+ #ifdef USE_ONNX_MODEL
+ #include "onnxmodel.h"
+ #define DefaultRunModel ONNXModel
#else
#define DefaultRunModel SNPEModel
#endif
diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py
index 3c040e6dd..f0e86e457 100755
--- a/selfdrive/monitoring/dmonitoringd.py
+++ b/selfdrive/monitoring/dmonitoringd.py
@@ -15,7 +15,7 @@ def dmonitoringd_thread(sm=None, pm=None):
pm = messaging.PubMaster(['dMonitoringState'])
if sm is None:
- sm = messaging.SubMaster(['driverState', 'liveCalibration', 'carState', 'model', 'dragonConf'], poll=['driverState'])
+ sm = messaging.SubMaster(['driverState', 'liveCalibration', 'carState', 'controlsState', 'model', 'dragonConf'], poll=['driverState'])
driver_status = DriverStatus()
driver_status.is_rhd_region = Params().get("IsRHD") == b"1"
@@ -25,7 +25,6 @@ def dmonitoringd_thread(sm=None, pm=None):
sm['liveCalibration'].calStatus = Calibration.INVALID
sm['liveCalibration'].rpyCalib = [0, 0, 0]
sm['carState'].vEgo = 0.
- sm['carState'].cruiseState.enabled = False
sm['carState'].cruiseState.speed = 0.
sm['carState'].buttonEvents = []
sm['carState'].steeringPressed = False
@@ -72,7 +71,7 @@ def dmonitoringd_thread(sm=None, pm=None):
sm['carState'].gasPressed or \
sm['carState'].brakePressed
if driver_engaged:
- driver_status.update(Events(), True, sm['carState'].cruiseState.enabled, sm['carState'].standstill)
+ driver_status.update(Events(), True, sm['controlsState'].enabled, sm['carState'].standstill)
v_cruise_last = v_cruise
if sm.updated['model']:
@@ -81,14 +80,14 @@ def dmonitoringd_thread(sm=None, pm=None):
# Get data from dmonitoringmodeld
events = Events()
if sm['dragonConf'].dpDriverMonitor:
- driver_status.get_pose(sm['driverState'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['carState'].cruiseState.enabled)
+ driver_status.get_pose(sm['driverState'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['controlsState'].enabled)
# Block engaging after max number of distrations
if driver_status.terminal_alert_cnt >= MAX_TERMINAL_ALERTS or driver_status.terminal_time >= MAX_TERMINAL_DURATION:
events.add(car.CarEvent.EventName.tooDistracted)
# Update events from driver state
- driver_status.update(events, driver_engaged, sm['carState'].cruiseState.enabled, sm['carState'].standstill)
+ driver_status.update(events, driver_engaged, sm['controlsState'].enabled, sm['carState'].standstill)
# build dMonitoringState packet
dat = messaging.new_message('dMonitoringState')
diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py
index 515838075..33005e19c 100644
--- a/selfdrive/monitoring/driver_monitor.py
+++ b/selfdrive/monitoring/driver_monitor.py
@@ -15,8 +15,8 @@ EventName = car.CarEvent.EventName
# ******************************************************************************************
_AWARENESS_TIME = 35. # passive wheel touch total timeout
-_AWARENESS_PRE_TIME_TILL_TERMINAL = 7.
-_AWARENESS_PROMPT_TIME_TILL_TERMINAL = 5.
+_AWARENESS_PRE_TIME_TILL_TERMINAL = 12.
+_AWARENESS_PROMPT_TIME_TILL_TERMINAL = 6.
_DISTRACTED_TIME = 11.
_DISTRACTED_PRE_TIME_TILL_TERMINAL = 8.
_DISTRACTED_PROMPT_TIME_TILL_TERMINAL = 6.
@@ -251,13 +251,13 @@ class DriverStatus():
if self.awareness <= 0.:
# terminal red alert: disengagement required
alert = EventName.driverDistracted if self.active_monitoring_mode else EventName.driverUnresponsive
+ self.hi_std_alert_enabled = True
self.terminal_time += 1
if awareness_prev > 0.:
self.terminal_alert_cnt += 1
elif self.awareness <= self.threshold_prompt:
# prompt orange alert
alert = EventName.promptDriverDistracted if self.active_monitoring_mode else EventName.promptDriverUnresponsive
- self.hi_std_alert_enabled = True
elif self.awareness <= self.threshold_pre:
# pre green alert
alert = EventName.preDriverDistracted if self.active_monitoring_mode else EventName.preDriverUnresponsive
diff --git a/selfdrive/rtshield.py b/selfdrive/rtshield.py
old mode 100644
new mode 100755
index 2e7bd3c6a..9a638c916
--- a/selfdrive/rtshield.py
+++ b/selfdrive/rtshield.py
@@ -17,3 +17,4 @@ def main():
if __name__ == "__main__":
main()
+
diff --git a/selfdrive/sensord/SConscript b/selfdrive/sensord/SConscript
index facbf6403..01b0eec84 100644
--- a/selfdrive/sensord/SConscript
+++ b/selfdrive/sensord/SConscript
@@ -17,4 +17,7 @@ else:
'sensors/lsm6ds3_gyro.cc',
'sensors/lsm6ds3_temp.cc',
]
- env.Program('_sensord', ['sensors_qcom2.cc'] + sensors, LIBS=[common, cereal, messaging, 'capnp', 'zmq', 'kj'])
+ libs = [common, cereal, messaging, 'capnp', 'zmq', 'kj']
+ if arch == "larch64":
+ libs.append('i2c')
+ env.Program('_sensord', ['sensors_qcom2.cc'] + sensors, LIBS=libs)
diff --git a/selfdrive/test/test_cpu_usage.py b/selfdrive/test/test_cpu_usage.py
index a86472105..a2c5a0a1f 100755
--- a/selfdrive/test/test_cpu_usage.py
+++ b/selfdrive/test/test_cpu_usage.py
@@ -15,11 +15,11 @@ def cputime_total(ct):
def print_cpu_usage(first_proc, last_proc):
procs = [
- ("selfdrive.controls.controlsd", 45.0),
- ("./loggerd", 33.90),
- ("selfdrive.locationd.locationd", 29.5),
- ("selfdrive.controls.plannerd", 11.84),
- ("selfdrive.locationd.paramsd", 10.5),
+ ("selfdrive.controls.controlsd", 47.0),
+ ("./loggerd", 42.0),
+ ("selfdrive.locationd.locationd", 35.0),
+ ("selfdrive.locationd.paramsd", 12.0),
+ ("selfdrive.controls.plannerd", 10.0),
("./_modeld", 7.12),
("./camerad", 7.07),
("./_sensord", 6.17),
@@ -102,5 +102,7 @@ if __name__ == "__main__":
passed = False
try:
passed = test_cpu_usage()
+ except Exception as e:
+ print("\n\n\n", "TEST FAILED:", str(e), "\n\n\n")
finally:
sys.exit(int(not passed))
diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py
index 76b9ad3b2..a6f2d4c4e 100644
--- a/selfdrive/thermald/power_monitoring.py
+++ b/selfdrive/thermald/power_monitoring.py
@@ -9,7 +9,6 @@ from common.params import Params, put_nonblocking
from common.hardware import TICI
from selfdrive.swaglog import cloudlog
-PANDA_OUTPUT_VOLTAGE = 5.28
CAR_VOLTAGE_LOW_PASS_K = 0.091 # LPF gain for 5s tau (dt/tau / (dt/tau + 1))
# A C2 uses about 1W while idling, and 30h seens like a good shutoff for most cars
@@ -62,11 +61,6 @@ def _read_param(path, parser, default=0):
return default
-def panda_current_to_actual_current(panda_current):
- # From white/grey panda schematic
- return (3.3 - (panda_current * 3.3 / 4096)) / 8.25
-
-
class PowerMonitoring:
def __init__(self):
self.params = Params()
@@ -135,11 +129,6 @@ class PowerMonitoring:
# If the battery is discharging, we can use this measurement
# On C2: this is low by about 10-15%, probably mostly due to UNO draw not being factored in
current_power = ((get_battery_voltage() / 1000000) * (get_battery_current() / 1000000))
- elif (health.health.hwType in [log.HealthData.HwType.whitePanda, log.HealthData.HwType.greyPanda]) and (health.health.current > 1):
- # If white/grey panda, use the integrated current measurements if the measurement is not 0
- # If the measurement is 0, the current is 400mA or greater, and out of the measurement range of the panda
- # This seems to be accurate to about 5%
- current_power = (PANDA_OUTPUT_VOLTAGE * panda_current_to_actual_current(health.health.current))
elif (self.next_pulsed_measurement_time is not None) and (self.next_pulsed_measurement_time <= now):
# TODO: Figure out why this is off by a factor of 3/4???
FUDGE_FACTOR = 1.33
diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py
index cd6803ddb..648ad870e 100755
--- a/selfdrive/thermald/thermald.py
+++ b/selfdrive/thermald/thermald.py
@@ -136,6 +136,7 @@ else:
# max fan speed only allowed if battery is hot
_BAT_TEMP_THRESHOLD = 45.
+
def handle_fan_eon(max_cpu_temp, bat_temp, fan_speed, ignition):
new_speed_h = next(speed for speed, temp_h in zip(_FAN_SPEEDS, _TEMP_THRS_H) if temp_h > max_cpu_temp)
new_speed_l = next(speed for speed, temp_l in zip(_FAN_SPEEDS, _TEMP_THRS_L) if temp_l > max_cpu_temp)
@@ -211,7 +212,6 @@ def thermald_thread():
should_start_prev = False
handle_fan = None
is_uno = False
- has_relay = False
pm = PowerMonitoring()
no_panda_cnt = 0
@@ -262,7 +262,6 @@ def thermald_thread():
# Setup fan handler on first connect to panda
if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown:
is_uno = health.health.hwType == log.HealthData.HwType.uno
- has_relay = health.health.hwType in [log.HealthData.HwType.blackPanda, log.HealthData.HwType.uno, log.HealthData.HwType.dos]
if (not EON) or is_uno:
cloudlog.info("Setting up UNO fan handler")
@@ -319,7 +318,7 @@ def thermald_thread():
# since going onroad increases load and can make temps go over 107
# We only do this if there is a relay that prevents the car from faulting
is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (sec_since_boot() - off_ts > 60 * 5))
- if max_cpu_temp > 107. or bat_temp >= 63. or (has_relay and is_offroad_for_5_min and max_cpu_temp > 70.0):
+ if max_cpu_temp > 107. or bat_temp >= 63. or (is_offroad_for_5_min and max_cpu_temp > 70.0):
# onroad not allowed
thermal_status = ThermalStatus.danger
elif max_comp_temp > 96.0 or bat_temp > 60.:
@@ -346,7 +345,7 @@ def thermald_thread():
# now = datetime.datetime.utcnow()
#
# # show invalid date/time alert
- # startup_conditions["time_valid"] = now.year >= 2019
+ # startup_conditions["time_valid"] = (now.year > 2020) or (now.year == 2020 and now.month >= 10)
# set_offroad_alert_if_changed("Offroad_InvalidTime", (not startup_conditions["time_valid"]))
#
# # Show update prompt
@@ -382,18 +381,18 @@ def thermald_thread():
# set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
# set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
# set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt", False)
- #
+
startup_conditions["not_uninstalling"] = not params.get("DoUninstall") == b"1"
startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version
- completed_training = params.get("CompletedTrainingVersion") == training_version
panda_signature = params.get("PandaFirmware")
startup_conditions["fw_version_match"] = (panda_signature is None) or (panda_signature == FW_SIGNATURE) # don't show alert is no panda is connected (None)
set_offroad_alert_if_changed("Offroad_PandaFirmwareMismatch", (not startup_conditions["fw_version_match"]))
- #
- # # with 2% left, we killall, otherwise the phone will take a long time to boot
+
+ # with 2% left, we killall, otherwise the phone will take a long time to boot
startup_conditions["free_space"] = msg.thermal.freeSpace > 0.02
- startup_conditions["completed_training"] = completed_training or (current_branch in ['dashcam', 'dashcam-staging'])
+ 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"
# if any CPU gets above 107 or the battery gets above 63, kill all processes
@@ -402,6 +401,10 @@ def thermald_thread():
set_offroad_alert_if_changed("Offroad_TemperatureTooHigh", (not startup_conditions["device_temp_good"]))
should_start = all(startup_conditions.values())
+ startup_conditions["hardware_supported"] = health is not None and health.health.hwType not in [log.HealthData.HwType.whitePanda,
+ log.HealthData.HwType.greyPanda]
+ set_offroad_alert_if_changed("Offroad_HardwareUnsupported", health is not None and not startup_conditions["hardware_supported"])
+
if should_start:
if not should_start_prev:
params.delete("IsOffroad")
diff --git a/selfdrive/tombstoned.py b/selfdrive/tombstoned.py
index e43f98371..5a208ffc5 100755
--- a/selfdrive/tombstoned.py
+++ b/selfdrive/tombstoned.py
@@ -21,7 +21,9 @@ def get_tombstones():
# Loop over first 1000 directory entries
for _, f in zip(range(1000), d):
- if f.name.startswith("tombstone") or f.name.endswith(".crash"):
+ if f.name.startswith("tombstone"):
+ files.append((f.path, int(f.stat().st_ctime)))
+ elif f.name.endswith(".crash") and f.stat().st_mode == 0o100640:
files.append((f.path, int(f.stat().st_ctime)))
return files
diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript
index 220a2401b..d3c5eecff 100644
--- a/selfdrive/ui/SConscript
+++ b/selfdrive/ui/SConscript
@@ -1,30 +1,84 @@
-Import('env', 'qt_env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal')
+import os
+Import('env', 'arch', 'real_arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal')
+
+qt_env = None
+if arch in ["x86_64", "Darwin", "larch64"]:
+ qt_env = env.Clone()
+
+ if arch == "Darwin":
+ qt_env['QTDIR'] = "/usr/local/opt/qt"
+ QT_BASE = "/usr/local/opt/qt/"
+ qt_dirs = [
+ QT_BASE + "include/",
+ QT_BASE + "include/QtWidgets",
+ QT_BASE + "include/QtGui",
+ QT_BASE + "include/QtCore",
+ QT_BASE + "include/QtDBus",
+ QT_BASE + "include/QtMultimedia",
+ ]
+ qt_env["LINKFLAGS"] += ["-F" + QT_BASE + "lib"]
+ else:
+ qt_env['QTDIR'] = "/usr"
+ qt_dirs = [
+ f"/usr/include/{real_arch}-linux-gnu/qt5",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtWidgets",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtCore",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtDBus",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtMultimedia",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui/5.5.1/QtGui",
+ f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui/5.12.8/QtGui",
+ ]
+
+ qt_env.Tool('qt')
+ qt_env['CPPPATH'] += qt_dirs
+ qt_flags = [
+ "-D_REENTRANT",
+ "-DQT_NO_DEBUG",
+ "-DQT_WIDGETS_LIB",
+ "-DQT_GUI_LIB",
+ "-DQT_CORE_LIB"
+ ]
+ qt_env['CXXFLAGS'] += qt_flags
+
+
src = ['ui.cc', 'paint.cc', 'sidebar.cc', 'paint_dp.cc', '#phonelibs/nanovg/nanovg.c']
libs = [common, 'zmq', 'capnp', 'kj', 'm', cereal, messaging, gpucommon, visionipc]
if qt_env is None:
- libs += ['EGL', 'GLESv3', 'gnustl_shared', 'log', 'utils', 'gui', 'hardware', 'ui', 'CB', 'gsl', 'adreno_utils', 'OpenSLES', 'cutils', 'uuid', 'OpenCL']
+ libs += ['EGL', 'GLESv3', 'gnustl_shared', 'log', 'utils', 'gui', 'hardware',
+ 'ui', 'CB', 'gsl', 'adreno_utils', 'OpenSLES', 'cutils', 'uuid', 'OpenCL']
linkflags = ['-Wl,-rpath=/system/lib64,-rpath=/system/comma/usr/lib']
src += ["android/ui.cc", "android/sl_sound.cc"]
env.Program('_ui', src,
LINKFLAGS=linkflags,
LIBS=libs)
-
else:
qt_libs = ["pthread"]
- if arch == "Darwin":
- qt_env["FRAMEWORKS"] += ["QtWidgets", "QtGui", "QtCore", "QtDBus", "QtMultimedia"]
- else:
- qt_libs += ["Qt5Widgets", "Qt5Gui", "Qt5Core", "Qt5DBus", "Qt5Multimedia"]
+ qt_modules = ["Widgets", "Gui", "Core", "DBus", "Multimedia"]
if arch == "larch64":
qt_libs += ["GLESv2", "wayland-client"]
- else:
+ elif arch != "Darwin":
qt_libs += ["GL"]
- qt_src = ["qt/ui.cc", "qt/window.cc", "qt/settings.cc", "qt/qt_sound.cc"] + src
+ if arch == "Darwin":
+ qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
+ else:
+ qt_libs += [f"Qt5{m}" for m in qt_modules]
+
+ qt_src = ["qt/ui.cc", "qt/window.cc", "qt/qt_sound.cc", "qt//offroad/keyboard.cc", "qt/offroad/input_field.cc", "qt/offroad/settings.cc", "qt/offroad/onboarding.cc", "qt/offroad/wifi.cc", "qt/offroad/wifiManager.cc"] + src
qt_env.Program("_ui", qt_src, LIBS=qt_libs + libs)
+
+ # spinner and text window
+ qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs + libs)
+ qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_libs + libs)
+
+ # setup and installer
+ if "BUILD_SETUP" in os.environ:
+ qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc"], LIBS=qt_libs + libs + ['curl'])
+ qt_env.Program("qt/setup/installer", ["qt/setup/installer.cc"], LIBS=qt_libs + libs)
diff --git a/selfdrive/ui/spinner/Makefile b/selfdrive/ui/android/spinner/Makefile
similarity index 77%
rename from selfdrive/ui/spinner/Makefile
rename to selfdrive/ui/android/spinner/Makefile
index 49401067f..7ceea5f61 100644
--- a/selfdrive/ui/spinner/Makefile
+++ b/selfdrive/ui/android/spinner/Makefile
@@ -1,7 +1,9 @@
CC = clang
CXX = clang++
-PHONELIBS = ../../../phonelibs
+ROOT_DIR = ../../..
+PHONELIBS = $(ROOT_DIR)/phonelibs
+COMMON = $(ROOT)/selfdrive/common
WARN_FLAGS = -Werror=implicit-function-declaration \
-Werror=incompatible-pointer-types \
@@ -19,10 +21,10 @@ OPENGL_LIBS = -lGLESv3
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
OBJS = spinner.o \
- ../../common/framebuffer.o \
- ../../common/util.o \
+ $(COMMON)/framebuffer.o \
+ $(COMMON)/util.o \
$(PHONELIBS)/nanovg/nanovg.o \
- ../../common/spinner.o \
+ $(COMMON)/spinner.o \
opensans_semibold.o \
img_spinner_track.o \
img_spinner_comma.o
@@ -41,7 +43,7 @@ spinner: $(OBJS)
$(OPENGL_LIBS) \
-lm -llog
-../../common/framebuffer.o: ../../common/framebuffer.cc
+$(COMMON)/framebuffer.o: $(COMMON)/framebuffer.cc
@echo "[ CXX ] $@"
$(CXX) $(CXXFLAGS) -MMD \
-I$(PHONELIBS)/android_frameworks_native/include \
@@ -49,15 +51,15 @@ spinner: $(OBJS)
-I$(PHONELIBS)/android_hardware_libhardware/include \
-c -o '$@' '$<'
-opensans_semibold.o: ../../assets/fonts/opensans_semibold.ttf
+opensans_semibold.o: $(ROOT_DIR)/selfdrive/assets/fonts/opensans_semibold.ttf
@echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
-img_spinner_track.o: ../../assets/img_spinner_track.png
+img_spinner_track.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_track.png
@echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
-img_spinner_comma.o: ../../assets/img_spinner_comma.png
+img_spinner_comma.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_comma.png
@echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
diff --git a/selfdrive/ui/spinner/spinner b/selfdrive/ui/android/spinner/spinner
similarity index 100%
rename from selfdrive/ui/spinner/spinner
rename to selfdrive/ui/android/spinner/spinner
diff --git a/selfdrive/common/spinner.c b/selfdrive/ui/android/spinner/spinner.c
similarity index 99%
rename from selfdrive/common/spinner.c
rename to selfdrive/ui/android/spinner/spinner.c
index f56983941..70ff71034 100644
--- a/selfdrive/common/spinner.c
+++ b/selfdrive/ui/android/spinner/spinner.c
@@ -42,8 +42,7 @@ bool stdin_input_available() {
return (FD_ISSET(0, &fds));
}
-int spin(int argc, char** argv) {
- int err;
+int main(int argc, char** argv) {
bool draw_progress = false;
float progress_val = 0.0;
diff --git a/selfdrive/ui/text/Makefile b/selfdrive/ui/android/text/Makefile
similarity index 84%
rename from selfdrive/ui/text/Makefile
rename to selfdrive/ui/android/text/Makefile
index ac0d720d5..3401cae0f 100644
--- a/selfdrive/ui/text/Makefile
+++ b/selfdrive/ui/android/text/Makefile
@@ -1,7 +1,8 @@
CC = clang
CXX = clang++
-PHONELIBS = ../../../phonelibs
+PHONELIBS = ../../../../phonelibs
+COMMON = ../../../common
WARN_FLAGS = -Werror=implicit-function-declaration \
-Werror=incompatible-pointer-types \
@@ -19,9 +20,9 @@ OPENGL_LIBS = -lGLESv3
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
OBJS = text.o \
- ../../common/framebuffer.o \
- ../../common/util.o \
- ../../../selfdrive/common/touch.o \
+ $(COMMON)/framebuffer.o \
+ $(COMMON)/util.o \
+ $(COMMON)/touch.o \
$(PHONELIBS)/nanovg/nanovg.o \
opensans_regular.o \
@@ -39,7 +40,7 @@ text: $(OBJS)
$(OPENGL_LIBS) \
-lm -llog
-opensans_regular.o: ../../assets/fonts/opensans_regular.ttf
+opensans_regular.o: ../../../assets/fonts/opensans_regular.ttf
@echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
@@ -47,7 +48,7 @@ opensans_regular.o: ../../assets/fonts/opensans_regular.ttf
mkdir -p $(@D)
@echo "[ CC ] $@"
$(CC) $(CPPFLAGS) $(CFLAGS) \
- -I../.. \
+ -I../../.. \
-I$(PHONELIBS)/android_frameworks_native/include \
-I$(PHONELIBS)/android_system_core/include \
-I$(PHONELIBS)/android_hardware_libhardware/include \
@@ -58,8 +59,8 @@ opensans_regular.o: ../../assets/fonts/opensans_regular.ttf
mkdir -p $(@D)
@echo "[ CXX ] $@"
$(CXX) $(CPPFLAGS) $(CXXFLAGS) \
- -I../../selfdrive \
- -I../../ \
+ -I../../../selfdrive \
+ -I../../../ \
-I$(PHONELIBS)/android_frameworks_native/include \
-I$(PHONELIBS)/android_system_core/include \
-I$(PHONELIBS)/android_hardware_libhardware/include \
diff --git a/selfdrive/ui/text/text b/selfdrive/ui/android/text/text
similarity index 100%
rename from selfdrive/ui/text/text
rename to selfdrive/ui/android/text/text
diff --git a/selfdrive/ui/text/text.c b/selfdrive/ui/android/text/text.c
similarity index 100%
rename from selfdrive/ui/text/text.c
rename to selfdrive/ui/android/text/text.c
diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc
index af6bf4a7a..632cc2875 100644
--- a/selfdrive/ui/paint.cc
+++ b/selfdrive/ui/paint.cc
@@ -6,6 +6,7 @@
#include "common/util.h"
#include
+
#define NANOVG_GLES3_IMPLEMENTATION
#include "nanovg_gl.h"
#include "nanovg_gl_utils.h"
@@ -56,6 +57,7 @@ bool car_space_to_full_frame(const UIState *s, float in_x, float in_y, float in_
return *out_x >= 0 && *out_x <= s->fb_w && *out_y >= 0 && *out_y <= s->fb_h;
}
+
static void ui_draw_text(NVGcontext *vg, float x, float y, const char* string, float size, NVGcolor color, int font){
nvgFontFaceId(vg, font);
nvgFontSize(vg, size);
@@ -260,7 +262,9 @@ static void ui_draw_world(UIState *s) {
const UIScene *scene = &s->scene;
nvgSave(s->vg);
- nvgScissor(s->vg, s->video_rect.x, s->video_rect.y, s->video_rect.w, s->video_rect.h);
+
+ // Don't draw on top of sidebar
+ nvgScissor(s->vg, scene->viz_rect.x, scene->viz_rect.y, scene->viz_rect.w, scene->viz_rect.h);
// Apply transformation such that video pixel coordinates match video
// 1) Put (0, 0) in the middle of the video
diff --git a/selfdrive/ui/qt/offroad/input_field.cc b/selfdrive/ui/qt/offroad/input_field.cc
new file mode 100644
index 000000000..4696416ea
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/input_field.cc
@@ -0,0 +1,56 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "input_field.hpp"
+#include "keyboard.hpp"
+
+InputField::InputField(QWidget *parent): QWidget(parent) {
+ l = new QVBoxLayout();
+ QHBoxLayout *r = new QHBoxLayout();
+ label = new QLabel(this);
+ label->setText("password");
+ r->addWidget(label);
+ QPushButton* cancel = new QPushButton("cancel");
+ QObject::connect(cancel, SIGNAL(released()), this, SLOT(emitEmpty()));
+ cancel->setFixedHeight(150);
+ cancel->setFixedWidth(300);
+ r->addWidget(cancel);
+ l->addLayout(r);
+ l->addSpacing(80);
+
+ line = new QLineEdit("");
+ l->addWidget(line);
+ l->addSpacing(200);
+
+ k = new Keyboard(this);
+ QObject::connect(k, SIGNAL(emitButton(QString)), this, SLOT(getText(QString)));
+ l->addWidget(k);
+ setLayout(l);
+}
+
+void InputField::emitEmpty(){
+ emitText("");
+ line->setText("");
+}
+void InputField::getText(QString s){
+ if(!QString::compare(s,"⌫")){
+ line->backspace();
+ }
+
+ if(!QString::compare(s,"⏎")){
+ emitText(line->text());
+ line->setText("");
+ }
+
+ QVector control_buttons {"⇧", "↑", "ABC", "⏎", "#+=", "⌫", "123"};
+ for(QString c :control_buttons){
+ if(!QString::compare(s, c)){
+ return;
+ }
+ }
+ line->insert(s.left(1));
+}
+
diff --git a/selfdrive/ui/qt/offroad/input_field.hpp b/selfdrive/ui/qt/offroad/input_field.hpp
new file mode 100644
index 000000000..a56bac261
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/input_field.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+#include "keyboard.hpp"
+
+class InputField : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit InputField(QWidget* parent = 0);
+ QLabel *label;
+
+private:
+ QLineEdit *line;
+ Keyboard *k;
+ QVBoxLayout *l;
+
+public slots:
+ void emitEmpty();
+ void getText(QString s);
+
+signals:
+ void emitText(QString s);
+};
diff --git a/selfdrive/ui/qt/offroad/keyboard.cc b/selfdrive/ui/qt/offroad/keyboard.cc
new file mode 100644
index 000000000..0cdc38c56
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/keyboard.cc
@@ -0,0 +1,120 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "keyboard.hpp"
+
+KeyboardLayout::KeyboardLayout(QWidget* parent, std::vector> layout) : QWidget(parent) {
+ QVBoxLayout* vlayout = new QVBoxLayout;
+ QButtonGroup* btn_group = new QButtonGroup(this);
+
+ QObject::connect(btn_group, SIGNAL(buttonClicked(QAbstractButton*)), parent, SLOT(handleButton(QAbstractButton*)));
+
+ int i = 0;
+ for(auto s : layout){
+ QHBoxLayout *hlayout = new QHBoxLayout;
+
+ if (i == 1){
+ hlayout->addSpacing(50);
+ }
+
+ for(QString p : s){
+ QPushButton* btn = new QPushButton(p);
+ btn->setFixedHeight(100);
+
+ if (p == QString(" ")){
+ btn->setFixedWidth(1024);
+ }
+
+ btn_group->addButton(btn);
+ hlayout->addSpacing(5);
+ hlayout->addWidget(btn);
+ }
+
+ if (i == 1){
+ hlayout->addSpacing(50);
+ }
+
+ vlayout->addLayout(hlayout);
+ i++;
+ }
+
+ setLayout(vlayout);
+}
+
+Keyboard::Keyboard(QWidget *parent) : QWidget(parent) {
+ main_layout = new QStackedLayout;
+
+ // lowercase
+ std::vector> lowercase = {
+ {"q","w","e","r","t","y","u","i","o","p"},
+ {"a","s","d","f","g","h","j","k","l"},
+ {"⇧","z","x","c","v","b","n","m","⌫"},
+ {"123"," ","⏎"},
+ };
+ main_layout->addWidget(new KeyboardLayout(this, lowercase));
+
+ // uppercase
+ std::vector> uppercase = {
+ {"Q","W","E","R","T","Y","U","I","O","P"},
+ {"A","S","D","F","G","H","J","K","L"},
+ {"↑","Z","X","C","V","B","N","M","⌫"},
+ {"123"," ","⏎"},
+ };
+ main_layout->addWidget(new KeyboardLayout(this, uppercase));
+
+ // 1234567890
+ std::vector> numbers = {
+ {"1","2","3","4","5","6","7","8","9","0"},
+ {"-","/",":",";","(",")","$","&&","@","\""},
+ {"#+=",".",",","?","!","`","⌫"},
+ {"ABC"," ","⏎"},
+ };
+ main_layout->addWidget(new KeyboardLayout(this, numbers));
+
+ // Special characters
+ std::vector> specials = {
+ {"[","]","{","}","#","%","^","*","+","="},
+ {"_","\\","|","~","<",">","€","£","¥"," "},
+ {"123",".",",","?","!","`","⌫"},
+ {"ABC"," ","⏎"},
+ };
+ main_layout->addWidget(new KeyboardLayout(this, specials));
+
+ setLayout(main_layout);
+ main_layout->setCurrentIndex(0);
+
+ setStyleSheet(R"(
+ QPushButton { font-size: 40px }
+ * {
+ background-color: #99777777;
+ }
+ )");
+}
+
+
+void Keyboard::handleButton(QAbstractButton* m_button){
+ QString id = m_button->text();
+ if(!QString::compare(m_button->text(),"↑")||!QString::compare(m_button->text(),"ABC")){
+ main_layout->setCurrentIndex(0);
+ }
+ if(!QString::compare(m_button->text(),"⇧")){
+ main_layout->setCurrentIndex(1);
+ }
+ if(!QString::compare(m_button->text(),"123")){
+ main_layout->setCurrentIndex(2);
+ }
+ if(!QString::compare(m_button->text(),"#+=")){
+ main_layout->setCurrentIndex(3);
+ }
+ if(!QString::compare(m_button->text(),"⏎")){
+ main_layout->setCurrentIndex(0);
+ }
+ if("A" <= id && id <= "Z"){
+ main_layout->setCurrentIndex(0);
+ }
+ emit emitButton(m_button->text());
+}
diff --git a/selfdrive/ui/qt/offroad/keyboard.hpp b/selfdrive/ui/qt/offroad/keyboard.hpp
new file mode 100644
index 000000000..f21d48700
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/keyboard.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include
+
+#include
+#include
+#include
+#include
+
+class KeyboardLayout : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit KeyboardLayout(QWidget *parent, std::vector> layout);
+};
+
+class Keyboard : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit Keyboard(QWidget *parent = 0);
+
+private:
+ QStackedLayout* main_layout;
+
+private slots:
+ void handleButton(QAbstractButton* m_button);
+
+signals:
+ void emitButton(QString s);
+};
diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc
new file mode 100644
index 000000000..5e97b15e2
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/onboarding.cc
@@ -0,0 +1,115 @@
+#include
+#include
+#include
+#include
+
+#include "onboarding.hpp"
+#include "common/params.h"
+
+
+QLabel * title_label(QString text) {
+ QLabel *l = new QLabel(text);
+ l->setStyleSheet(R"(font-size: 100px;)");
+ l->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ return l;
+}
+
+QWidget * OnboardingWindow::terms_screen() {
+
+ QGridLayout *main_layout = new QGridLayout();
+ main_layout->setMargin(30);
+ main_layout->setSpacing(30);
+
+ main_layout->addWidget(title_label("Review Terms"), 0, 0, 1, -1);
+
+ QLabel *terms = new QLabel("See terms at https://my.comma.ai/terms");
+ terms->setAlignment(Qt::AlignCenter);
+ terms->setStyleSheet(R"(
+ font-size: 75px;
+ border-radius: 10px;
+ background-color: #292929;
+ )");
+ main_layout->addWidget(terms, 1, 0, 1, -1);
+
+ main_layout->addWidget(new QPushButton("Decline"), 2, 0);
+
+ QPushButton *accept_btn = new QPushButton("Accept");
+ main_layout->addWidget(accept_btn, 2, 1);
+ QObject::connect(accept_btn, &QPushButton::released, [=]() {
+ Params().write_db_value("HasAcceptedTerms", LATEST_TERMS_VERSION);
+ updateActiveScreen();
+ });
+
+ QWidget *widget = new QWidget;
+ widget->setLayout(main_layout);
+ widget->setStyleSheet(R"(
+ QPushButton {
+ font-size: 50px;
+ padding: 50px;
+ border-radius: 10px;
+ background-color: #292929;
+ }
+ )");
+
+ return widget;
+}
+
+QWidget * OnboardingWindow::training_screen() {
+
+ QGridLayout *main_layout = new QGridLayout();
+ main_layout->setMargin(30);
+ main_layout->setSpacing(30);
+
+ main_layout->addWidget(title_label("Training Guide"), 0, 0);
+
+ QPushButton *btn = new QPushButton("Continue");
+ main_layout->addWidget(btn, 1, 0);
+ QObject::connect(btn, &QPushButton::released, [=]() {
+ Params().write_db_value("CompletedTrainingVersion", LATEST_TRAINING_VERSION);
+ updateActiveScreen();
+ });
+
+ QWidget *widget = new QWidget;
+ widget->setLayout(main_layout);
+ return widget;
+}
+
+void OnboardingWindow::updateActiveScreen() {
+
+ Params params = Params();
+ bool accepted_terms = params.get("HasAcceptedTerms", false).compare(LATEST_TERMS_VERSION) == 0;
+ bool training_done = params.get("CompletedTrainingVersion", false).compare(LATEST_TRAINING_VERSION) == 0;
+
+ if (!accepted_terms) {
+ swidget->setCurrentIndex(0);
+ } else if (!training_done) {
+ swidget->setCurrentIndex(1);
+ } else {
+ emit onboardingDone();
+ }
+}
+
+OnboardingWindow::OnboardingWindow(QWidget *parent) : QWidget(parent) {
+ QVBoxLayout * top_layout = new QVBoxLayout;
+
+ swidget = new QStackedWidget();
+ swidget->addWidget(terms_screen());
+ swidget->addWidget(training_screen());
+
+ top_layout->addWidget(swidget);
+
+ setLayout(top_layout);
+ setStyleSheet(R"(
+ * {
+ background-color: black;
+ }
+ QPushButton {
+ font-size: 50px;
+ padding: 50px;
+ border-radius: 10px;
+ background-color: #292929;
+ }
+ )");
+
+ updateActiveScreen();
+}
diff --git a/selfdrive/ui/qt/offroad/onboarding.hpp b/selfdrive/ui/qt/offroad/onboarding.hpp
new file mode 100644
index 000000000..137ace822
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/onboarding.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include
+#include
+
+// TODO: this is defined in python too
+#define LATEST_TERMS_VERSION "2"
+#define LATEST_TRAINING_VERSION "0.2.0"
+
+class OnboardingWindow : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit OnboardingWindow(QWidget *parent = 0);
+
+private:
+ QWidget * terms_screen();
+ QWidget * training_screen();
+ QStackedWidget *swidget;
+
+signals:
+ void onboardingDone();
+
+public slots:
+ void updateActiveScreen();
+};
diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc
new file mode 100644
index 000000000..eb2424082
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/settings.cc
@@ -0,0 +1,273 @@
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "wifi.hpp"
+#include "settings.hpp"
+#include "input_field.hpp"
+
+#include "common/params.h"
+#include "common/utilpp.h"
+
+
+ParamsToggle::ParamsToggle(QString param, QString title, QString description, QString icon_path, QWidget *parent): QFrame(parent) , param(param) {
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ QVBoxLayout *vlayout = new QVBoxLayout;
+
+ hlayout->addSpacing(25);
+ if (icon_path.length()){
+ QPixmap pix(icon_path);
+ QLabel *icon = new QLabel();
+ icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation));
+ icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ hlayout->addWidget(icon);
+ } else{
+ hlayout->addSpacing(100);
+ }
+ hlayout->addSpacing(25);
+
+ checkbox = new QCheckBox(title);
+ QLabel *label = new QLabel(description);
+ label->setWordWrap(true);
+
+ // TODO: show descriptions on tap
+ //vlayout->addSpacing(50);
+ vlayout->addWidget(checkbox);
+ //vlayout->addWidget(label);
+ //vlayout->addSpacing(50);
+ hlayout->addLayout(vlayout);
+
+ setLayout(hlayout);
+
+ checkbox->setChecked(Params().read_db_bool(param.toStdString().c_str()));
+
+ setStyleSheet(R"(
+ QCheckBox {
+ font-size: 70px;
+ }
+ QCheckBox::indicator {
+ width: 100px;
+ height: 100px;
+ }
+ QCheckBox::indicator:unchecked {
+ image: url(../assets/offroad/circled-checkmark-empty.png);
+ }
+ QCheckBox::indicator:checked {
+ image: url(../assets/offroad/circled-checkmark.png);
+ }
+ QLabel { font-size: 40px }
+ * {
+ background-color: #114265;
+ }
+ )");
+
+ QObject::connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkboxClicked(int)));
+}
+
+void ParamsToggle::checkboxClicked(int state){
+ char value = state ? '1': '0';
+ Params().write_db_value(param.toStdString().c_str(), &value, 1);
+}
+
+QWidget * toggles_panel() {
+
+ QVBoxLayout *toggles_list = new QVBoxLayout();
+ toggles_list->setSpacing(25);
+
+ toggles_list->addWidget(new ParamsToggle("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(new ParamsToggle("LaneChangeEnabled",
+ "Enable Lane Change Assist",
+ "Perform assisted lane changes with openpilot by checking your surroundings for safety, activating the turn signal and gently nudging the steering wheel towards your desired lane. openpilot is not capable of checking if a lane change is safe. You must continuously observe your surroundings to use this feature.",
+ "../assets/offroad/icon_road.png"
+ ));
+ toggles_list->addWidget(new ParamsToggle("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(new ParamsToggle("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(new ParamsToggle("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(new ParamsToggle("IsMetric",
+ "Use Metric System",
+ "Display speed in km/h instead of mp/h.",
+ "../assets/offroad/icon_metric.png"
+ ));
+ toggles_list->addWidget(new ParamsToggle("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"
+ ));
+
+ QWidget *widget = new QWidget;
+ widget->setLayout(toggles_list);
+ return widget;
+}
+
+QWidget * device_panel() {
+
+ QVBoxLayout *device_layout = new QVBoxLayout;
+ device_layout->setSpacing(50);
+
+ Params params = Params();
+ std::vector> labels = {
+ {"Dongle ID", params.get("DongleId", false)},
+ //{"Serial Number", "abcdefghijk"},
+ };
+
+ for (auto l : labels) {
+ QString text = QString::fromStdString(l.first + ": " + l.second);
+ device_layout->addWidget(new QLabel(text));
+ }
+
+ QPushButton *clear_cal_btn = new QPushButton("Reset Calibration");
+ device_layout->addWidget(clear_cal_btn);
+ QObject::connect(clear_cal_btn, &QPushButton::released, [=]() {
+ Params().delete_db_value("CalibrationParams");
+ });
+
+ std::map power_btns = {
+ {"Power Off", "sudo poweroff"},
+ {"Reboot", "sudo reboot"},
+ };
+
+ for (auto b : power_btns) {
+ QPushButton *btn = new QPushButton(QString::fromStdString(b.first));
+ device_layout->addWidget(btn);
+#ifdef __aarch64__
+ QObject::connect(btn, &QPushButton::released,
+ [=]() {std::system(b.second);});
+#endif
+ }
+
+ QWidget *widget = new QWidget;
+ widget->setLayout(device_layout);
+ widget->setStyleSheet(R"(
+ QPushButton {
+ padding: 60px;
+ }
+ )");
+ return widget;
+}
+
+QWidget * developer_panel() {
+ QVBoxLayout *main_layout = new QVBoxLayout;
+
+ // TODO: enable SSH toggle and github keys
+
+ Params params = Params();
+ std::string brand = params.read_db_bool("Passive") ? "dashcam" : "openpilot";
+ std::string os_version = util::read_file("/VERSION");
+ std::vector> labels = {
+ {"Version", brand + " v" + params.get("Version", false)},
+ {"OS Version", os_version},
+ {"Git Branch", params.get("GitBranch", false)},
+ {"Git Commit", params.get("GitCommit", false).substr(0, 10)},
+ {"Panda Firmware", params.get("PandaFirmwareHex", false)},
+ };
+
+ for (auto l : labels) {
+ QString text = QString::fromStdString(l.first + ": " + l.second);
+ main_layout->addWidget(new QLabel(text));
+ }
+
+ QWidget *widget = new QWidget;
+ widget->setLayout(main_layout);
+ return widget;
+}
+
+QWidget * network_panel() {
+ QVBoxLayout *main_layout = new QVBoxLayout;
+
+ main_layout->addWidget(new WifiUI());
+
+ QWidget *widget = new QWidget;
+ widget->setLayout(main_layout);
+ return widget;
+}
+
+
+void SettingsWindow::setActivePanel() {
+ QPushButton *btn = qobject_cast(sender());
+ panel_layout->setCurrentWidget(panels[btn->text()]);
+}
+
+SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) {
+
+ // sidebar
+ QVBoxLayout *sidebar_layout = new QVBoxLayout();
+ panel_layout = new QStackedLayout();
+
+ // close button
+ QPushButton *close_button = new QPushButton("X");
+ close_button->setStyleSheet(R"(
+ QPushButton {
+ padding: 50px;
+ font-weight: bold;
+ font-size: 100px;
+ }
+ )");
+ sidebar_layout->addWidget(close_button);
+ QObject::connect(close_button, SIGNAL(released()), this, SIGNAL(closeSettings()));
+
+ // setup panels
+ panels = {
+ {"device", device_panel()},
+ {"toggles", toggles_panel()},
+ {"developer", developer_panel()},
+ {"network", network_panel()},
+ };
+
+ for (auto &panel : panels) {
+ QPushButton *btn = new QPushButton(panel.first);
+ btn->setStyleSheet(R"(
+ QPushButton {
+ padding-top: 35px;
+ padding-bottom: 35px;
+ font-size: 60px;
+ text-align: right;
+ border: none;
+ background: none;
+ font-weight: bold;
+ }
+ )");
+
+ sidebar_layout->addWidget(btn);
+ panel_layout->addWidget(panel.second);
+ QObject::connect(btn, SIGNAL(released()), this, SLOT(setActivePanel()));
+ }
+
+ QHBoxLayout *settings_layout = new QHBoxLayout();
+ settings_layout->addSpacing(45);
+ settings_layout->addLayout(sidebar_layout);
+ settings_layout->addSpacing(45);
+ settings_layout->addLayout(panel_layout);
+ settings_layout->addSpacing(45);
+ setLayout(settings_layout);
+
+ setStyleSheet(R"(
+ * {
+ color: white;
+ font-size: 50px;
+ }
+ )");
+}
diff --git a/selfdrive/ui/qt/settings.hpp b/selfdrive/ui/qt/offroad/settings.hpp
similarity index 77%
rename from selfdrive/ui/qt/settings.hpp
rename to selfdrive/ui/qt/offroad/settings.hpp
index e65e75bc7..e4f65a694 100644
--- a/selfdrive/ui/qt/settings.hpp
+++ b/selfdrive/ui/qt/offroad/settings.hpp
@@ -4,25 +4,36 @@
#include
#include
#include
+#include
+
class ParamsToggle : public QFrame {
Q_OBJECT
+public:
+ explicit ParamsToggle(QString param, QString title, QString description, QString icon, QWidget *parent = 0);
+
private:
QCheckBox *checkbox;
QString param;
-public:
- explicit ParamsToggle(QString param, QString title, QString description, QString icon, QWidget *parent = 0);
+
public slots:
void checkboxClicked(int state);
};
-
-
class SettingsWindow : public QWidget {
Q_OBJECT
+
public:
explicit SettingsWindow(QWidget *parent = 0);
+
signals:
void closeSettings();
+
+private:
+ std::map panels;
+ QStackedLayout *panel_layout;
+
+private slots:
+ void setActivePanel();
};
diff --git a/selfdrive/ui/qt/offroad/wifi.cc b/selfdrive/ui/qt/offroad/wifi.cc
new file mode 100644
index 000000000..00088d7bd
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/wifi.cc
@@ -0,0 +1,192 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "wifi.hpp"
+
+
+void clearLayout(QLayout* layout) {
+ while (QLayoutItem* item = layout->takeAt(0)) {
+ if (QWidget* widget = item->widget()){
+ widget->deleteLater();
+ }
+ if (QLayout* childLayout = item->layout()) {
+ clearLayout(childLayout);
+ }
+ delete item;
+ }
+}
+
+WifiUI::WifiUI(QWidget *parent) : QWidget(parent) {
+ wifi = new WifiManager;
+
+ QVBoxLayout * top_layout = new QVBoxLayout;
+ swidget = new QStackedWidget;
+
+ // Networks page
+ wifi_widget = new QWidget;
+ vlayout = new QVBoxLayout;
+ wifi_widget->setLayout(vlayout);
+ swidget->addWidget(wifi_widget);
+
+ // Keyboard page
+ a = new InputField();
+ QObject::connect(a, SIGNAL(emitText(QString)), this, SLOT(receiveText(QString)));
+ swidget->addWidget(a);
+ swidget->setCurrentIndex(0);
+
+ top_layout->addWidget(swidget);
+ setLayout(top_layout);
+ a->setStyleSheet(R"(
+ QLineEdit {
+ background-color: #114265;
+ }
+ )");
+
+ // TODO: implement (not) connecting with wrong password
+
+ // Update network list
+ timer = new QTimer(this);
+ QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh()));
+ timer->start(400);
+
+ // Scan on startup
+ wifi->request_scan();
+ page = 0;
+}
+
+void WifiUI::refresh() {
+ if (!this->isVisible()) {
+ return;
+ }
+
+ wifi->request_scan();
+ wifi->refreshNetworks();
+
+ clearLayout(vlayout);
+
+ connectButtons = new QButtonGroup(this);
+ QObject::connect(connectButtons, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(handleButton(QAbstractButton*)));
+
+ int i = 0;
+ 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);
+ hlayout->addWidget(new QLabel(QString::fromUtf8(network.ssid)));
+
+ // 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);
+ hlayout->addSpacing(20);
+
+ // connect button
+ QPushButton* btn = new QPushButton(network.connected ? "Connected" : "Connect");
+ btn->setFixedWidth(300);
+ btn->setDisabled(network.connected || network.security_type == SecurityType::UNSUPPORTED);
+ hlayout->addWidget(btn);
+ hlayout->addSpacing(20);
+
+ connectButtons->addButton(btn, i);
+
+ QWidget * w = new QWidget;
+ w->setLayout(hlayout);
+ vlayout->addWidget(w);
+ w->setStyleSheet(R"(
+ QLabel {
+ font-size: 40px;
+ }
+ QPushButton:enabled {
+ background-color: #114265;
+ }
+ QPushButton:disabled {
+ background-color: #323C43;
+ }
+ * {
+ background-color: #114265;
+ }
+ )");
+ }
+ i+=1;
+ }
+ QHBoxLayout *prev_next_buttons = new QHBoxLayout;
+ QPushButton* prev = new QPushButton("Previous");
+ prev->setEnabled(page);
+ prev->setFixedHeight(100);
+
+ QPushButton* next = new QPushButton("Next");
+ next->setFixedHeight(100);
+ //If there are more visible networks then we can show, enable going to next page
+ if(wifi->seen_networks.size() > (page + 1) * networks_per_page){
+ next->setEnabled(true);
+ }else{
+ next->setDisabled(true);
+ }
+ QObject::connect(prev, SIGNAL(released()), this, SLOT(prevPage()));
+ QObject::connect(next, SIGNAL(released()), this, SLOT(nextPage()));
+ prev_next_buttons->addWidget(prev);
+ prev_next_buttons->addWidget(next);
+
+ QWidget * w = new QWidget;
+ w->setLayout(prev_next_buttons);
+ w->setStyleSheet(R"(
+ QPushButton:enabled {
+ background-color: #114265;
+ }
+ QPushButton:disabled {
+ background-color: #323C43;
+ }
+ * {
+ background-color: #114265;
+ }
+ )");
+ vlayout->addWidget(w);
+}
+
+void WifiUI::handleButton(QAbstractButton* button) {
+ QPushButton* btn = static_cast(button);
+ qDebug() << connectButtons->id(btn);
+ Network n = wifi->seen_networks[connectButtons->id(btn)];
+
+ a->label->setText("Enter password for \"" + n.ssid + "\"");
+
+ if(n.security_type == SecurityType::OPEN){
+ wifi->connect(n);
+ } else if (n.security_type == SecurityType::WPA){
+ QString password = getStringFromUser();
+ if(password.size()){
+ wifi->connect(n, password);
+ }
+ } else {
+ qDebug() << "Cannot determine network's security type";
+ }
+}
+
+QString WifiUI::getStringFromUser(){
+ swidget->setCurrentIndex(1);
+ loop.exec();
+ swidget->setCurrentIndex(0);
+ return text;
+}
+
+void WifiUI::receiveText(QString t) {
+ loop.quit();
+ text = t;
+}
+void WifiUI::prevPage() {
+ page--;
+ refresh();
+}
+void WifiUI::nextPage() {
+ page++;
+ refresh();
+}
diff --git a/selfdrive/ui/qt/offroad/wifi.hpp b/selfdrive/ui/qt/offroad/wifi.hpp
new file mode 100644
index 000000000..0343e6be5
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/wifi.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+#include "wifiManager.hpp"
+#include "input_field.hpp"
+
+
+class WifiUI : public QWidget {
+ Q_OBJECT
+
+private:
+ WifiManager* wifi;
+ int page;
+ const int networks_per_page = 10;
+
+ QStackedWidget* swidget;
+ QVBoxLayout* vlayout;
+ QWidget * wifi_widget;
+
+ InputField *a;
+ QEventLoop loop;
+ QTimer * timer;
+ QString text;
+ QButtonGroup *connectButtons;
+
+ QString getStringFromUser();
+
+public:
+ explicit WifiUI(QWidget *parent = 0);
+
+private slots:
+ void handleButton(QAbstractButton* m_button);
+ void refresh();
+ void receiveText(QString text);
+ void prevPage();
+ void nextPage();
+};
diff --git a/selfdrive/ui/qt/offroad/wifiManager.cc b/selfdrive/ui/qt/offroad/wifiManager.cc
new file mode 100644
index 000000000..987b09c8e
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/wifiManager.cc
@@ -0,0 +1,261 @@
+#include
+#include
+
+#include "wifiManager.hpp"
+
+
+QString nm_path = "/org/freedesktop/NetworkManager";
+QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings";
+
+QString nm_iface = "org.freedesktop.NetworkManager";
+QString props_iface = "org.freedesktop.DBus.Properties";
+QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings";
+QString nm_settings_conn_iface = "org.freedesktop.NetworkManager.Settings.Connection";
+QString device_iface = "org.freedesktop.NetworkManager.Device";
+QString wireless_device_iface = "org.freedesktop.NetworkManager.Device.Wireless";
+QString ap_iface = "org.freedesktop.NetworkManager.AccessPoint";
+QString connection_iface = "org.freedesktop.NetworkManager.Connection.Active";
+
+QString nm_service = "org.freedesktop.NetworkManager";
+
+
+template
+T get_response(QDBusMessage response){
+ QVariant first = response.arguments().at(0);
+ QDBusVariant dbvFirst = first.value();
+ QVariant vFirst = dbvFirst.variant();
+ return vFirst.value();
+}
+
+bool compare_by_strength(const Network &a, const Network &b){
+ if (a.connected) return true;
+ if (b.connected) return false;
+ return a.strength > b.strength;
+}
+
+WifiManager::WifiManager(){
+ qDBusRegisterMetaType();
+
+ adapter = get_adapter();
+ has_adapter = adapter != "";
+}
+
+void WifiManager::refreshNetworks(){
+ if (!has_adapter) return;
+
+ bus = QDBusConnection::systemBus();
+ seen_networks.clear();
+ seen_ssids.clear();
+
+ for (Network &network : get_networks()){
+ if(seen_ssids.count(network.ssid)){
+ continue;
+ }
+ seen_ssids.push_back(network.ssid);
+ seen_networks.push_back(network);
+ }
+}
+
+QList WifiManager::get_networks(){
+ QList r;
+ QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus);
+ QDBusMessage response = nm.call("GetAllAccessPoints");
+ QVariant first = response.arguments().at(0);
+
+ QString active_ap = get_active_ap();
+
+ const QDBusArgument &args = first.value();
+ args.beginArray();
+ while (!args.atEnd()) {
+ QDBusObjectPath path;
+ args >> path;
+
+ QByteArray ssid = get_property(path.path(), "Ssid");
+ unsigned int strength = get_ap_strength(path.path());
+ SecurityType security = getSecurityType(path.path());
+ Network network = {path.path(), ssid, strength, path.path()==active_ap, security};
+
+ if (ssid.length()){
+ r.push_back(network);
+ }
+ }
+ args.endArray();
+
+ std::sort(r.begin(), r.end(), compare_by_strength);
+ return r;
+}
+
+SecurityType WifiManager::getSecurityType(QString path){
+ int sflag = get_property(path, "Flags").toInt();
+ int wpaflag = get_property(path, "WpaFlags").toInt();
+ int rsnflag = get_property(path, "RsnFlags").toInt();
+ int wpa_props = wpaflag | rsnflag;
+
+ if(sflag == 0){
+ return SecurityType::OPEN;
+ } else if((sflag & 0x1) && (wpa_props & (0x333) && !(wpa_props & 0x200))) {
+ return SecurityType::WPA;
+ } else {
+ // qDebug() << "Cannot determine security type for " << get_property(path, "Ssid") << " with flags";
+ // qDebug() << "flag " << sflag;
+ // qDebug() << "WpaFlag " << wpaflag;
+ // qDebug() << "RsnFlag " << rsnflag;
+ return SecurityType::UNSUPPORTED;
+ }
+}
+
+void WifiManager::connect(Network n){
+ return connect(n, "", "");
+}
+
+void WifiManager::connect(Network n, QString password){
+ return connect(n, "", password);
+}
+
+void WifiManager::connect(Network n, QString username, QString password){
+ QString active_ap = get_active_ap();
+ if (active_ap!="") {
+ clear_connections(get_property(active_ap, "Ssid"));
+ }
+ clear_connections(n.ssid);
+ qDebug() << "Connecting to"<< n.ssid << "with username, password =" << username << "," < result = nm_settings.call("AddConnection", QVariant::fromValue(connection));
+ if (!result.isValid()) {
+ qDebug() << result.error().name() << result.error().message();
+ } else {
+ qDebug() << result.value().path();
+ }
+}
+
+void WifiManager::print_active_connections(){
+ //TO-DO clean up, the code is not currently in use.
+ QDBusInterface nm(nm_service, nm_path, props_iface, bus);
+ QDBusMessage response = nm.call("Get", nm_iface, "ActiveConnections");
+ QVariant first = response.arguments().at(0);
+ QDBusVariant dbvFirst = first.value();
+ QVariant vFirst = dbvFirst.variant();
+ QDBusArgument step4 = vFirst.value();
+ QDBusObjectPath path;
+ step4.beginArray();
+ while (!step4.atEnd()){
+ step4 >> path;
+ qDebug()<();
+ args.beginArray();
+ while (!args.atEnd()) {
+ QDBusObjectPath path;
+ args >> path;
+ QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus);
+ QDBusMessage response = nm2.call("GetSettings");
+
+ const QDBusArgument &dbusArg = response.arguments().at(0).value();
+
+ QMap > map;
+ dbusArg >> map;
+ for(QString outer_key : map.keys()) {
+ QMap innerMap = map.value(outer_key);
+ for(QString inner_key : innerMap.keys()) {
+ if(inner_key == "ssid"){
+ QString value = innerMap.value(inner_key).value();
+ if(value == ssid){
+ // qDebug()<<"Deleting "<(response);
+ return resp;
+}
+
+QString WifiManager::get_active_ap(){
+ QDBusInterface device_props(nm_service, adapter, props_iface, bus);
+ QDBusMessage response = device_props.call("Get", wireless_device_iface, "ActiveAccessPoint");
+ QDBusObjectPath r = get_response(response);
+ return r.path();
+}
+
+QByteArray WifiManager::get_property(QString network_path ,QString property){
+ QDBusInterface device_props(nm_service, network_path, props_iface, bus);
+ QDBusMessage response = device_props.call("Get", ap_iface, property);
+ return get_response(response);
+}
+
+unsigned int WifiManager::get_ap_strength(QString network_path){
+ QDBusInterface device_props(nm_service, network_path, props_iface, bus);
+ QDBusMessage response = device_props.call("Get", ap_iface, "Strength");
+ return get_response(response);
+}
+
+QString WifiManager::get_adapter(){
+
+ QDBusInterface nm(nm_service, nm_path, nm_iface, bus);
+ QDBusMessage response = nm.call("GetDevices");
+ QVariant first = response.arguments().at(0);
+
+ QString adapter_path = "";
+
+ const QDBusArgument &args = first.value();
+ args.beginArray();
+ while (!args.atEnd()) {
+ QDBusObjectPath path;
+ args >> path;
+
+ // Get device type
+ QDBusInterface device_props(nm_service, path.path(), props_iface, bus);
+ QDBusMessage response = device_props.call("Get", device_iface, "DeviceType");
+ uint device_type = get_response(response);
+
+ if (device_type == 2) { // Wireless
+ adapter_path = path.path();
+ break;
+ }
+ }
+ args.endArray();
+
+ return adapter_path;
+}
diff --git a/selfdrive/ui/qt/offroad/wifiManager.hpp b/selfdrive/ui/qt/offroad/wifiManager.hpp
new file mode 100644
index 000000000..e107f6ade
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/wifiManager.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include
+#include
+
+enum class SecurityType {
+ OPEN,
+ WPA,
+ UNSUPPORTED
+};
+
+typedef QMap> Connection;
+
+struct Network {
+ QString path;
+ QByteArray ssid;
+ unsigned int strength;
+ bool connected;
+ SecurityType security_type;
+};
+
+class WifiManager{
+public:
+ explicit WifiManager();
+
+ bool has_adapter;
+ void request_scan();
+ QVector seen_networks;
+
+ void refreshNetworks();
+ void connect(Network ssid);
+ void connect(Network ssid, QString password);
+ void connect(Network ssid, QString username, QString password);
+
+private:
+ QVector seen_ssids;
+ QString adapter;//Path to network manager wifi-device
+ QDBusConnection bus = QDBusConnection::systemBus();
+
+ QString get_adapter();
+ QList get_networks();
+ void connect(QByteArray ssid, QString username, QString password, SecurityType security_type);
+ QString get_active_ap();
+ void clear_connections(QString ssid);
+ void print_active_connections();
+ uint get_wifi_device_state();
+ QByteArray get_property(QString network_path, QString property);
+ unsigned int get_ap_strength(QString network_path);
+ SecurityType getSecurityType(QString ssid);
+};
diff --git a/selfdrive/ui/qt/qt_sound.cc b/selfdrive/ui/qt/qt_sound.cc
index c44e27ec9..c18b2d585 100644
--- a/selfdrive/ui/qt/qt_sound.cc
+++ b/selfdrive/ui/qt/qt_sound.cc
@@ -1,5 +1,5 @@
#include
-#include "qt/qt_sound.hpp"
+#include "qt_sound.hpp"
QtSound::QtSound() {
for (auto &kv : sound_map) {
@@ -9,22 +9,22 @@ QtSound::QtSound() {
}
bool QtSound::play(AudibleAlert alert) {
- sounds[alert].setLoopCount(sound_map[alert].second>-1 ? sound_map[alert].second : QSoundEffect::Infinite);
- sounds[alert].setVolume(0.9);
+ int loops = sound_map[alert].second> - 1 ? sound_map[alert].second : QSoundEffect::Infinite;
+ sounds[alert].setLoopCount(loops);
+ sounds[alert].setVolume(0.7);
sounds[alert].play();
return true;
}
void QtSound::stop() {
for (auto &kv : sounds) {
- kv.second.stop();
+ // Only stop repeating sounds
+ if (sound_map[kv.first].second != 0) {
+ kv.second.stop();
+ }
}
}
void QtSound::setVolume(int volume) {
// TODO: implement this
}
-
-QtSound::~QtSound() {
-
-}
diff --git a/selfdrive/ui/qt/qt_sound.hpp b/selfdrive/ui/qt/qt_sound.hpp
index c2aab2de4..8c7f8aa34 100644
--- a/selfdrive/ui/qt/qt_sound.hpp
+++ b/selfdrive/ui/qt/qt_sound.hpp
@@ -6,7 +6,6 @@
class QtSound : public Sound {
public:
QtSound();
- ~QtSound();
bool play(AudibleAlert alert);
void stop();
void setVolume(int volume);
diff --git a/selfdrive/ui/qt/settings.cc b/selfdrive/ui/qt/settings.cc
deleted file mode 100644
index 728b3d84b..000000000
--- a/selfdrive/ui/qt/settings.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-#include
-#include
-#include
-#include
-
-#include "qt/settings.hpp"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "common/params.h"
-
-ParamsToggle::ParamsToggle(QString param, QString title, QString description, QString icon_path, QWidget *parent): QFrame(parent) , param(param) {
- QHBoxLayout *hlayout = new QHBoxLayout;
- QVBoxLayout *vlayout = new QVBoxLayout;
-
- hlayout->addSpacing(25);
- if (icon_path.length()){
- QPixmap pix(icon_path);
- QLabel *icon = new QLabel();
- icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation));
- icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
- hlayout->addWidget(icon);
- } else{
- hlayout->addSpacing(100);
- }
- hlayout->addSpacing(25);
-
- checkbox = new QCheckBox(title);
- QLabel *label = new QLabel(description);
- label->setWordWrap(true);
-
- vlayout->addWidget(checkbox);
- vlayout->addWidget(label);
- hlayout->addLayout(vlayout);
-
- setLayout(hlayout);
-
- checkbox->setChecked(Params().read_db_bool(param.toStdString().c_str()));
-
- setStyleSheet(R"(
- QCheckBox { font-size: 70px }
- QLabel { font-size: 40px }
- * {
- background-color: #114265;
- }
- )");
-
- QObject::connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkboxClicked(int)));
-}
-
-void ParamsToggle::checkboxClicked(int state){
- char value = state ? '1': '0';
- Params().write_db_value(param.toStdString().c_str(), &value, 1);
-}
-
-SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) {
- QWidget *container = new QWidget(this);
-
- QVBoxLayout *settings_list = new QVBoxLayout();
- settings_list->addWidget(new ParamsToggle("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"
- ));
- settings_list->addWidget(new ParamsToggle("LaneChangeEnabled",
- "Enable Lane Change Assist",
- "Perform assisted lane changes with openpilot by checking your surroundings for safety, activating the turn signal and gently nudging the steering wheel towards your desired lane. openpilot is not capable of checking if a lane change is safe. You must continuously observe your surroundings to use this feature.",
- "../assets/offroad/icon_road.png"
- ));
- settings_list->addWidget(new ParamsToggle("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"
- ));
- settings_list->addWidget(new ParamsToggle("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"
- ));
- settings_list->addWidget(new ParamsToggle("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"
- ));
- settings_list->addWidget(new ParamsToggle("IsMetric",
- "Use Metric System",
- "Display speed in km/h instead of mp/h.",
- "../assets/offroad/icon_metric.png"
- ));
- settings_list->addWidget(new ParamsToggle("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"
- ));
-
- settings_list->setSpacing(25);
-
- container->setLayout(settings_list);
- container->setFixedWidth(1650);
-
- QScrollArea *scrollArea = new QScrollArea;
- scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- scrollArea->setWidget(container);
-
- QScrollerProperties sp;
- sp.setScrollMetric(QScrollerProperties::DecelerationFactor, 2.0);
-
- QScroller* qs = QScroller::scroller(scrollArea);
- qs->setScrollerProperties(sp);
-
- QHBoxLayout *main_layout = new QHBoxLayout;
- main_layout->addSpacing(50);
- main_layout->addWidget(scrollArea);
-
- QPushButton * button = new QPushButton("Close");
- main_layout->addWidget(button);
- main_layout->addSpacing(20);
-
- setLayout(main_layout);
-
- QScroller::grabGesture(scrollArea, QScroller::LeftMouseButtonGesture);
- QObject::connect(button, SIGNAL(clicked()), this, SIGNAL(closeSettings()));
-
- setStyleSheet(R"(
- QPushButton { font-size: 40px }
- * {
- color: white;
- background-color: #072339;
- }
- )");
-}
diff --git a/selfdrive/ui/qt/spinner.cc b/selfdrive/ui/qt/spinner.cc
new file mode 100644
index 000000000..540b58f14
--- /dev/null
+++ b/selfdrive/ui/qt/spinner.cc
@@ -0,0 +1,124 @@
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#ifdef QCOM2
+#include
+#include
+#include
+#endif
+
+#include "spinner.hpp"
+
+
+Spinner::Spinner(QWidget *parent) {
+ QGridLayout *main_layout = new QGridLayout();
+ main_layout->setSpacing(0);
+ main_layout->setContentsMargins(200, 200, 200, 200);
+
+ const int img_size = 360;
+
+ comma = new QLabel();
+ comma->setPixmap(QPixmap("../assets/img_spinner_comma.png").scaled(img_size, img_size, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+ comma->setFixedSize(img_size, img_size);
+ main_layout->addWidget(comma, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter);
+
+ track_img = QPixmap("../assets/img_spinner_track.png").scaled(img_size, img_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ track = new QLabel();
+ track->setPixmap(track_img);
+ track->setFixedSize(img_size, img_size);
+ main_layout->addWidget(track, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter);
+
+ text = new QLabel();
+ text->setVisible(false);
+ main_layout->addWidget(text, 1, 0, Qt::AlignHCenter);
+
+ progress_bar = new QProgressBar();
+ progress_bar->setRange(5, 100);
+ progress_bar->setTextVisible(false);
+ progress_bar->setVisible(false);
+ main_layout->addWidget(progress_bar, 1, 0, Qt::AlignHCenter);
+
+ setLayout(main_layout);
+ setStyleSheet(R"(
+ Spinner {
+ background-color: black;
+ }
+ QLabel {
+ color: white;
+ font-size: 80px;
+ }
+ QProgressBar {
+ background-color: #373737;
+ height: 20px;
+ width: 1000px;
+ border solid white;
+ border-radius: 10px;
+ }
+ QProgressBar::chunk {
+ border-radius: 10px;
+ background-color: white;
+ }
+ )");
+
+ rotate_timer = new QTimer(this);
+ rotate_timer->start(1000/30.);
+ 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() {
+ transform.rotate(5);
+
+ QPixmap r = track_img.transformed(transform.rotate(5), Qt::SmoothTransformation);
+ int x = (r.width() - track->width()) / 2;
+ int y = (r.height() - track->height()) / 2;
+ track->setPixmap(r.copy(x, y, track->width(), track->height()));
+};
+
+void Spinner::update(int n) {
+ std::string line;
+ std::getline(std::cin, line);
+
+ if (line.length()) {
+ bool number = std::all_of(line.begin(), line.end(), ::isdigit);
+ text->setVisible(!number);
+ progress_bar->setVisible(number);
+ text->setText(QString::fromStdString(line));
+ if (number) {
+ progress_bar->setValue(std::stoi(line));
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ QApplication a(argc, argv);
+
+ Spinner *spinner = new Spinner();
+
+ // TODO: get size from QScreen, doesn't work on tici
+#ifdef QCOM2
+ int w = 2160, h = 1080;
+#else
+ int w = 1920, h = 1080;
+#endif
+ spinner->setFixedSize(w, h);
+ spinner->show();
+
+#ifdef QCOM2
+ QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
+ wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", spinner->windowHandle()));
+ wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
+ wl_surface_commit(s);
+ spinner->showFullScreen();
+#endif
+
+ return a.exec();
+}
diff --git a/selfdrive/ui/qt/spinner.hpp b/selfdrive/ui/qt/spinner.hpp
new file mode 100644
index 000000000..ea0f8afdc
--- /dev/null
+++ b/selfdrive/ui/qt/spinner.hpp
@@ -0,0 +1,27 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class Spinner : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit Spinner(QWidget *parent = 0);
+
+private:
+ QPixmap track_img;
+ QTimer *rotate_timer;
+ QLabel *comma, *track;
+ QLabel *text;
+ QProgressBar *progress_bar;
+ QTransform transform;
+ QSocketNotifier *notifier;
+
+public slots:
+ void rotate();
+ void update(int n);
+};
diff --git a/selfdrive/ui/qt/text.cc b/selfdrive/ui/qt/text.cc
new file mode 100644
index 000000000..ab7d9f4c4
--- /dev/null
+++ b/selfdrive/ui/qt/text.cc
@@ -0,0 +1,90 @@
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef QCOM2
+#include
+#include
+#include
+#endif
+
+
+int main(int argc, char *argv[]) {
+ QApplication a(argc, argv);
+ QWidget *window = new QWidget();
+
+ // TODO: get size from QScreen, doesn't work on tici
+#ifdef QCOM2
+ int w = 2160, h = 1080;
+#else
+ int w = 1920, h = 1080;
+#endif
+ window->setFixedSize(w, h);
+
+ QVBoxLayout *main_layout = new QVBoxLayout();
+
+ QString text = "";
+ for (int i = 1; i < argc; i++) {
+ if (i > 1) {
+ text.append(" ");
+ }
+ text.append(argv[i]);
+ }
+
+ QLabel *label = new QLabel(text);
+ label->setAlignment(Qt::AlignTop);
+ main_layout->addWidget(label);
+
+ QPushButton *btn = new QPushButton();
+#ifdef __aarch64__
+ btn->setText("Reboot");
+ QObject::connect(btn, &QPushButton::released, [=]() {
+ std::system("sudo reboot");
+ });
+#else
+ btn->setText("Exit");
+ QObject::connect(btn, SIGNAL(released()), &a, SLOT(quit()));
+#endif
+ main_layout->addWidget(btn);
+
+ window->setLayout(main_layout);
+ window->setStyleSheet(R"(
+ QWidget {
+ margin: 60px;
+ background-color: black;
+ }
+ QLabel {
+ color: white;
+ font-size: 60px;
+ }
+ QPushButton {
+ color: white;
+ font-size: 50px;
+ padding: 60px;
+ margin-left: 1500px;
+ border-color: white;
+ border-width: 2px;
+ border-style: solid;
+ border-radius: 20px;
+ }
+ )");
+
+ window->show();
+
+
+#ifdef QCOM2
+ QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
+ wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", window->windowHandle()));
+ wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
+ wl_surface_commit(s);
+ window->showFullScreen();
+#endif
+
+ return a.exec();
+}
diff --git a/selfdrive/ui/qt/ui.cc b/selfdrive/ui/qt/ui.cc
index aece1742a..de4f6950e 100644
--- a/selfdrive/ui/qt/ui.cc
+++ b/selfdrive/ui/qt/ui.cc
@@ -25,6 +25,8 @@ int main(int argc, char *argv[]) {
w.setFixedSize(vwp_w, vwp_h);
w.show();
+ a.installEventFilter(&w);
+
#ifdef QCOM2
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", w.windowHandle()));
diff --git a/selfdrive/ui/qt/wifi.cc b/selfdrive/ui/qt/wifi.cc
deleted file mode 100644
index 1d66c2c86..000000000
--- a/selfdrive/ui/qt/wifi.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-#include
-#include
-
-typedef QMap > Connection;
-Q_DECLARE_METATYPE(Connection)
-
-void wifi_stuff(){
- qDBusRegisterMetaType();
-
- QString nm_path = "/org/freedesktop/NetworkManager";
- QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings";
-
- QString nm_iface = "org.freedesktop.NetworkManager";
- QString props_iface = "org.freedesktop.DBus.Properties";
- QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings";
-
- QString nm_service = "org.freedesktop.NetworkManager";
- QString device_service = "org.freedesktop.NetworkManager.Device";
-
- QDBusConnection bus = QDBusConnection::systemBus();
-
- // Get devices
- QDBusInterface nm(nm_service, nm_path, nm_iface, bus);
- QDBusMessage response = nm.call("GetDevices");
- QVariant first = response.arguments().at(0);
-
- const QDBusArgument &args = first.value();
- args.beginArray();
- while (!args.atEnd()) {
- QDBusObjectPath path;
- args >> path;
-
- // Get device type
- QDBusInterface device_props(nm_service, path.path(), props_iface, bus);
- QDBusMessage response = device_props.call("Get", device_service, "DeviceType");
- QVariant first = response.arguments().at(0);
- QDBusVariant dbvFirst = first.value();
- QVariant vFirst = dbvFirst.variant();
- uint device_type = vFirst.value();
- qDebug() << path.path() << device_type;
- }
- args.endArray();
-
-
- // Add connection
- Connection connection;
- connection["connection"]["type"] = "802-11-wireless";
- connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}');
- connection["connection"]["id"] = "Connection 1";
-
- connection["802-11-wireless"]["ssid"] = QByteArray("");
- connection["802-11-wireless"]["mode"] = "infrastructure";
-
- connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk";
- connection["802-11-wireless-security"]["auth-alg"] = "open";
- connection["802-11-wireless-security"]["psk"] = "";
-
- connection["ipv4"]["method"] = "auto";
- connection["ipv6"]["method"] = "ignore";
-
-
- QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus);
- QDBusReply result = nm_settings.call("AddConnection", QVariant::fromValue(connection));
- if (!result.isValid()) {
- qDebug() << result.error().name() << result.error().message();
- } else {
- qDebug() << result.value().path();
- }
-}
diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc
index ceea1219b..e5ee59cb0 100644
--- a/selfdrive/ui/qt/window.cc
+++ b/selfdrive/ui/qt/window.cc
@@ -8,11 +8,11 @@
#include
#include
-#include
-#include
#include "window.hpp"
-#include "settings.hpp"
+#include "offroad/input_field.hpp"
+#include "offroad/settings.hpp"
+#include "offroad/onboarding.hpp"
#include "paint.hpp"
#include "common/util.h"
@@ -23,6 +23,18 @@
volatile sig_atomic_t do_exit = 0;
+static void handle_display_state(UIState *s, int dt, bool user_input) {
+ static int awake_timeout = 0;
+ awake_timeout = std::max(awake_timeout-dt, 0);
+
+ if (user_input || s->ignition || s->started) {
+ s->awake = true;
+ awake_timeout = 30*UI_FREQ;
+ } else if (awake_timeout == 0){
+ s->awake = false;
+ }
+}
+
static void set_backlight(int brightness){
std::ofstream brightness_control("/sys/class/backlight/panel0-backlight/brightness");
if (brightness_control.is_open()){
@@ -38,18 +50,25 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
set_core_affinity(7);
#endif
- GLWindow * glWindow = new GLWindow(this);
+ glWindow = new GLWindow(this);
main_layout->addWidget(glWindow);
- SettingsWindow * settingsWindow = new SettingsWindow(this);
+ settingsWindow = new SettingsWindow(this);
main_layout->addWidget(settingsWindow);
+ onboardingWindow = new OnboardingWindow(this);
+ main_layout->addWidget(onboardingWindow);
main_layout->setMargin(0);
setLayout(main_layout);
QObject::connect(glWindow, SIGNAL(openSettings()), this, SLOT(openSettings()));
QObject::connect(settingsWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings()));
+ // start at onboarding
+ main_layout->setCurrentWidget(onboardingWindow);
+ QObject::connect(onboardingWindow, SIGNAL(onboardingDone()), this, SLOT(closeSettings()));
+ onboardingWindow->updateActiveScreen();
+
setStyleSheet(R"(
* {
color: white;
@@ -67,6 +86,14 @@ void MainWindow::closeSettings() {
}
+bool MainWindow::eventFilter(QObject *obj, QEvent *event){
+ if (event->type() == QEvent::MouseButtonPress) {
+ glWindow->wake();
+ }
+ return false;
+}
+
+
GLWindow::GLWindow(QWidget *parent) : QOpenGLWidget(parent) {
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
@@ -101,6 +128,8 @@ void GLWindow::initializeGL() {
ui_state->fb_h = vwp_h;
ui_init(ui_state);
+ wake();
+
timer->start(0);
backlight_timer->start(BACKLIGHT_DT * 100);
}
@@ -113,11 +142,9 @@ void GLWindow::backlightUpdate(){
smooth_brightness = clipped_brightness * k + smooth_brightness * (1.0f - k);
int brightness = smooth_brightness;
-#ifdef QCOM2
- if (!ui_state->started){
+ if (!ui_state->awake){
brightness = 0;
}
-#endif
std::thread{set_backlight, brightness}.detach();
}
@@ -130,6 +157,10 @@ void GLWindow::timerUpdate(){
}
#endif
+ // Fix awake timeout if running 1 Hz when offroad
+ int dt = timer->interval() == 0 ? 1 : 20;
+ handle_display_state(ui_state, dt, false);
+
ui_update(ui_state);
repaint();
}
@@ -142,7 +173,16 @@ void GLWindow::paintGL() {
ui_draw(ui_state);
}
+void GLWindow::wake(){
+ // UI state might not be initialized yet
+ if (ui_state != nullptr){
+ handle_display_state(ui_state, 1, true);
+ }
+}
+
void GLWindow::mousePressEvent(QMouseEvent *e) {
+ wake();
+
// Settings button click
if (!ui_state->scene.uilayout_sidebarcollapsed && settings_btn.ptInRect(e->x(), e->y())) {
emit openSettings();
diff --git a/selfdrive/ui/qt/window.hpp b/selfdrive/ui/qt/window.hpp
index 8c82e6023..1f5a4c10e 100644
--- a/selfdrive/ui/qt/window.hpp
+++ b/selfdrive/ui/qt/window.hpp
@@ -2,30 +2,14 @@
#include
#include
-#include
-#include
#include
#include
#include
#include "qt/qt_sound.hpp"
#include "ui/ui.hpp"
-
-class MainWindow : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit MainWindow(QWidget *parent = 0);
-
-private:
- QStackedLayout *main_layout;
-
-public slots:
- void openSettings();
- void closeSettings();
-
-};
+#include "offroad/settings.hpp"
+#include "offroad/onboarding.hpp"
#ifdef QCOM2
const int vwp_w = 2160;
@@ -33,13 +17,15 @@ const int vwp_w = 2160;
const int vwp_w = 1920;
#endif
const int vwp_h = 1080;
-class GLWindow : public QOpenGLWidget, protected QOpenGLFunctions
-{
+
+
+class GLWindow : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT
public:
using QOpenGLWidget::QOpenGLWidget;
explicit GLWindow(QWidget *parent = 0);
+ void wake();
~GLWindow();
protected:
@@ -48,16 +34,16 @@ protected:
void resizeGL(int w, int h) override;
void paintGL() override;
-
private:
QTimer * timer;
QTimer * backlight_timer;
- UIState * ui_state;
+ UIState * ui_state = nullptr;
QtSound sound;
bool onroad = true;
- QLabel * label = NULL;
+
+ // TODO: this shouldn't be here
float brightness_b = 0;
float brightness_m = 0;
float smooth_brightness = 0;
@@ -69,3 +55,23 @@ public slots:
signals:
void openSettings();
};
+
+class MainWindow : public QWidget {
+ Q_OBJECT
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+
+private:
+ QStackedLayout *main_layout;
+ GLWindow *glWindow;
+ SettingsWindow *settingsWindow;
+ OnboardingWindow *onboardingWindow;
+
+public slots:
+ void openSettings();
+ void closeSettings();
+};
diff --git a/selfdrive/ui/spinner b/selfdrive/ui/spinner
new file mode 100755
index 000000000..c2ef33b7e
--- /dev/null
+++ b/selfdrive/ui/spinner
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -f /EON ]; then
+ export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
+ exec ./android/spinner/spinner "$1"
+else
+ if [ -f /TICI ] && [ ! -f qt/spinner ]; then
+ cp qt/spinner_aarch64 qt/spinner
+ fi
+
+ exec ./qt/spinner "$1"
+fi
diff --git a/selfdrive/ui/spinner/spinner.c b/selfdrive/ui/spinner/spinner.c
deleted file mode 100644
index 14b452a49..000000000
--- a/selfdrive/ui/spinner/spinner.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include "common/framebuffer.h"
-#include "common/spinner.h"
-
-int main(int argc, char** argv) {
- int err;
-
- spin(argc, argv);
-
- return 0;
-}
diff --git a/selfdrive/ui/text b/selfdrive/ui/text
new file mode 100755
index 000000000..085425e8a
--- /dev/null
+++ b/selfdrive/ui/text
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -f /EON ]; then
+ export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
+ exec ./android/text/text "$1"
+else
+ if [ -f /TICI ] && [ ! -f qt/text ]; then
+ cp qt/text_aarch64 qt/text
+ fi
+
+ exec ./qt/text "$1"
+fi
diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc
index 3a87c188a..2fb22f64f 100644
--- a/selfdrive/ui/ui.cc
+++ b/selfdrive/ui/ui.cc
@@ -294,6 +294,7 @@ void ui_update(UIState *s) {
s->status = STATUS_OFFROAD;
s->active_app = cereal::UiLayoutState::App::HOME;
s->scene.uilayout_sidebarcollapsed = false;
+ s->sound->stop();
} else if (s->started && s->status == STATUS_OFFROAD) {
s->status = STATUS_DISENGAGED;
s->started_frame = s->sm->frame;
diff --git a/site_scons/site_tools/cython.py b/site_scons/site_tools/cython.py
new file mode 100644
index 000000000..ad53f2831
--- /dev/null
+++ b/site_scons/site_tools/cython.py
@@ -0,0 +1,37 @@
+import SCons
+from SCons.Action import Action
+
+cythonAction = Action("$CYTHONCOM")
+
+def create_builder(env):
+ try:
+ cython = env['BUILDERS']['Cython']
+ except KeyError:
+ cython = SCons.Builder.Builder(
+ action = cythonAction,
+ emitter = {},
+ suffix = cython_suffix_emitter,
+ single_source = 1)
+ env['BUILDERS']['Cython'] = cython
+ return cython
+
+def cython_suffix_emitter(env, source):
+ return "$CYTHONCFILESUFFIX"
+
+def generate(env):
+ env["CYTHON"] = "cythonize"
+ env["CYTHONCOM"] = "$CYTHON $CYTHONFLAGS $SOURCE"
+ env["CYTHONCFILESUFFIX"] = ".cpp"
+
+ c_file, _ = SCons.Tool.createCFileBuilders(env)
+
+ c_file.suffix['.pyx'] = cython_suffix_emitter
+ c_file.add_action('.pyx', cythonAction)
+
+ c_file.suffix['.py'] = cython_suffix_emitter
+ c_file.add_action('.py', cythonAction)
+
+ create_builder(env)
+
+def exists(env):
+ return True