diff --git a/Jenkinsfile b/Jenkinsfile
index c3625120..dd0e2c12 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,33 +1,60 @@
-pipeline {
- agent {
- docker {
- image 'python:3.7.3'
- args '--user=root'
+def phone(String ip, String step_label, String cmd) {
+ def ci_env = "CI=1 TEST_DIR=${env.TEST_DIR} GIT_BRANCH=${env.GIT_BRANCH} GIT_COMMIT=${env.GIT_COMMIT}"
+
+ withCredentials([file(credentialsId: 'id_rsa_public', variable: 'key_file')]) {
+ sh label: step_label,
+ script: """
+ ssh -tt -o StrictHostKeyChecking=no -i ${key_file} -p 8022 root@${ip} '${ci_env} /usr/bin/bash -le' <<'EOF'
+echo \$\$ > /dev/cpuset/app/tasks || true
+echo \$PPID > /dev/cpuset/app/tasks || true
+mkdir -p /dev/shm
+chmod 777 /dev/shm
+cd ${env.TEST_DIR} || true
+${cmd}
+exit 0
+EOF"""
+ }
+}
+
+def phone_steps(String device_type, steps) {
+ lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
+ timeout(time: 60, unit: 'MINUTES') {
+ phone(device_ip, "kill old processes", "pkill -f comma || true")
+ phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),)
+ steps.each { item ->
+ phone(device_ip, item[0], item[1])
+ }
}
}
+}
+
+pipeline {
+ agent none
environment {
COMMA_JWT = credentials('athena-test-jwt')
+ TEST_DIR = "/data/openpilot"
}
stages {
stage('Release Build') {
+ agent {
+ docker {
+ image 'python:3.7.3'
+ args '--user=root'
+ }
+ }
when {
branch 'devel-staging'
}
steps {
- lock(resource: "", label: 'eon-build', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
- timeout(time: 60, unit: 'MINUTES') {
- dir(path: 'selfdrive/test') {
- sh 'pip install paramiko'
- sh 'python phone_ci.py "cd release && PUSH=1 ./build_release2.sh"'
- }
- }
- }
+ phone_steps("eon-build", [
+ ["build release2-staging and dashcam-staging", "cd release && PUSH=1 ./build_release2.sh"],
+ ])
}
}
- stage('On-device Tests') {
+ stage('openpilot tests') {
when {
not {
anyOf {
@@ -36,48 +63,80 @@ pipeline {
}
}
- parallel {
- stage('Build') {
- environment {
- CI_PUSH = "${env.BRANCH_NAME == 'master' ? 'master-ci' : ''}"
+ stages {
+
+ /*
+ stage('PC tests') {
+ agent {
+ dockerfile {
+ filename 'Dockerfile.openpilot'
+ args '--privileged --shm-size=1G --user=root'
+ }
}
-
- steps {
- lock(resource: "", label: 'eon', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
- timeout(time: 60, unit: 'MINUTES') {
- dir(path: 'selfdrive/test') {
- sh 'pip install paramiko'
- sh 'python phone_ci.py "cd release && ./build_devel.sh"'
- }
+ stages {
+ stage('Build') {
+ steps {
+ sh 'scons -j$(nproc)'
}
}
}
- }
-
- stage('Replay Tests') {
- steps {
- lock(resource: "", label: 'eon2', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
- timeout(time: 60, unit: 'MINUTES') {
- dir(path: 'selfdrive/test') {
- sh 'pip install paramiko'
- sh 'python phone_ci.py "cd selfdrive/test/process_replay && ./camera_replay.py"'
- }
- }
+ post {
+ always {
+ // fix permissions since docker runs as another user
+ sh "chmod -R 777 ."
}
}
}
+ */
- stage('HW Tests') {
- steps {
- lock(resource: "", label: 'eon', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
- timeout(time: 60, unit: 'MINUTES') {
- dir(path: 'selfdrive/test') {
- sh 'pip install paramiko'
- sh 'python phone_ci.py "SCONS_CACHE=1 scons -j3 cereal/ && \
- nosetests -s selfdrive/test/test_sounds.py && \
- nosetests -s selfdrive/boardd/tests/test_boardd_loopback.py"'
+ stage('On-device Tests') {
+ agent {
+ docker {
+ image 'python:3.7.3'
+ args '--user=root'
+ }
+ }
+
+ stages {
+ stage('parallel tests') {
+ parallel {
+
+ stage('Devel Build') {
+ environment {
+ CI_PUSH = "${env.BRANCH_NAME == 'master' ? 'master-ci' : ' '}"
+ }
+ steps {
+ phone_steps("eon", [
+ ["build devel", "cd release && CI_PUSH=${env.CI_PUSH} ./build_devel.sh"],
+ ["test openpilot", "nosetests -s selfdrive/test/test_openpilot.py"],
+ ["test cpu usage", "cd selfdrive/test/ && ./test_cpu_usage.py"],
+ ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"],
+ ["test spinner build", "cd selfdrive/ui/spinner && make clean && make"],
+ ["test text window build", "cd selfdrive/ui/text && make clean && make"],
+ ])
+ }
}
+
+ stage('Replay Tests') {
+ steps {
+ phone_steps("eon2", [
+ ["camerad/modeld replay", "cd selfdrive/test/process_replay && ./camera_replay.py"],
+ ])
+ }
+ }
+
+ stage('HW + Unit Tests') {
+ steps {
+ phone_steps("eon", [
+ ["build cereal", "SCONS_CACHE=1 scons -j4 cereal/"],
+ ["test sounds", "nosetests -s selfdrive/test/test_sounds.py"],
+ ["test boardd loopback", "nosetests -s selfdrive/boardd/tests/test_boardd_loopback.py"],
+ //["test updater", "python installer/updater/test_updater.py"],
+ ])
+ }
+ }
+
}
}
}
diff --git a/README.md b/README.md
index 052828cf..f78a0708 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 |
-| Honda | Accord 2018-19 | 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 |
| Honda | Civic Sedan/Coupe 2016-18 | Honda Sensing | openpilot | 0mph | 12mph |
@@ -76,7 +76,7 @@ Supported Cars
| Honda | CR-V Hybrid 2017-2019 | Honda Sensing | Stock | 0mph | 12mph |
| Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph1 | 12mph |
| Honda | HR-V 2019 | Honda Sensing | openpilot | 25mph1 | 12mph |
-| Honda | Insight 2019 | Honda Sensing | Stock | 0mph | 3mph |
+| Honda | Insight 2019-20 | Honda Sensing | Stock | 0mph | 3mph |
| Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph1 | 0mph |
| Honda | Passport 2019 | All | openpilot | 25mph1 | 12mph |
| Honda | Pilot 2016-18 | Honda Sensing | openpilot | 25mph1 | 12mph |
@@ -136,6 +136,7 @@ Community Maintained Cars and Features
| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph |
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Chrysler | Pacifica Hybrid 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
+| Genesis | G70 2018 | All | Stock | 0mph | 0mph |
| Genesis | G80 2018 | All | Stock | 0mph | 0mph |
| Genesis | G90 2018 | All | Stock | 0mph | 0mph |
| GMC | Acadia Denali 20182| Adaptive Cruise | openpilot | 0mph | 7mph |
@@ -144,11 +145,12 @@ Community Maintained Cars and Features
| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph |
| Hyundai | Ioniq Electric Premium SE 2020| SCC + LKAS | Stock | 0mph | 32mph |
| Hyundai | Ioniq Electric Limited 2019 | SCC + LKAS | Stock | 0mph | 32mph |
-| Hyundai | Kona 2017-19 | SCC + LKAS | Stock | 22mph | 0mph |
+| Hyundai | Kona 2020 | SCC + LKAS | Stock | 0mph | 0mph |
| Hyundai | Kona EV 2019 | SCC + LKAS | Stock | 0mph | 0mph |
| Hyundai | Palisade 2020 | All | Stock | 0mph | 0mph |
| Hyundai | Santa Fe 2019 | All | Stock | 0mph | 0mph |
| Hyundai | Sonata 2019 | All | Stock | 0mph | 0mph |
+| Hyundai | Veloster 2019 | SCC + LKAS | Stock | 5mph | 0mph |
| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
| Kia | Forte 2018-19 | SCC + LKAS | Stock | 0mph | 0mph |
@@ -156,9 +158,9 @@ Community Maintained Cars and Features
| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Sorento 2018 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph |
-| Nissan | Leaf 2018-192 | Propilot | Stock | 0mph | 0mph |
-| Nissan | Rogue 20192 | Propilot | Stock | 0mph | 0mph |
-| Nissan | X-Trail 20172 | Propilot | Stock | 0mph | 0mph |
+| Nissan | Leaf 2018-19 | Propilot | Stock | 0mph | 0mph |
+| Nissan | Rogue 2019 | Propilot | Stock | 0mph | 0mph |
+| Nissan | X-Trail 2017 | Propilot | Stock | 0mph | 0mph |
| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Forester 2019 | EyeSight | Stock | 0mph | 0mph |
diff --git a/RELEASES.md b/RELEASES.md
index 5559cd3c..0c6dd3d4 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,10 @@
+Version 0.7.8 (2020-08-19)
+========================
+ * New driver monitoring model: improved face detection and better compatibility with sunglasses
+ * Download NEOS operating system updates in the background
+ * Improved updater reliability and responsiveness
+ * Hyundai Kona 2020, Veloster 2019, and Genesis G70 2018 support thanks to xps-genesis!
+
Version 0.7.7 (2020-07-20)
========================
* White panda is no longer supported, upgrade to comma two or black panda
diff --git a/SConstruct b/SConstruct
index 7e5a412b..322bdd5f 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,3 +1,5 @@
+import Cython
+import distutils
import os
import shutil
import subprocess
@@ -12,6 +14,10 @@ AddOption('--asan',
action='store_true',
help='turn on ASAN')
+# Rebuild cython extensions if python, distutils, or cython change
+cython_dependencies = [Value(v) for v in (sys.version, distutils.__version__, Cython.__version__)]
+Export('cython_dependencies')
+
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin":
arch = "Darwin"
diff --git a/apk/ai.comma.plus.offroad.apk b/apk/ai.comma.plus.offroad.apk
index f411e636..237b0b36 100644
Binary files a/apk/ai.comma.plus.offroad.apk and b/apk/ai.comma.plus.offroad.apk differ
diff --git a/cereal/SConscript b/cereal/SConscript
index ec651dd8..0ab943db 100644
--- a/cereal/SConscript
+++ b/cereal/SConscript
@@ -1,35 +1,34 @@
-Import('env', 'arch', 'zmq')
+Import('env', 'arch', 'zmq', 'cython_dependencies')
+
+import shutil
gen_dir = Dir('gen')
messaging_dir = Dir('messaging')
# TODO: remove src-prefix and cereal from command string. can we set working directory?
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/')
-import shutil
+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/')
+
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/')
+ 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/')
# TODO: remove non shared cereal and messaging
cereal_objects = env.SharedObject([
- 'gen/cpp/car.capnp.c++',
- 'gen/cpp/log.capnp.c++',
- ])
+ 'gen/cpp/car.capnp.c++',
+ 'gen/cpp/log.capnp.c++',
+])
env.Library('cereal', cereal_objects)
env.SharedLibrary('cereal_shared', cereal_objects)
cereal_dir = Dir('.')
-services_h = env.Command(
- ['services.h'],
- ['service_list.yaml', 'services.py'],
- 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
+services_h = env.Command(['services.h'],
+ ['service_list.yaml', 'services.py'],
+ 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
messaging_objects = env.SharedObject([
'messaging/messaging.cc',
@@ -56,9 +55,9 @@ Depends('messaging/bridge.cc', services_h)
#env.Program('messaging/demo', ['messaging/demo.cc'], LIBS=[messaging_lib, 'zmq'])
-env.Command(['messaging/messaging_pyx.so'],
- [messaging_lib, 'messaging/messaging_pyx_setup.py', 'messaging/messaging_pyx.pyx', 'messaging/messaging.pxd'],
- "cd " + messaging_dir.path + " && python3 messaging_pyx_setup.py build_ext --inplace")
+env.Command(['messaging/messaging_pyx.so', 'messaging/messaging_pyx.cpp'],
+ cython_dependencies + [messaging_lib, 'messaging/messaging_pyx_setup.py', 'messaging/messaging_pyx.pyx', 'messaging/messaging.pxd'],
+ "cd " + messaging_dir.path + " && python3 messaging_pyx_setup.py build_ext --inplace")
if GetOption('test'):
diff --git a/cereal/car.capnp b/cereal/car.capnp
index 5278006e..0db47f78 100644
--- a/cereal/car.capnp
+++ b/cereal/car.capnp
@@ -112,6 +112,7 @@ struct CarEvent @0x9b1657f34caf3ad3 {
wrongCruiseMode @87;
neosUpdateRequired @88;
modeldLagging @89;
+ deviceFalling @90;
}
}
@@ -474,6 +475,7 @@ struct CarParams {
volkswagenPq @21;
subaruLegacy @22; # pre-Global platform
hyundaiLegacy @23;
+ hyundaiCommunity @24;
}
enum SteerControlType {
diff --git a/cereal/log.capnp b/cereal/log.capnp
index 9d3021af..64a577bc 100644
--- a/cereal/log.capnp
+++ b/cereal/log.capnp
@@ -441,18 +441,22 @@ struct RadarState @0x9a185389d6fdd05f {
struct LiveCalibrationData {
# deprecated
warpMatrix @0 :List(Float32);
+
# camera_frame_from_model_frame
warpMatrix2 @5 :List(Float32);
warpMatrixBig @6 :List(Float32);
+
calStatus @1 :Int8;
calCycle @2 :Int32;
calPerc @3 :Int8;
+ validBlocks @9 :Int32;
# view_frame_from_road_frame
# ui's is inversed needs new
extrinsicMatrix @4 :List(Float32);
# the direction of travel vector in device frame
rpyCalib @7 :List(Float32);
+ rpyCalibSpread @8 :List(Float32);
}
struct LiveTracks {
@@ -864,6 +868,7 @@ struct LiveLocationKalman {
posenetOK @18 :Bool = true;
gpsOK @19 :Bool = true;
sensorsOK @21 :Bool = true;
+ deviceStable @22 :Bool = true;
enum Status {
uninitialized @0;
diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py
index 7aa16cad..5e36bd8d 100644
--- a/cereal/messaging/__init__.py
+++ b/cereal/messaging/__init__.py
@@ -122,13 +122,6 @@ def recv_one_retry(sock):
if dat is not None:
return log.Event.from_bytes(dat)
-# TODO: This does not belong in messaging
-def get_one_can(logcan):
- while True:
- can = recv_one_retry(logcan)
- if len(can.can) > 0:
- return can
-
class SubMaster():
def __init__(self, services, ignore_alive=None, addr="127.0.0.1"):
self.poller = Poller()
diff --git a/cereal/messaging/messaging.hpp b/cereal/messaging/messaging.hpp
index 20bb3521..fb0f96af 100644
--- a/cereal/messaging/messaging.hpp
+++ b/cereal/messaging/messaging.hpp
@@ -59,34 +59,36 @@ public:
};
class SubMaster {
- public:
+public:
SubMaster(const std::initializer_list &service_list,
const char *address = nullptr, const std::initializer_list &ignore_alive = {});
int update(int timeout = 1000);
inline bool allAlive(const std::initializer_list &service_list = {}) { return all_(service_list, false, true); }
inline bool allValid(const std::initializer_list &service_list = {}) { return all_(service_list, true, false); }
inline bool allAliveAndValid(const std::initializer_list &service_list = {}) { return all_(service_list, true, true); }
- bool updated(const char *name) const;
void drain();
- cereal::Event::Reader &operator[](const char *name);
~SubMaster();
- private:
+ uint64_t frame = 0;
+ bool updated(const char *name) const;
+ uint64_t rcv_frame(const char *name) const;
+ cereal::Event::Reader &operator[](const char *name);
+
+private:
bool all_(const std::initializer_list &service_list, bool valid, bool alive);
Poller *poller_ = nullptr;
- uint64_t frame_ = 0;
struct SubMessage;
std::map messages_;
std::map services_;
};
class PubMaster {
- public:
+public:
PubMaster(const std::initializer_list &service_list);
inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); }
int send(const char *name, capnp::MessageBuilder &msg);
~PubMaster();
- private:
+private:
std::map sockets_;
};
diff --git a/cereal/messaging/messaging_pyx_setup.py b/cereal/messaging/messaging_pyx_setup.py
index 3e1c41ce..992b3915 100644
--- a/cereal/messaging/messaging_pyx_setup.py
+++ b/cereal/messaging/messaging_pyx_setup.py
@@ -39,7 +39,7 @@ if ARCH == "aarch64" and os.path.isdir("/system"):
extra_compile_args += ["-Wno-deprecated-register"]
libraries += ['gnustl_shared']
-setup(name='CAN parser',
+setup(name='messaging',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
@@ -51,7 +51,7 @@ setup(name='CAN parser',
extra_objects=[
os.path.join(os.path.dirname(os.path.realpath(__file__)), '../', 'libmessaging.a'),
]
- )
+ ),
+ nthreads=4,
),
- nthreads=4,
)
diff --git a/cereal/messaging/socketmaster.cc b/cereal/messaging/socketmaster.cc
index 66b7696c..a0f6c1ef 100644
--- a/cereal/messaging/socketmaster.cc
+++ b/cereal/messaging/socketmaster.cc
@@ -2,20 +2,24 @@
#include
#include "messaging.hpp"
#include "services.h"
+
#ifdef __APPLE__
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
#endif
+
static inline uint64_t nanos_since_boot() {
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
+
static const service *get_service(const char *name) {
for (const auto &it : services) {
if (strcmp(it.name, name) == 0) return ⁢
}
return nullptr;
}
+
static inline bool inList(const std::initializer_list &list, const char *value) {
for (auto &v : list) {
if (strcmp(value, v) == 0) return true;
@@ -24,7 +28,7 @@ static inline bool inList(const std::initializer_list &list, const
}
class MessageContext {
- public:
+public:
MessageContext() { ctx_ = Context::create(); }
~MessageContext() { delete ctx_; }
Context *ctx_;
@@ -53,18 +57,18 @@ SubMaster::SubMaster(const std::initializer_list &service_list, co
assert(socket != 0);
poller_->registerSocket(socket);
SubMessage *m = new SubMessage{
- .socket = socket,
- .freq = serv->frequency,
- .ignore_alive = inList(ignore_alive, name),
- .allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
- .buf = kj::heapArray(1024)};
+ .socket = socket,
+ .freq = serv->frequency,
+ .ignore_alive = inList(ignore_alive, name),
+ .allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
+ .buf = kj::heapArray(1024)};
messages_[socket] = m;
services_[name] = m;
}
}
int SubMaster::update(int timeout) {
- if (++frame_ == UINT64_MAX) frame_ = 1;
+ if (++frame == UINT64_MAX) frame = 1;
for (auto &kv : messages_) kv.second->updated = false;
int updated = 0;
@@ -89,7 +93,7 @@ int SubMaster::update(int timeout) {
m->event = m->msg_reader->getRoot();
m->updated = true;
m->rcv_time = current_time;
- m->rcv_frame = frame_;
+ m->rcv_frame = frame;
m->valid = m->event.getValid();
++updated;
@@ -126,8 +130,17 @@ void SubMaster::drain() {
}
}
-bool SubMaster::updated(const char *name) const { return services_.at(name)->updated; }
-cereal::Event::Reader &SubMaster::operator[](const char *name) { return services_.at(name)->event; };
+bool SubMaster::updated(const char *name) const {
+ return services_.at(name)->updated;
+}
+
+uint64_t SubMaster::rcv_frame(const char *name) const {
+ return services_.at(name)->rcv_frame;
+}
+
+cereal::Event::Reader &SubMaster::operator[](const char *name) {
+ return services_.at(name)->event;
+};
SubMaster::~SubMaster() {
delete poller_;
diff --git a/cereal/service_list.yaml b/cereal/service_list.yaml
index fc362338..490e903f 100644
--- a/cereal/service_list.yaml
+++ b/cereal/service_list.yaml
@@ -63,7 +63,7 @@ orbOdometry: [8057, true, 0.]
orbFeatures: [8058, false, 0.]
orbKeyFrame: [8059, true, 0.]
uiLayoutState: [8060, true, 0.]
-frontEncodeIdx: [8061, true, 5.]
+frontEncodeIdx: [8061, true, 5.] # should be 20fps on tici
orbFeaturesSummary: [8062, true, 0.]
driverState: [8063, true, 5., 1]
liveParameters: [8064, true, 20., 2]
@@ -77,6 +77,7 @@ carParams: [8071, true, 0.02, 1]
frontFrame: [8072, true, 10.]
dMonitoringState: [8073, true, 5., 1]
offroadLayout: [8074, false, 0.]
+wideEncodeIdx: [8075, true, 20.]
testModel: [8040, false, 0.]
testLiveLocation: [8045, false, 0.]
diff --git a/common/SConscript b/common/SConscript
index 103d416f..35abeb9e 100644
--- a/common/SConscript
+++ b/common/SConscript
@@ -1,6 +1,6 @@
-Import('env')
+Import('env', 'cython_dependencies')
-# parser
-env.Command(['common_pyx.so'],
- ['common_pyx_setup.py', 'clock.pyx'],
- "cd common && python3 common_pyx_setup.py build_ext --inplace")
+# 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")
diff --git a/common/kalman/SConscript b/common/kalman/SConscript
index abd7e043..3d7011fe 100644
--- a/common/kalman/SConscript
+++ b/common/kalman/SConscript
@@ -1,6 +1,6 @@
-Import('env')
+Import('env', 'cython_dependencies')
env.Command(['simple_kalman_impl.so'],
- ['simple_kalman_impl.pyx', 'simple_kalman_impl.pxd', 'simple_kalman_setup.py'],
- "cd common/kalman && python3 simple_kalman_setup.py build_ext --inplace")
+ 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")
diff --git a/common/kalman/simple_kalman_old.py b/common/kalman/simple_kalman_old.py
index 3f7d049c..d11770fa 100644
--- a/common/kalman/simple_kalman_old.py
+++ b/common/kalman/simple_kalman_old.py
@@ -8,7 +8,7 @@ class KF1D:
def __init__(self, x0, A, C, K):
self.x = x0
self.A = A
- self.C = C
+ self.C = np.atleast_2d(C)
self.K = K
self.A_K = self.A - np.dot(self.K, self.C)
diff --git a/common/kalman/tests/test_simple_kalman.py b/common/kalman/tests/test_simple_kalman.py
index 9b947a43..63087599 100644
--- a/common/kalman/tests/test_simple_kalman.py
+++ b/common/kalman/tests/test_simple_kalman.py
@@ -21,10 +21,10 @@ class TestSimpleKalman(unittest.TestCase):
K0_0 = 0.12287673
K1_0 = 0.29666309
- self.kf_old = KF1D_old(x0=np.matrix([[x0_0], [x1_0]]),
- A=np.matrix([[A0_0, A0_1], [A1_0, A1_1]]),
- C=np.matrix([C0_0, C0_1]),
- K=np.matrix([[K0_0], [K1_0]]))
+ self.kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]),
+ A=np.array([[A0_0, A0_1], [A1_0, A1_1]]),
+ C=np.array([C0_0, C0_1]),
+ K=np.array([[K0_0], [K1_0]]))
self.kf = KF1D(x0=[[x0_0], [x1_0]],
A=[[A0_0, A0_1], [A1_0, A1_1]],
@@ -47,8 +47,8 @@ class TestSimpleKalman(unittest.TestCase):
x = self.kf.update(v_wheel)
# Compare the output x, verify that the error is less than 1e-4
- self.assertAlmostEqual(x_old[0], x[0])
- self.assertAlmostEqual(x_old[1], x[1])
+ np.testing.assert_almost_equal(x_old[0], x[0])
+ np.testing.assert_almost_equal(x_old[1], x[1])
def test_new_is_faster(self):
setup = """
@@ -69,10 +69,10 @@ C0_1 = 0.0
K0_0 = 0.12287673
K1_0 = 0.29666309
-kf_old = KF1D_old(x0=np.matrix([[x0_0], [x1_0]]),
- A=np.matrix([[A0_0, A0_1], [A1_0, A1_1]]),
- C=np.matrix([C0_0, C0_1]),
- K=np.matrix([[K0_0], [K1_0]]))
+kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]),
+ A=np.array([[A0_0, A0_1], [A1_0, A1_1]]),
+ C=np.array([C0_0, C0_1]),
+ K=np.array([[K0_0], [K1_0]]))
kf = KF1D(x0=[[x0_0], [x1_0]],
A=[[A0_0, A0_1], [A1_0, A1_1]],
diff --git a/common/params.py b/common/params.py
index 7b90913e..e1067050 100755
--- a/common/params.py
+++ b/common/params.py
@@ -80,6 +80,7 @@ keys = {
"IsUploadRawEnabled": [TxType.PERSISTENT],
"LastAthenaPingTime": [TxType.PERSISTENT],
"LastUpdateTime": [TxType.PERSISTENT],
+ "LastUpdateException": [TxType.PERSISTENT],
"LimitSetSpeed": [TxType.PERSISTENT],
"LimitSetSpeedNeural": [TxType.PERSISTENT],
"LiveParameters": [TxType.PERSISTENT],
@@ -108,6 +109,7 @@ keys = {
"Offroad_InvalidTime": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_NeosUpdate": [TxType.CLEAR_ON_MANAGER_START],
+ "Offroad_UpdateFailed": [TxType.CLEAR_ON_MANAGER_START],
}
@@ -319,14 +321,15 @@ def write_db(params_path, key, value):
lock.acquire()
try:
- tmp_path = tempfile.mktemp(prefix=".tmp", dir=params_path)
- with open(tmp_path, "wb") as f:
+ tmp_path = tempfile.NamedTemporaryFile(mode="wb", prefix=".tmp", dir=params_path, delete=False)
+ with tmp_path as f:
f.write(value)
f.flush()
os.fsync(f.fileno())
+ os.chmod(tmp_path.name, 0o666)
path = "%s/d/%s" % (params_path, key)
- os.rename(tmp_path, path)
+ os.rename(tmp_path.name, path)
fsync_dir(os.path.dirname(path))
finally:
os.umask(prev_umask)
diff --git a/common/spinner.py b/common/spinner.py
index c49b124c..53e8ee52 100644
--- a/common/spinner.py
+++ b/common/spinner.py
@@ -4,14 +4,17 @@ from common.basedir import BASEDIR
class Spinner():
- def __init__(self):
- 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, 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 __enter__(self):
return self
@@ -40,23 +43,6 @@ class Spinner():
self.close()
-class FakeSpinner(Spinner):
- def __init__(self): # pylint: disable=super-init-not-called
- pass
-
- def __enter__(self):
- return self
-
- def update(self, _):
- pass
-
- def close(self):
- pass
-
- def __exit__(self, exc_type, exc_value, traceback):
- pass
-
-
if __name__ == "__main__":
import time
with Spinner() as s:
diff --git a/common/text_window.py b/common/text_window.py
index 88da8e53..b815d802 100755
--- a/common/text_window.py
+++ b/common/text_window.py
@@ -6,20 +6,22 @@ from common.basedir import BASEDIR
class TextWindow():
- def __init__(self, s):
- 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, 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 get_status(self):
if self.text_proc is not None:
self.text_proc.poll()
return self.text_proc.returncode
-
return None
def __enter__(self):
@@ -31,10 +33,11 @@ class TextWindow():
self.text_proc = None
def wait_for_exit(self):
- while True:
- if self.get_status() == 1:
- return
- time.sleep(0.1)
+ if self.text_proc is not None:
+ while True:
+ if self.get_status() == 1:
+ return
+ time.sleep(0.1)
def __del__(self):
self.close()
@@ -43,29 +46,6 @@ class TextWindow():
self.close()
-class FakeTextWindow(TextWindow):
- def __init__(self, s): # pylint: disable=super-init-not-called
- pass
-
- def get_status(self):
- return 1
-
- def wait_for_exit(self):
- return
-
- def __enter__(self):
- return self
-
- def update(self, _):
- pass
-
- def close(self):
- pass
-
- def __exit__(self, exc_type, exc_value, traceback):
- pass
-
-
if __name__ == "__main__":
text = """Traceback (most recent call last):
File "./controlsd.py", line 608, in
diff --git a/common/transformations/SConscript b/common/transformations/SConscript
index 7c051746..0f729522 100644
--- a/common/transformations/SConscript
+++ b/common/transformations/SConscript
@@ -1,9 +1,8 @@
-Import('env')
+Import('env', 'cython_dependencies')
d = Dir('.')
-env.Command(
- ['transformations.so'],
- ['transformations.pxd', 'transformations.pyx',
- 'coordinates.cc', 'orientation.cc', 'coordinates.hpp', 'orientation.hpp'],
- 'cd ' + d.path + ' && python3 setup.py build_ext --inplace')
+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')
diff --git a/common/transformations/camera.py b/common/transformations/camera.py
index e56a6f34..b406c33f 100644
--- a/common/transformations/camera.py
+++ b/common/transformations/camera.py
@@ -52,6 +52,13 @@ def get_view_frame_from_road_frame(roll, pitch, yaw, height):
return np.hstack((view_from_road, [[0], [height], [0]]))
+# aka 'extrinsic_matrix'
+def get_view_frame_from_calib_frame(roll, pitch, yaw, height):
+ device_from_calib= orient.rot_from_euler([roll, pitch, yaw])
+ view_from_calib = view_frame_from_device_frame.dot(device_from_calib)
+ return np.hstack((view_from_calib, [[0], [height], [0]]))
+
+
def vp_from_ke(m):
"""
Computes the vanishing point from the product of the intrinsic and extrinsic
diff --git a/common/transformations/coordinates.cc b/common/transformations/coordinates.cc
index 313683b6..8a1aa0ad 100644
--- a/common/transformations/coordinates.cc
+++ b/common/transformations/coordinates.cc
@@ -10,9 +10,9 @@
#define RAD2DEG(x) ((x) * 180.0 / M_PI)
-double a = 6378137;
-double b = 6356752.3142;
-double esq = 6.69437999014 * 0.001;
+double a = 6378137; // lgtm [cpp/short-global-name]
+double b = 6356752.3142; // lgtm [cpp/short-global-name]
+double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name]
double e1sq = 6.73949674228 * 0.001;
diff --git a/common/transformations/model.py b/common/transformations/model.py
index 070d1747..a3b46858 100644
--- a/common/transformations/model.py
+++ b/common/transformations/model.py
@@ -2,6 +2,7 @@ import numpy as np
from common.transformations.camera import (FULL_FRAME_SIZE, eon_focal_length,
get_view_frame_from_road_frame,
+ get_view_frame_from_calib_frame,
vp_from_ke)
# segnet
@@ -73,6 +74,9 @@ bigmodel_frame_from_road_frame = np.dot(bigmodel_intrinsics,
medmodel_frame_from_road_frame = np.dot(medmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
+medmodel_frame_from_calib_frame = np.dot(medmodel_intrinsics,
+ get_view_frame_from_calib_frame(0, 0, 0, 0))
+
model_frame_from_bigmodel_frame = np.dot(model_intrinsics, np.linalg.inv(bigmodel_intrinsics))
medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics))
diff --git a/common/transformations/orientation.py b/common/transformations/orientation.py
index f0920942..415e247a 100644
--- a/common/transformations/orientation.py
+++ b/common/transformations/orientation.py
@@ -46,7 +46,6 @@ quats_from_rotations = rot2quat
quat_from_rot = rot2quat
rotations_from_quats = quat2rot
rot_from_quat = quat2rot
-rot_from_quat = quat2rot
euler_from_rot = rot2euler
euler_from_quat = quat2euler
rot_from_euler = euler2rot
diff --git a/installer/updater/updater b/installer/updater/updater
index 15858eab..66047420 100755
Binary files a/installer/updater/updater and b/installer/updater/updater differ
diff --git a/installer/updater/updater.cc b/installer/updater/updater.cc
index a76be8b8..ca0b9270 100644
--- a/installer/updater/updater.cc
+++ b/installer/updater/updater.cc
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
@@ -33,10 +34,10 @@
#define USER_AGENT "NEOSUpdater-0.2"
-#define MANIFEST_URL_EON_STAGING "https://github.com/commaai/eon-neos/raw/master/update.staging.json"
-#define MANIFEST_URL_EON_LOCAL "http://192.168.5.1:8000/neosupdate/update.local.json"
-#define MANIFEST_URL_EON "https://github.com/commaai/eon-neos/raw/master/update.json"
-const char *manifest_url = MANIFEST_URL_EON;
+#define MANIFEST_URL_NEOS_STAGING "https://github.com/commaai/eon-neos/raw/master/update.staging.json"
+#define MANIFEST_URL_NEOS_LOCAL "http://192.168.5.1:8000/neosupdate/update.local.json"
+#define MANIFEST_URL_NEOS "https://github.com/commaai/eon-neos/raw/master/update.json"
+const char *manifest_url = MANIFEST_URL_NEOS;
#define RECOVERY_DEV "/dev/block/bootdevice/by-name/recovery"
#define RECOVERY_COMMAND "/cache/recovery/command"
@@ -96,7 +97,7 @@ std::string download_string(CURL *curl, std::string url) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0);
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 0);
@@ -149,6 +150,32 @@ static void start_settings_activity(const char* name) {
system(launch_cmd);
}
+bool is_settings_active() {
+ FILE *fp;
+ char sys_output[4096];
+
+ fp = popen("/bin/dumpsys window windows", "r");
+ if (fp == NULL) {
+ return false;
+ }
+
+ bool active = false;
+ while (fgets(sys_output, sizeof(sys_output), fp) != NULL) {
+ if (strstr(sys_output, "mCurrentFocus=null") != NULL) {
+ break;
+ }
+
+ if (strstr(sys_output, "mCurrentFocus=Window") != NULL) {
+ active = true;
+ break;
+ }
+ }
+
+ pclose(fp);
+
+ return active;
+}
+
struct Updater {
bool do_exit = false;
@@ -166,7 +193,6 @@ struct Updater {
std::mutex lock;
- // i hate state machines give me coroutines already
enum UpdateState {
CONFIRMATION,
LOW_BATTERY,
@@ -190,9 +216,15 @@ struct Updater {
int b_x, b_w, b_y, b_h;
int balt_x;
+ // download stage writes these for the installation stage
+ int recovery_len;
+ std::string recovery_hash;
+ std::string recovery_fn;
+ std::string ota_fn;
+
CURL *curl = NULL;
- Updater() {
+ void ui_init() {
touch_init(&touch);
fb = framebuffer_init("updater", 0x00001000, false,
@@ -218,7 +250,6 @@ struct Updater {
b_h = 220;
state = CONFIRMATION;
-
}
int download_file_xferinfo(curl_off_t dltotal, curl_off_t dlno,
@@ -251,7 +282,7 @@ struct Updater {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0);
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, resume_from);
@@ -319,32 +350,113 @@ struct Updater {
state = RUNNING;
}
- std::string stage_download(std::string url, std::string hash, std::string name) {
+ std::string download(std::string url, std::string hash, std::string name) {
std::string out_fn = UPDATE_DIR "/" + util::base_name(url);
- set_progress("Downloading " + name + "...");
- bool r = download_file(url, out_fn);
- if (!r) {
- set_error("failed to download " + name);
- return "";
+ // start or resume downloading if hash doesn't match
+ std::string fn_hash = sha256_file(out_fn);
+ if (hash.compare(fn_hash) != 0) {
+ set_progress("Downloading " + name + "...");
+ bool r = download_file(url, out_fn);
+ if (!r) {
+ set_error("failed to download " + name);
+ unlink(out_fn.c_str());
+ return "";
+ }
+ fn_hash = sha256_file(out_fn);
}
set_progress("Verifying " + name + "...");
- std::string fn_hash = sha256_file(out_fn);
printf("got %s hash: %s\n", name.c_str(), hash.c_str());
if (fn_hash != hash) {
set_error(name + " was corrupt");
unlink(out_fn.c_str());
return "";
}
-
return out_fn;
}
- void run_stages() {
+ bool download_stage() {
curl = curl_easy_init();
assert(curl);
+ // ** quick checks before download **
+
+ if (!check_space()) {
+ set_error("2GB of free space required to update");
+ return false;
+ }
+
+ mkdir(UPDATE_DIR, 0777);
+
+ set_progress("Finding latest version...");
+ std::string manifest_s = download_string(curl, manifest_url);
+ printf("manifest: %s\n", manifest_s.c_str());
+
+ std::string err;
+ auto manifest = json11::Json::parse(manifest_s, err);
+ if (manifest.is_null() || !err.empty()) {
+ set_error("failed to load update manifest");
+ return false;
+ }
+
+ std::string ota_url = manifest["ota_url"].string_value();
+ std::string ota_hash = manifest["ota_hash"].string_value();
+
+ std::string recovery_url = manifest["recovery_url"].string_value();
+ recovery_hash = manifest["recovery_hash"].string_value();
+ recovery_len = manifest["recovery_len"].int_value();
+
+ // std::string installer_url = manifest["installer_url"].string_value();
+ // std::string installer_hash = manifest["installer_hash"].string_value();
+
+ if (ota_url.empty() || ota_hash.empty()) {
+ set_error("invalid update manifest");
+ return false;
+ }
+
+ // std::string installer_fn = download(installer_url, installer_hash, "installer");
+ // if (installer_fn.empty()) {
+ // //error'd
+ // return;
+ // }
+
+ // ** handle recovery download **
+ if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) {
+ set_progress("Skipping recovery flash...");
+ } else {
+ // only download the recovery if it differs from what's flashed
+ set_progress("Checking recovery...");
+ std::string existing_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len);
+ printf("existing recovery hash: %s\n", existing_recovery_hash.c_str());
+
+ if (existing_recovery_hash != recovery_hash) {
+ recovery_fn = download(recovery_url, recovery_hash, "recovery");
+ if (recovery_fn.empty()) {
+ // error'd
+ return false;
+ }
+ }
+ }
+
+ // ** handle ota download **
+ ota_fn = download(ota_url, ota_hash, "update");
+ if (ota_fn.empty()) {
+ //error'd
+ return false;
+ }
+
+ // download sucessful
+ return true;
+ }
+
+ // thread that handles downloading and installing the update
+ void run_stages() {
+ printf("run_stages start\n");
+
+
+ // ** download update **
+
if (!check_battery()) {
set_battery_low();
int battery_cap = battery_capacity();
@@ -356,77 +468,12 @@ struct Updater {
set_running();
}
- if (!check_space()) {
- set_error("2GB of free space required to update");
+ bool sucess = download_stage();
+ if (!sucess) {
return;
}
- mkdir(UPDATE_DIR, 0777);
-
- const int EON = (access("/EON", F_OK) != -1);
-
- set_progress("Finding latest version...");
- std::string manifest_s;
- if (EON) {
- manifest_s = download_string(curl, manifest_url);
- } else {
- // don't update NEO
- exit(0);
- }
-
- printf("manifest: %s\n", manifest_s.c_str());
-
- std::string err;
- auto manifest = json11::Json::parse(manifest_s, err);
- if (manifest.is_null() || !err.empty()) {
- set_error("failed to load update manifest");
- return;
- }
-
- std::string ota_url = manifest["ota_url"].string_value();
- std::string ota_hash = manifest["ota_hash"].string_value();
-
- std::string recovery_url = manifest["recovery_url"].string_value();
- std::string recovery_hash = manifest["recovery_hash"].string_value();
- int recovery_len = manifest["recovery_len"].int_value();
-
- // std::string installer_url = manifest["installer_url"].string_value();
- // std::string installer_hash = manifest["installer_hash"].string_value();
-
- if (ota_url.empty() || ota_hash.empty()) {
- set_error("invalid update manifest");
- return;
- }
-
- // std::string installer_fn = stage_download(installer_url, installer_hash, "installer");
- // if (installer_fn.empty()) {
- // //error'd
- // return;
- // }
-
- std::string recovery_fn;
- if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) {
- set_progress("Skipping recovery flash...");
- } else {
- // only download the recovery if it differs from what's flashed
- set_progress("Checking recovery...");
- std::string existing_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len);
- printf("existing recovery hash: %s\n", existing_recovery_hash.c_str());
-
- if (existing_recovery_hash != recovery_hash) {
- recovery_fn = stage_download(recovery_url, recovery_hash, "recovery");
- if (recovery_fn.empty()) {
- // error'd
- return;
- }
- }
- }
-
- std::string ota_fn = stage_download(ota_url, ota_hash, "update");
- if (ota_fn.empty()) {
- //error'd
- return;
- }
+ // ** install update **
if (!check_battery()) {
set_battery_low();
@@ -601,7 +648,7 @@ struct Updater {
int powerprompt_y = 312;
nvgFontFace(vg, "opensans_regular");
nvgFontSize(vg, 64.0f);
- nvgText(vg, fb_w/2, 740, "Ensure EON is connected to power.", NULL);
+ nvgText(vg, fb_w/2, 740, "Ensure your device remains connected to a power source.", NULL);
NVGpaint paint = nvgBoxGradient(
vg, progress_x + 1, progress_y + 1,
@@ -657,9 +704,7 @@ struct Updater {
void ui_update() {
std::lock_guard guard(lock);
- switch (state) {
- case ERROR:
- case CONFIRMATION: {
+ if (state == ERROR || state == CONFIRMATION) {
int touch_x = -1, touch_y = -1;
int res = touch_poll(&touch, &touch_x, &touch_y, 0);
if (res == 1 && !is_settings_active()) {
@@ -678,13 +723,11 @@ struct Updater {
}
}
}
- default:
- break;
- }
}
-
void go() {
+ ui_init();
+
while (!do_exit) {
ui_update();
@@ -718,51 +761,37 @@ struct Updater {
update_thread_handle.join();
}
+ // reboot
system("service call power 16 i32 0 i32 0 i32 1");
}
- bool is_settings_active() {
- FILE *fp;
- char sys_output[4096];
-
- fp = popen("/bin/dumpsys window windows", "r");
- if (fp == NULL) {
- return false;
- }
-
- bool active = false;
- while (fgets(sys_output, sizeof(sys_output), fp) != NULL) {
- if (strstr(sys_output, "mCurrentFocus=null") != NULL) {
- break;
- }
-
- if (strstr(sys_output, "mCurrentFocus=Window") != NULL) {
- active = true;
- break;
- }
- }
-
- pclose(fp);
-
- return active;
- }
-
};
}
+
int main(int argc, char *argv[]) {
+ bool background_cache = false;
if (argc > 1) {
if (strcmp(argv[1], "local") == 0) {
- manifest_url = MANIFEST_URL_EON_LOCAL;
+ manifest_url = MANIFEST_URL_NEOS_LOCAL;
} else if (strcmp(argv[1], "staging") == 0) {
- manifest_url = MANIFEST_URL_EON_STAGING;
+ manifest_url = MANIFEST_URL_NEOS_STAGING;
+ } else if (strcmp(argv[1], "bgcache") == 0) {
+ manifest_url = argv[2];
+ background_cache = true;
} else {
manifest_url = argv[1];
}
}
+
printf("updating from %s\n", manifest_url);
Updater updater;
- updater.go();
- return 0;
+ int err = 0;
+ if (background_cache) {
+ err = !updater.download_stage();
+ } else {
+ updater.go();
+ }
+ return err;
}
diff --git a/launch.sh b/launch.sh
new file mode 100755
index 00000000..eeebfc9e
--- /dev/null
+++ b/launch.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/bash
+
+export PASSIVE="0"
+exec ./launch_chffrplus.sh
diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh
index ae166041..af548356 100755
--- a/launch_chffrplus.sh
+++ b/launch_chffrplus.sh
@@ -1,25 +1,20 @@
#!/usr/bin/bash
-export OMP_NUM_THREADS=1
-export MKL_NUM_THREADS=1
-export NUMEXPR_NUM_THREADS=1
-export OPENBLAS_NUM_THREADS=1
-export VECLIB_MAXIMUM_THREADS=1
-
if [ -z "$BASEDIR" ]; then
BASEDIR="/data/openpilot"
fi
-if [ -z "$PASSIVE" ]; then
- export PASSIVE="1"
-fi
+source "$BASEDIR/launch_env.sh"
-STAGING_ROOT="/data/safe_staging"
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
function launch {
# Wifi scan
wpa_cli IFNAME=wlan0 SCAN
+ # Remove orphaned git lock if it exists on boot
+ [ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock
+
# Check to see if there's a valid overlay-based update available. Conditions
# are as follows:
#
@@ -49,6 +44,7 @@ function launch {
git submodule foreach --recursive git reset --hard
echo "Restarting launch script ${LAUNCHER_LOCATION}"
+ unset REQUIRED_NEOS_VERSION
exec "${LAUNCHER_LOCATION}"
else
echo "openpilot backup found, not updating"
@@ -75,26 +71,21 @@ function launch {
[ -d "/proc/irq/733" ] && echo 3 > /proc/irq/733/smp_affinity_list # USB for LeEco
[ -d "/proc/irq/736" ] && echo 3 > /proc/irq/736/smp_affinity_list # USB for OP3T
- DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
-
- # Remove old NEOS update file
- # TODO: move this code to the updater
- if [ -d /data/neoupdate ]; then
- rm -rf /data/neoupdate
- fi
# Check for NEOS update
- if [ $(< /VERSION) != "14" ]; then
+ if [ $(< /VERSION) != "$REQUIRED_NEOS_VERSION" ]; then
if [ -f "$DIR/scripts/continue.sh" ]; then
cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh"
fi
if [ ! -f "$BASEDIR/prebuilt" ]; then
- echo "Clearing build products and resetting scons state prior to NEOS update"
- cd $BASEDIR && scons --clean
- rm -rf /tmp/scons_cache
- rm -r $BASEDIR/.sconsign.dblite
+ # Clean old build products, but preserve the scons cache
+ cd $DIR
+ scons --clean
+ git clean -xdf
+ git submodule foreach --recursive git clean -xdf
fi
+
"$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json"
else
if [[ $(uname -v) == "#1 SMP PREEMPT Wed Jun 10 12:40:53 PDT 2020" ]]; then
diff --git a/launch_env.sh b/launch_env.sh
new file mode 100755
index 00000000..9a86d315
--- /dev/null
+++ b/launch_env.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/bash
+
+export OMP_NUM_THREADS=1
+export MKL_NUM_THREADS=1
+export NUMEXPR_NUM_THREADS=1
+export OPENBLAS_NUM_THREADS=1
+export VECLIB_MAXIMUM_THREADS=1
+
+if [ -z "$REQUIRED_NEOS_VERSION" ]; then
+ export REQUIRED_NEOS_VERSION="14"
+fi
+
+if [ -z "$PASSIVE" ]; then
+ export PASSIVE="1"
+fi
+
+export STAGING_ROOT="/data/safe_staging"
diff --git a/models/dmonitoring_model_q.dlc b/models/dmonitoring_model_q.dlc
index 44ddc8f0..9935584b 100644
Binary files a/models/dmonitoring_model_q.dlc and b/models/dmonitoring_model_q.dlc differ
diff --git a/opendbc/.gitignore b/opendbc/.gitignore
index 1d65c548..f2596919 100644
--- a/opendbc/.gitignore
+++ b/opendbc/.gitignore
@@ -14,4 +14,3 @@ can/packer_pyx.cpp
can/parser_pyx.cpp
can/packer_pyx.html
can/parser_pyx.html
-can/packer_impl.cpp
diff --git a/opendbc/can/SConscript b/opendbc/can/SConscript
index 8fb0fc8a..c8d4f347 100644
--- a/opendbc/can/SConscript
+++ b/opendbc/can/SConscript
@@ -1,4 +1,4 @@
-Import('env', 'cereal')
+Import('env', 'cereal', 'cython_dependencies')
import os
from opendbc.can.process_dbc import process
@@ -17,7 +17,6 @@ for x in sorted(os.listdir('../')):
libdbc = env.SharedLibrary('libdbc', ["dbc.cc", "parser.cc", "packer.cc", "common.cc"]+dbcs, LIBS=["capnp", "kj"])
# Build packer and parser
-
-env.Command(['packer_pyx.so', 'parser_pyx.so'],
- [libdbc, cereal, 'common_pyx_setup.py', 'packer_pyx.pyx', 'parser_pyx.pyx', 'common.pxd'],
- "cd opendbc/can && python3 common_pyx_setup.py build_ext --inplace")
+env.Command(['packer_pyx.so', 'packer_pyx.cpp', 'parser_pyx.so', 'parser_pyx.cpp'],
+ cython_dependencies + [libdbc, cereal, 'common_pyx_setup.py', 'common.pxd', 'packer_pyx.pyx', 'parser_pyx.pyx', 'packer.cc', 'parser.cc'],
+ "cd opendbc/can && python3 common_pyx_setup.py build_ext --inplace")
diff --git a/opendbc/can/common_pyx_setup.py b/opendbc/can/common_pyx_setup.py
index b071dc36..72a0cde7 100644
--- a/opendbc/can/common_pyx_setup.py
+++ b/opendbc/can/common_pyx_setup.py
@@ -63,9 +63,9 @@ setup(name='CAN parser',
include_dirs=include_dirs,
extra_link_args=extra_link_args,
),
+ nthreads=4,
annotate=ANNOTATE
),
- nthreads=4,
)
if platform.system() == "Darwin":
@@ -85,9 +85,9 @@ setup(name='CAN packer',
include_dirs=include_dirs,
extra_link_args=extra_link_args,
),
+ nthreads=4,
annotate=ANNOTATE
),
- nthreads=4,
)
if platform.system() == "Darwin":
diff --git a/opendbc/can/parser_pyx.pyx b/opendbc/can/parser_pyx.pyx
index f12b2e6c..bd5adf6f 100644
--- a/opendbc/can/parser_pyx.pyx
+++ b/opendbc/can/parser_pyx.pyx
@@ -3,20 +3,17 @@
from libcpp.string cimport string
from libcpp.vector cimport vector
-from libcpp cimport bool
from libcpp.unordered_set cimport unordered_set
from libc.stdint cimport uint32_t, uint64_t, uint16_t
from libcpp.map cimport map
-
-from collections import defaultdict
+from libcpp cimport bool
from common cimport CANParser as cpp_CANParser
from common cimport SignalParseOptions, MessageParseOptions, dbc_lookup, SignalValue, DBC
-
-from libcpp cimport bool
import os
import numbers
+from collections import defaultdict
cdef int CAN_INVALID_CNT = 5
@@ -30,7 +27,7 @@ cdef class CANParser:
vector[SignalValue] can_values
bool test_mode_enabled
- cdef public:
+ cdef readonly:
string dbc_name
dict vl
dict ts
diff --git a/opendbc/honda_crv_ex_2017_body_generated.dbc b/opendbc/honda_crv_ex_2017_body_generated.dbc
new file mode 100644
index 00000000..9bf77b3f
--- /dev/null
+++ b/opendbc/honda_crv_ex_2017_body_generated.dbc
@@ -0,0 +1,13 @@
+CM_ "AUTOGENERATED FILE, DO NOT EDIT"
+
+CM_ "honda_crv_ex_2017_body.dbc starts here"
+BO_ 318291879 BSM_STATUS_RIGHT: 8 XXX
+ SG_ BSM_ALERT : 4|1@0+ (1,0) [0|1] "" XXX
+ SG_ BSM_MODE : 6|2@0+ (1,0) [0|3] "" XXX
+
+BO_ 318291615 BSM_STATUS_LEFT: 8 XXX
+ SG_ BSM_ALERT : 4|1@0+ (1,0) [0|1] "" XXX
+ SG_ BSM_MODE : 6|2@0+ (1,0) [0|3] "" XXX
+
+VAL_ 318291879 BSM_MODE 2 "blind_spot" 1 "cross_traffic" 0 "off";
+VAL_ 318291615 BSM_MODE 2 "blind_spot" 1 "cross_traffic" 0 "off";
diff --git a/opendbc/hyundai_kia_generic.dbc b/opendbc/hyundai_kia_generic.dbc
index d1c7605a..958b5c1f 100644
--- a/opendbc/hyundai_kia_generic.dbc
+++ b/opendbc/hyundai_kia_generic.dbc
@@ -191,8 +191,12 @@ BO_ 916 TCS13: 8 ESC
SG_ BrakeLight : 11|1@1+ (1.0,0.0) [0.0|1.0] "" CLU,EMS,SCC
SG_ DCEnable : 12|1@1+ (1.0,0.0) [0.0|1.0] "" EMS,SCC
SG_ AliveCounterTCS : 13|3@1+ (1.0,0.0) [0.0|7.0] "" EMS,SCC
- SG_ ACCReqLim : 22|2@1+ (1.0,0.0) [0.0|3.0] "" EMS,SCC
- SG_ TQI_ACC : 24|8@1+ (0.390625,0.0) [0.0|99.609375] "%" EMS
+ SG_ Pre_TCS_CTL : 16|1@1+ (1.0,0.0) [0.0|1.0] "" Vector__XXX
+ SG_ EBA_ACK : 17|1@1+ (1.0,0.0) [0.0|1.0] "" Vector__XXX
+ SG_ FCA_ACK : 18|1@1+ (1.0,0.0) [0.0|1.0] "" Vector__XXX
+ SG_ DF_BF_STAT : 19|2@1+ (1.0,0.0) [0.0|3.0] "" BCW
+ SG_ SCCReqLim : 21|2@1+ (1.0,0.0) [0.0|3.0] "" SCC
+ SG_ TQI_SCC : 23|9@1+ (0.390625,0.0) [0.0|199.609375] "%" Vector__XXX
SG_ ACCEL_REF_ACC : 32|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" EMS,SCC
SG_ ACCEnable : 43|2@1+ (1.0,0.0) [0.0|3.0] "" EMS,SCC
SG_ DriverOverride : 45|2@1+ (1.0,0.0) [0.0|3.0] "" EMS,SCC
@@ -448,6 +452,7 @@ BO_ 897 MDPS11: 8 MDPS
SG_ CF_Mdps_LKAS_FUNC : 58|1@1+ (1.0,0.0) [0.0|1.0] "flag" LDWS_LKAS
SG_ CF_Mdps_CurrMode : 59|2@1+ (1.0,0.0) [0.0|3.0] "" LDWS_LKAS
SG_ CF_Mdps_Type : 61|2@1+ (1.0,0.0) [0.0|2.0] "" LDWS_LKAS,SPAS
+ SG_ CF_MDPS_VSM_FUNC : 56|1@0+ (1.0,0.0) [0.0|1.0] "" XXX
BO_ 896 DI_BOX13: 8 DI_BOX
SG_ CF_DiBox_HPreInjVConfStat : 0|8@1+ (1.0,0.0) [0.0|255.0] "" EMS
@@ -961,7 +966,7 @@ BO_ 64 DATC14: 8 DATC
SG_ DATC_ADSDisp : 28|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
BO_ 832 LKAS11: 8 LDWS_LKAS
- SG_ CF_Lkas_Bca_R : 0|2@1+ (1.0,0.0) [0.0|3.0] "" CLU,IBOX,PSB
+ SG_ CF_Lkas_LdwsActivemode : 0|2@1+ (1,0) [0|3] "" CLU,IBOX,PSB
SG_ CF_Lkas_LdwsSysState : 2|4@1+ (1.0,0.0) [0.0|15.0] "" CLU,IBOX,PSB
SG_ CF_Lkas_SysWarning : 6|4@1+ (1.0,0.0) [0.0|15.0] "" BCM,CLU
SG_ CF_Lkas_LdwsLHWarning : 10|2@1+ (1.0,0.0) [0.0|3.0] "" BCM,CLU,PSB
@@ -978,11 +983,11 @@ BO_ 832 LKAS11: 8 LDWS_LKAS
SG_ CF_Lkas_FcwSysState : 40|3@1+ (1.0,0.0) [0.0|7.0] "" CLU
SG_ CF_Lkas_FcwCollisionWarning : 43|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
SG_ CF_Lkas_FusionState : 45|2@1+ (1.0,0.0) [0.0|3.0] "" SCC
+ SG_ CF_Lkas_Unknown1 : 47|1@1+ (1.0,0.0) [0.0|1.0] "" XXX
SG_ CF_Lkas_Chksum : 48|8@1+ (1.0,0.0) [0.0|255.0] "" MDPS
SG_ CF_Lkas_FcwOpt_USM : 56|3@1+ (1.0,0.0) [0.0|7.0] "" CLU
SG_ CF_Lkas_LdwsOpt_USM : 59|3@1+ (1.0,0.0) [0.0|7.0] "" CLU,MDPS
- SG_ CF_Lkas_Unknown1 : 47|1@1+ (1,0) [0|3] "" XXX
- SG_ CF_Lkas_Unknown2 : 63|2@0+ (1,0) [0|3] "" XXX
+ SG_ CF_Lkas_Unknown2 : 62|2@1+ (1.0,0.0) [0.0|1.0] "" XXX
BO_ 1342 LKAS12: 6 LDWS_LKAS
SG_ CF_Lkas_TsrSlifOpt : 10|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
@@ -1037,6 +1042,7 @@ BO_ 1322 CLU15: 8 CLU
SG_ CF_Clu_HudFontSizeSet : 31|2@1+ (1.0,0.0) [0.0|3.0] "" HUD
SG_ CF_Clu_LanguageInfo : 33|5@1+ (1.0,0.0) [0.0|31.0] "" BCM,PGS
SG_ CF_Clu_ClusterSound : 38|1@1- (1.0,0.0) [0.0|0.0] "" BCM,CGW,FATC
+ SG_ CF_Clu_VehicleSpeed2 : 48|8@1+ (1,0) [0|255] "" XXX
BO_ 1066 _4WD13: 6 _4WD
SG_ _4WD_CURRENT : 0|8@1+ (0.390625,0.0) [-50.0|50.0] "A" TCU
@@ -1250,14 +1256,6 @@ BO_ 790 EMS11: 8 EMS
SG_ VS : 48|8@1+ (1.0,0.0) [0.0|254.0] "km/h" _4WD,AAF,ACU,AHLS,BCM,CLU,DATC,ECS,EPB,IBOX,LCA,LDWS_LKAS,LVR,MDPS,ODS,SCC,SMK,SPAS,TCU,TPMS
SG_ RATIO_TQI_BAS_MAX_STND : 56|8@1+ (0.0078,0.0) [0.0|2.0] "" _4WD,IBOX,TCU
-BO_ 881 E_EMS11: 8 XXX
- SG_ Cruise_Limit_Status : 13|1@1+ (1,0) [0|1] "" XXX
- SG_ Cruise_Limit_Target : 23|8@1+ (1,0) [0|15] "" XXX
- SG_ Gear_Change : 12|1@0+ (1,0) [0|31] "" XXX
- SG_ IG_Reactive_Stat : 8|3@1+ (1,0) [0|3] "" XXX
- SG_ Brake_Pedal_Pos : 0|8@1+ (1,0) [0|127] "" XXX
- SG_ Accel_Pedal_Pos : 31|8@1+ (1,0) [0|7] "" XXX
-
BO_ 1301 CLU14: 8 CLU
SG_ CF_Clu_ADrUNValueSet : 0|3@1+ (1.0,0.0) [0.0|7.0] "" BCM
SG_ CF_Clu_ADrLNValueSet : 3|3@1+ (1.0,0.0) [0.0|7.0] "" BCM
@@ -1380,6 +1378,7 @@ BO_ 1290 SCC13: 8 SCC
SG_ SCCDrvModeRValue : 0|3@1+ (1,0) [0|7] "" CLU
SG_ SCC_Equip : 3|1@1+ (1,0) [0|1] "" ESC
SG_ AebDrvSetStatus : 4|3@1+ (1,0) [0|7] "" CLU,ESC
+ SG_ Lead_Veh_Dep_Alert_USM : 13|2@0+ (1,0) [0|3] "" XXX
BO_ 1287 TCS15: 4 ESC
SG_ ABS_W_LAMP : 0|1@1+ (1.0,0.0) [0.0|1.0] "" _4WD,CLU,CUBIS,IBOX
@@ -1451,6 +1450,18 @@ BO_ 909 FCA11: 8 FCA
SG_ Supplemental_Counter : 35|4@1+ (1,0) [0|15] "" XXX
SG_ PAINT1_Status : 16|2@1+ (1,0) [0|1] "" XXX
+BO_ 1156 HDA11_MFC: 8 XXX
+ SG_ Counter : 5|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_1 : 1|2@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 7|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_3 : 15|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_4 : 16|2@1+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_5 : 18|14@1+ (1,0) [0|63] "" XXX
+ SG_ NEW_SIGNAL_6 : 33|2@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_7 : 34|14@1+ (1,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_8 : 49|2@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_9 : 50|14@1- (1,-4095) [0|16383] "" XXX
+
BO_ 1155 FCA12: 8 FCA
SG_ FCA_USM : 0|3@1+ (1,0) [0|7] "" CGW,CLU,ESC
SG_ FCA_DrvSetState : 3|3@1+ (1,0) [0|7] "" CGW
@@ -1459,22 +1470,166 @@ BO_ 1186 FRT_RADAR11: 2 FCA
SG_ CF_FCA_Equip_Front_Radar : 0|3@1+ (1,0) [0|7] "" LDWS_LKAS,LDW_LKA,ESC
BO_ 905 SCC14: 8 SCC
- SG_ ComfortBandLower : 6|6@1+ (1,0) [0|0] "" Vector__XXX
- SG_ ComfortBandUpper : 0|6@1+ (1,0) [0|0] "" Vector__XXX
- SG_ JerkLowerLimit : 19|7@1+ (1,0) [0|0] "" Vector__XXX
- SG_ JerkUpperLimit : 12|7@1+ (0.1,0) [0|0] "" Vector__XXX
+ SG_ ComfortBandUpper : 0|6@1+ (0.0986,-4.14) [0|1.26] "m/s^2" ESC
+ SG_ ComfortBandLower : 6|6@1+ (0.0986,-4.14) [0|1.26] "m/s^2" ESC
+ SG_ JerkUpperLimit : 12|7@1+ (1,0) [0|12.7] "m/s^3" ESC
+ SG_ JerkLowerLimit : 19|7@1+ (0.1,0) [0|12.7] "m/s^3" ESC
SG_ ACCMode : 32|3@1+ (1,0) [0|7] "" CLU,HUD,LDWS_LKAS,ESC
SG_ ObjGap : 56|8@1+ (1,0) [0|255] "" CLU,HUD,ESC
-BO_ 882 ELECT_GEAR: 8 XXX
- SG_ Elect_Gear_Shifter : 16|3@1+ (1,0) [0|7] "" CLU
-
BO_ 1157 LFAHDA_MFC: 4 XXX
- SG_ LFA_USM : 28|2@1+ (1,0) [0|3] "" XXX
- SG_ LFA_SysWarning : 16|2@1+ (1,0) [0|3] "" XXX
- SG_ ACTIVE2 : 4|2@0+ (1,0) [0|3] "" XXX
SG_ HDA_USM : 0|2@1+ (1,0) [0|3] "" XXX
+ SG_ ACTIVE2 : 4|2@0+ (1,0) [0|3] "" XXX
+ SG_ LFA_SysWarning : 16|2@1+ (1,0) [0|3] "" XXX
SG_ ACTIVE : 25|1@1+ (1,0) [0|3] "" XXX
+ SG_ LFA_USM : 28|2@1+ (1,0) [0|3] "" XXX
+BO_ 913 BCM_PO_11: 8 Vector__XXX
+ SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
+ SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
+
+BO_ 1426 LABEL11: 8 XXX
+ SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 910 WHL_SPD12_FS: 5 iBAU
+ SG_ CRC : 0|8@1+ (1,0) [0|0] "" Vector__XXX
+ SG_ WHL_SPD12_AliveCounter : 8|4@1+ (1,0) [0|15] "" Vector__XXX
+ SG_ WHL_SPD_FL : 12|14@1+ (0.03125,0) [0|511.96875] "km/h" Vector__XXX
+ SG_ WHL_SPD_FR : 26|14@1+ (0.03125,0) [0|511.96875] "km/h" Vector__XXX
+
+BO_ 911 WHL_SPD13_FS: 5 iBAU
+ SG_ CRC : 0|8@1+ (1,0) [0|0] "" Vector__XXX
+ SG_ WHL_SPD13_AliveCounter : 8|4@1+ (1,0) [0|15] "" Vector__XXX
+ SG_ WHL_SPD_RL : 12|14@1+ (0.03125,0) [0|511.96875] "km/h" Vector__XXX
+ SG_ WHL_SPD_RR : 26|14@1+ (0.03125,0) [0|511.96875] "km/h" Vector__XXX
+
+BO_ 865 ADAS_PRK_11: 8 ADAS_PRK
+ SG_ CF_PCA_BrkReq : 24|1@1+ (1,0) [0|0] "" Vector__XXX
+ SG_ CF_PCA_DclTrgtVal : 28|4@1+ (0.04,0) [0|0] "g" Vector__XXX
+ SG_ PCA_ALIVE_CNT : 40|4@1+ (1,0) [0|0] "" Vector__XXX
+ SG_ PCA_CHECK_SUM : 48|8@1+ (1,0) [0|0] "" Vector__XXX
+
+BO_ 882 ELECT_GEAR: 8 XXX
+ SG_ Elect_Gear_Shifter : 16|4@1+ (1,0) [0|7] "" CLU
+
+BO_ 881 E_EMS11: 8 XXX
+ SG_ Brake_Pedal_Pos : 0|8@1+ (1,0) [0|127] "" XXX
+ SG_ IG_Reactive_Stat : 8|3@1+ (1,0) [0|3] "" XXX
+ SG_ Gear_Change : 12|1@0+ (1,0) [0|31] "" XXX
+ SG_ Cruise_Limit_Status : 13|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Limit_Target : 23|8@1+ (1,0) [0|15] "" XXX
+ SG_ Accel_Pedal_Pos : 31|8@1+ (1,0) [0|7] "" XXX
+
+BO_ 1355 EV_PC6: 8 CGW
+ SG_ CF_Vcu_SbwWarnMsg : 16|3@1+ (1,0) [0|7] "" Vector__XXX
+
+BO_ 1430 EV_PC2: 8 CGW
+ SG_ CR_Ldc_ActVol_LS_V : 32|8@1+ (0.1,0) [0|0] "V" Vector__XXX
+
+BO_ 1535 EV_PC10: 8 CGW
+ SG_ CF_Vcu_EpbRequest : 37|1@1+ (1,0) [0|0] "" Vector__XXX
+
+BO_ 908 RSPA11: 8 RSPA
+ SG_ CF_RSPA_State : 0|4@1+ (1,0) [0|15] "" XXX
+ SG_ CF_RSPA_Act : 4|2@1+ (1,0) [0|3] "" XXX
+ SG_ CF_RSPA_DecCmd : 6|2@1+ (1,0) [0|3] "" XXX
+ SG_ CF_RSPA_Trgt_Spd : 8|10@1+ (0.01,0) [0|10.23] "km/h" XXX
+ SG_ CF_RSPA_StopReq : 18|1@1+ (1,0) [0|2] "" XXX
+ SG_ CR_RSPA_EPB_Req : 22|2@1+ (1,0) [0|3] "" XXX
+ SG_ CF_RSPA_ACC_ACT : 50|1@1+ (1,0) [0|2] "" XXX
+ SG_ CF_RSPA_AliveCounter : 52|4@1+ (1,0) [0|15] "" XXX
+ SG_ CF_RSPA_CRC : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 914 S_MDPS11: 8 XXX
+ SG_ CF_Mdps_Stat : 0|4@1+ (1,0) [0|15] "" XXX
+ SG_ CR_Mdps_DrvTq : 8|12@1+ (1,0) [0|15] "" XXX
+ SG_ CR_Mdps_StrAng : 24|16@1- (1,0) [0|65535] "" XXX
+ SG_ CF_Mdps_AliveCnt : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ CF_Mdps_Chksum : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 357 S_MDPS12: 8 XXX
+ SG_ NEW_SIGNAL_1 : 0|12@1+ (1,0) [0|4095] "" XXX
+ SG_ NEW_SIGNAL_2 : 12|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Counter : 48|4@1+ (1,0) [0|15] "" XXX
+ SG_ Checksum : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 352 AHB1: 8 iBAU
+ SG_ CF_Ahb_SLmp : 0|2@1+ (1,0) [0|3] "" CLU
+ SG_ CF_Ahb_Def : 2|2@1+ (1,0) [0|3] "" CGW
+ SG_ CF_Ahb_Act : 4|2@1+ (1,0) [0|3] "" Vector__XXX
+ SG_ CF_Ahb_Diag : 6|1@1+ (1,0) [0|1] "" Vector__XXX
+ SG_ CF_Ahb_WLmp : 7|1@1+ (1,0) [0|1] "" CLU
+ SG_ CR_Ahb_StDep_mm : 8|16@1- (0.1,0) [-3276.8|3276.7] "mm" Vector__XXX
+ SG_ CF_Ahb_SnsFail : 24|1@1+ (1,0) [0|1] "" Vector__XXX
+ SG_ CF_Ahb_PedalCalStat : 25|1@1+ (1,0) [0|1] "" Vector__XXX
+ SG_ CF_Ahb_Bzzr : 26|1@1+ (1,0) [0|1] "" Vector__XXX
+ SG_ CF_Ahb_ChkSum : 56|8@1+ (1,0) [0|255] "" Vector__XXX
+
+BO_ 1191 4a7MFC: 8 XXX
+ SG_ PAINT1 : 0|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 1162 BCA11: 8 BCW
+ SG_ CF_BCA_State : 16|3@1+ (1,0) [0|7] "" CLU,iBAU
+ SG_ CF_BCA_Warning : 19|2@1+ (1,0) [0|3] "" CLU,iBAU
+ SG_ AliveCounter : 21|4@1+ (1,0) [0|15] "" CLU,iBAU
+ SG_ RCCA_Brake_Command : 29|1@1+ (1,0) [0|1] "" iBAU
+ SG_ Check_Sum : 56|8@1+ (1,0) [0|16] "" iBAU
+
+BO_ 1136 P_STS: 6 CGW
+ SG_ HCU1_STS : 6|2@1+ (1,0) [0|3] "" BCW,EPB,FCA,MDPS,SCC,iBAU
+ SG_ HCU5_STS : 8|2@1+ (1,0) [0|3] "" EPB,FCA,MDPS,iBAU
+
+BO_ 304 YRS11: 8 ACU
+ SG_ CR_Yrs_Yr : 0|16@1+ (0.005,-163.84) [-163.84|163.83] "deg/s" CGW,iBAU
+ SG_ CR_Yrs_LatAc : 16|16@1+ (0.000127465,-4.17677312) [-4.17677312|4.17651819] "g" iBAU
+ SG_ CF_Yrs_YrStat : 32|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CF_Yrs_LatAcStat : 36|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CF_Yrs_MCUStat : 40|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CR_Yrs_MsgCnt1 : 48|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CR_Yrs_Crc1 : 56|8@1+ (1,0) [0|255] "" iBAU
+
+BO_ 320 YRS12: 8 ACU
+ SG_ CF_Yrs_LongAcStat : 16|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CF_IMU_ResetStat : 20|4@1+ (1,0) [0|15] "" iBAU
+ SG_ YRS_Temp : 24|8@1+ (1,-68) [-68|187] "" iBAU
+ SG_ YRS_TempStat : 32|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CF_Yrs_Type : 36|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CR_Yrs_MsgCnt2 : 48|4@1+ (1,0) [0|15] "" iBAU
+ SG_ CR_Yrs_Crc2 : 56|8@1+ (1,0) [0|255] "" iBAU
+ SG_ CR_Yrs_LongAc : 0|16@1+ (0.000127465,-4.17677312) [-4.17677312|4.17651819] "g" CGW,iBAU
+
+BO_ 1173 YRS13: 8 ACU
+ SG_ YRS_SeralNo : 16|48@1+ (1,0) [0|281474976710655] "" iBAU
+
+BO_ 870 366_EMS: 8 EMS
+ SG_ N : 7|16@0+ (1,0.25) [0|16383.75] "rpm" XXX
+ SG_ EMS_Related : 23|16@0+ (1,0) [0|65535] "" XXX
+ SG_ TQFR : 39|8@0+ (0.390625,0) [0|99.6094] "%" XXX
+ SG_ VS : 40|8@1+ (1,0) [0|255] "km/h" MDPS
+ SG_ SWI_IGK : 48|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 854 356: 8 XXX
+ SG_ PAINT1 : 32|1@0+ (1,0) [0|1] "" XXX
+ SG_ PAINT2 : 34|2@0+ (1,0) [0|1] "" XXX
+ SG_ PAINT3 : 36|2@0+ (1,0) [0|3] "" XXX
+ SG_ PAINT4 : 38|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 1042 ICM_412h: 8 ICM
+ SG_ T_Outside_input : 0|9@0+ (0.01,0) [0|5] "V" Vector__XXX
+ SG_ WarningSoundOutput_1Group : 5|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ WarningSoundOutput_2Group : 6|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ WarningSoundOutput_3Group : 7|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ TRIP_A_DT_Display_clock : 22|7@0+ (1,0) [0|99] "clock" Vector__XXX
+ SG_ TRIP_A_DT_Display_minute : 29|6@0+ (1,0) [0|59] "minute" Vector__XXX
+ SG_ TRIP_B_DT_Display_clock : 38|7@0+ (1,0) [0|99] "clock" Vector__XXX
+ SG_ TRIP_B_DT_Display_minute : 45|6@0+ (1,0) [0|59] "minute" Vector__XXX
+ SG_ PopupMessageOutput_1Level : 48|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_2Level : 49|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_3Level : 50|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_4Level : 51|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_5Level : 52|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_6Level : 53|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_7Level : 54|1@0+ (1,0) [0|1] "" Vector__XXX
+ SG_ PopupMessageOutput_8Level : 55|1@0+ (1,0) [0|1] "" Vector__XXX
VAL_ 909 CF_VSM_Warn 2 "FCW" 3 "AEB";
diff --git a/opendbc/subaru_forester_2017_generated.dbc b/opendbc/subaru_forester_2017_generated.dbc
new file mode 100644
index 00000000..96bc0064
--- /dev/null
+++ b/opendbc/subaru_forester_2017_generated.dbc
@@ -0,0 +1,258 @@
+CM_ "AUTOGENERATED FILE, DO NOT EDIT"
+
+
+CM_ "Imported file _subaru_preglobal_2015.dbc starts here"
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX X
+
+
+BO_ 2 Steering: 8 XXX
+ SG_ Steering_Angle : 7|16@0- (0.1,0) [-500|500] "degree" XXX
+ SG_ Counter : 27|3@0+ (1,0) [0|7] "" XXX
+ SG_ Checksum : 39|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 208 G_Sensor: 8 XXX
+ SG_ Steering_Angle : 0|16@1- (-0.1,0) [-500|500] "" XXX
+ SG_ Lateral : 16|16@1- (-0.0035,1) [-255|255] "" XXX
+ SG_ Longitudinal : 48|16@1- (-0.00035,0) [-255|255] "" XXX
+
+BO_ 209 Brake_Pedal: 8 XXX
+ SG_ Speed : 0|16@1+ (0.05625,0) [0|255] "KPH" XXX
+ SG_ Brake_Pedal : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 210 Brake_2: 8 XXX
+ SG_ Brake_Light : 35|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Related : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ Right_Brake : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Left_Brake : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 211 Brake_Type: 8 XXX
+ SG_ Brake_Light : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Speed_Counter : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Cruise_On : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal_On : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 48|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 212 Wheel_Speeds: 8 XXX
+ SG_ FL : 0|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ FR : 16|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ RL : 32|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ RR : 48|16@1+ (0.0592,0) [0|255] "KPH" XXX
+
+BO_ 320 Throttle: 8 XXX
+ SG_ Throttle_Pedal : 0|8@1+ (0.392157,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Not_Full_Throttle : 14|1@1+ (1,0) [0|1] "" XXX
+ SG_ Engine_RPM : 16|14@1+ (1,0) [0|32767] "" XXX
+ SG_ Off_Throttle : 30|1@1+ (1,0) [0|1] "" XXX
+ SG_ Throttle_Cruise : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Combo : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Body : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Off_Throttle_2 : 56|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 321 Engine: 8 XXX
+ SG_ Engine_Torque : 0|15@1+ (1,0) [0|255] "" XXX
+ SG_ Engine_Stop : 15|1@1+ (1,0) [0|1] "" XXX
+ SG_ Wheel_Torque : 16|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Engine_RPM : 32|12@1+ (1,0) [0|8191] "" XXX
+
+BO_ 324 CruiseControl: 8 XXX
+ SG_ OnOffButton : 2|1@1+ (1,0) [0|1] "" XXX
+ SG_ SET_BUTTON : 3|1@1+ (1,0) [0|1] "" XXX
+ SG_ RES_BUTTON : 4|1@1+ (1,0) [0|1] "" XXX
+ SG_ Button : 13|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_On : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal_On : 51|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 328 Transmission: 8 XXX
+ SG_ Manual_Gear : 4|4@1+ (1,0) [0|15] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Transmission_Engine : 16|15@1+ (1,0) [0|65535] "" XXX
+ SG_ Gear : 48|4@1+ (1,0) [0|15] "" XXX
+ SG_ Gear_2 : 52|4@1+ (1,0) [0|15] "" XXX
+ SG_ Paddle_Shift : 60|2@1+ (1,0) [0|3] "" XXX
+
+BO_ 329 CVT_Ratio: 8 XXX
+
+BO_ 336 Brake_Pressure: 8 XXX
+ SG_ Brake_Pressure_Right : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Pressure_Left : 8|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 338 Stalk: 8 XXX
+ SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Brake_Light : 52|1@1+ (1,0) [0|1] "" XXX
+ SG_ Runlights : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ Headlights : 59|1@1+ (1,0) [0|1] "" XXX
+ SG_ Highbeam : 60|1@1+ (1,0) [0|1] "" XXX
+ SG_ Wiper : 62|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 352 ES_Brake: 8 XXX
+ SG_ Brake_Pressure : 0|16@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Light : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Error : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_On : 22|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 353 ES_CruiseThrottle: 8 XXX
+ SG_ Throttle_Cruise : 0|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Cruise_Activated : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 17|3@1+ (1,0) [0|7] "" XXX
+ SG_ Brake_On : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ DistanceSwap : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Standstill : 22|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ CloseDistance : 24|8@1+ (0.0196,0) [0|255] "m" XXX
+ SG_ Signal4 : 32|9@1+ (1,0) [0|255] "" XXX
+ SG_ Standstill_2 : 41|1@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Error : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal5 : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 44|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal6 : 47|1@1+ (1,0) [0|1] "" XXX
+ SG_ Button : 48|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal7 : 51|5@1+ (1,0) [0|31] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 354 ES_RPM: 8 XXX
+ SG_ Brake : 8|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 9|1@1+ (1,0) [0|1] "" XXX
+ SG_ RPM : 16|16@1+ (1,0) [0|65535] "" XXX
+ SG_ Checksum : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
+
+BO_ 356 ES_LKAS: 8 XXX
+ SG_ Counter : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ LKAS_Command : 8|13@1- (-1,0) [-4096|4096] "" XXX
+ SG_ LKAS_Active : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 359 ES_LDW: 8 XXX
+ SG_ All_depart_2015 : 0|1@1+ (1,0) [0|1] "" XXX
+ SG_ Right_Line_2017 : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Left_Line_2017 : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1All_Depart : 28|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig2All_Depart : 31|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Inactive_2017 : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Active : 37|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1Right_Depart : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1Right_Depart_Front : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig2Right_Depart : 50|1@1+ (1,0) [0|1] "" XXX
+ SG_ Left_Depart_Front : 51|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig3All_Depart : 52|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 604 BSD_RCTA: 8 XXX
+ SG_ Counter : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ State : 5|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_ADJACENT : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_ADJACENT : 33|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_APPROACHING : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_APPROACHING : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_RCTA : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_RCTA : 47|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 642 Dashlights: 8 XXX
+ SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ SEATBELT_FL : 40|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_BLINKER : 44|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_BLINKER : 45|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 880 Steering_Torque_2: 8 XXX
+ SG_ Steering_Voltage_Flat : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Steer_Torque_Sensor : 29|11@1- (-1,0) [-1000|1000] "" XXX
+ SG_ Counter : 40|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 884 BodyInfo: 8 XXX
+ SG_ DOOR_OPEN_FR : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_FL : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RL : 26|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RR : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_Hatch : 28|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 864 Engine_Temp: 8 XXX
+ SG_ Oil_Temp : 16|8@1+ (1,-40) [0|255] "" XXX
+ SG_ Coolant_Temp : 24|8@1+ (1,-40) [0|255] "" XXX
+ SG_ Cruise_Activated : 45|1@1+ (1,0) [0|1] "" XXX
+ SG_ Saved_Speed : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 866 Fuel: 8 XXX
+
+BO_ 1745 Dash_State: 8 XXX
+ SG_ Units : 15|1@1+ (1,0) [0|1] "" XXX
+
+CM_ SG_ 320 Off_Throttle_2 "Less sensitive";
+CM_ SG_ 320 Throttle_Body "Throttle related";
+CM_ SG_ 328 Gear "15 = P, 14 = R, 0 = N, 1-6=gear";
+CM_ SG_ 328 Gear_2 "15 = P, 14 = R, 0 = N, 1-6=gear";
+CM_ SG_ 353 Button "1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 resume deep";
+CM_ SG_ 354 RPM "20hz version of Transmission_Engine under Transmission";
+CM_ SG_ 359 Sig1Right_Depart "right depart, hill steep and seatbelt disengage";
+CM_ SG_ 359 LKAS_Inactive_2017 "1 when not steering, 0 when lkas steering";
+CM_ SG_ 359 Sig1Right_Depart_Front "object in front, right depart, hill steep and seatbelt disengage alert ";
+CM_ SG_ 359 Left_Depart_Front "warning after acceleration into car in front and left depart";
+CM_ SG_ 359 Sig1All_Depart "Left and right depart";
+CM_ SG_ 359 Sig2All_Depart "Left and right depart";
+CM_ SG_ 359 All_depart_2015 "always 1 on 2017";
+CM_ SG_ 604 R_APPROACHING "Faster car approaching in far right lane";
+CM_ SG_ 604 L_APPROACHING "Faster car approaching in far left lane";
+CM_ SG_ 604 R_RCTA "Rear cross traffic alert, only when in R gear";
+CM_ SG_ 604 L_RCTA "Rear cross traffic alert, only when in R gear";
+CM_ SG_ 642 Counter "Affected by signals";
+CM_ SG_ 642 SEATBELT_FL "Driver seatbelt";
+CM_ SG_ 880 Steering_Voltage_Flat "receives later than 371";
+
+VAL_ 328 Gear 0 "N" 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 14 "R" 15 "P";
+VAL_ 1745 Units 0 "Metric" 1 "Imperial";
+
+CM_ "subaru_forester_2017.dbc starts here"
+
+
+BO_ 355 ES_DashStatus: 8 XXX
+ SG_ Not_Ready_Startup : 4|2@1+ (1,0) [0|3] "" XXX
+ SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Set_Speed : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 40|3@1+ (1,0) [0|7] "" XXX
+ SG_ Cruise_Activated : 54|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 881 Steering_Torque: 8 XXX
+ SG_ Steering_Motor_Flat : 0|10@1+ (32,0) [0|1000] "" XXX
+ SG_ Steer_Torque_Output : 16|11@1- (-32,0) [-1000|1000] "" XXX
+ SG_ LKA_Lockout : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ Steer_Torque_Sensor : 29|11@1- (-1,0) [-1000|1000] "" XXX
+ SG_ Steering_Angle : 40|16@1- (-0.033,0) [-600|600] "" XXX
diff --git a/opendbc/subaru_global_2017.dbc b/opendbc/subaru_global_2017.dbc
deleted file mode 100644
index e1743ff0..00000000
--- a/opendbc/subaru_global_2017.dbc
+++ /dev/null
@@ -1,209 +0,0 @@
-VERSION ""
-
-
-NS_ :
- NS_DESC_
- CM_
- BA_DEF_
- BA_
- VAL_
- CAT_DEF_
- CAT_
- FILTER
- BA_DEF_DEF_
- EV_DATA_
- ENVVAR_DATA_
- SGTYPE_
- SGTYPE_VAL_
- BA_DEF_SGTYPE_
- BA_SGTYPE_
- SIG_TYPE_REF_
- VAL_TABLE_
- SIG_GROUP_
- SIG_VALTYPE_
- SIGTYPE_VALTYPE_
- BO_TX_BU_
- BA_DEF_REL_
- BA_REL_
- BA_DEF_DEF_REL_
- BU_SG_REL_
- BU_EV_REL_
- BU_BO_REL_
- SG_MUL_VAL_
-
-BS_:
-
-BU_: XXX X
-
-
-BO_ 2 Steering: 8 XXX
- SG_ Steering_Angle : 7|16@0- (0.1,0) [0|65535] "" XXX
- SG_ Counter : 25|3@1+ (1,0) [0|7] "" XXX
- SG_ CHECKSUM : 32|8@1+ (1,0) [0|255] "" XXX
-
-BO_ 64 Throttle: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|255] "" XXX
- SG_ Engine_RPM : 16|12@1+ (1,0) [0|255] "" XXX
- SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX
- SG_ Throttle_Cruise : 40|8@1+ (1,0) [0|255] "" XXX
- SG_ Throttle_Combo : 48|8@1+ (1,0) [0|255] "" XXX
- SG_ Off_Accel : 60|4@1+ (1,0) [0|7] "" XXX
-
-BO_ 72 Transmission: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Gear : 24|8@1+ (1,0) [0|255] "" XXX
-
-BO_ 326 Cruise_Buttons: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Signal1 : 12|30@1+ (1,0) [0|1073741823] "" XXX
- SG_ Main : 42|1@1+ (1,0) [0|1] "" XXX
- SG_ set : 43|1@1+ (1,0) [0|1] "" XXX
- SG_ Resume : 44|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal2 : 45|19@1+ (1,0) [0|524287] "" XXX
-
-BO_ 315 G_Sensor: 8 XXX
- SG_ Lateral : 48|8@1- (-0.1,0) [0|255] "m/s2" XXX
- SG_ Longitudinal : 56|8@1- (-0.1,0) [0|255] "m/s2" XXX
-
-BO_ 314 Wheel_Speeds: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ FR : 12|13@1+ (0.057,0) [0|255] "kph" XXX
- SG_ RR : 25|13@1+ (0.057,0) [0|255] "kph" XXX
- SG_ FL : 51|13@1+ (0.057,0) [0|255] "kph" XXX
- SG_ RL : 38|13@1+ (0.057,0) [0|255] "kph" XXX
-
-BO_ 281 Steering_Torque: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|3] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Steer_Error_1 : 12|1@0+ (1,0) [0|1] "" XXX
- SG_ Steer_Torque_Sensor : 16|11@1- (-1,0) [0|3] "" XXX
- SG_ Steer_Error_2 : 28|1@1+ (1,0) [0|1] "" XXX
- SG_ Steer_Warning : 29|1@1+ (1,0) [0|1] "" XXX
- SG_ Steering_Angle : 32|16@1- (-0.0217,0) [0|255] "" X
- SG_ Steer_Torque_Output : 48|11@1- (-1,0) [0|31] "" XXX
-
-BO_ 312 Brake_Pressure_L_R: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|31] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|3] "" XXX
- SG_ Brake_1 : 48|8@1+ (1,0) [0|255] "" XXX
- SG_ Brake_2 : 56|8@1+ (1,0) [0|255] "" XXX
-
-BO_ 313 Brake_Pedal: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Brake_Pedal_On : 34|1@1+ (1,0) [0|7] "" XXX
- SG_ Brake_Pedal : 36|12@1+ (1,0) [0|65535] "" XXX
-
-BO_ 290 ES_LKAS: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ SET_1 : 12|1@0+ (1,0) [0|3] "" XXX
- SG_ LKAS_Output : 16|13@1- (-1,0) [0|3] "" XXX
- SG_ LKAS_Request : 29|1@0+ (1,0) [0|3] "" XXX
-
-BO_ 544 ES_Brake: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Brake_Pressure : 16|16@1+ (1,0) [0|255] "" XXX
- SG_ __Status : 36|4@1+ (1,0) [0|63] "" XXX
-
-BO_ 545 ES_Distance: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Signal1 : 12|20@1+ (1,0) [0|15] "" XXX
- SG_ Signal2 : 32|24@1+ (1,0) [0|15] "" XXX
- SG_ Main : 56|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal3 : 57|7@1+ (1,0) [0|1] "" XXX
-
-BO_ 546 ES_Status: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ RPM : 16|12@1+ (1,0) [0|255] "" XXX
- SG_ Cruise_Activated : 29|1@0+ (1,0) [0|3] "" XXX
- SG_ Cruise_Brake : 30|1@1+ (1,0) [0|3] "" XXX
-
-BO_ 576 CruiseControl: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Cruise_On : 40|1@1+ (1,0) [0|3] "" XXX
- SG_ Cruise_Activated : 41|1@1+ (1,0) [0|3] "" XXX
-
-BO_ 552 BSD_RCTA: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ R_ADJACENT : 48|1@1+ (1,0) [0|1] "" XXX
- SG_ L_ADJACENT : 49|1@1+ (1,0) [0|1] "" XXX
- SG_ R_APPROACHING : 58|1@1+ (1,0) [0|1] "" XXX
- SG_ L_APPROACHING : 59|1@1+ (1,0) [0|1] "" XXX
-
-BO_ 912 Dashlights: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ SEATBELT_FL : 48|1@1+ (1,0) [0|1] "" XXX
- SG_ LEFT_BLINKER : 50|1@1+ (1,0) [0|3] "" XXX
- SG_ RIGHT_BLINKER : 51|1@1+ (1,0) [0|1] "" XXX
-
-BO_ 940 BodyInfo: 8 XXX
- SG_ DOOR_OPEN_FL : 32|1@1+ (1,0) [0|255] "" XXX
- SG_ DOOR_OPEN_FR : 33|1@1+ (1,0) [0|3] "" XXX
- SG_ DOOR_OPEN_RL : 34|1@1+ (1,0) [0|1] "" XXX
- SG_ DOOR_OPEN_RR : 35|1@1+ (1,0) [0|1] "" XXX
- SG_ DOOR_OPEN_TRUNK : 36|1@0+ (1,0) [0|1] "" XXX
- SG_ DASH_BTN_LIGHTS : 56|1@0+ (1,0) [0|1] "" XXX
- SG_ Lowbeam : 57|1@1+ (1,0) [0|3] "" XXX
- SG_ Highbeam : 58|1@1+ (1,0) [0|1] "" XXX
- SG_ FOG_LIGHTS2 : 60|1@1+ (1,0) [0|1] "" XXX
- SG_ WIPERS : 62|1@0+ (1,0) [0|1] "" XXX
-
-BO_ 801 ES_DashStatus: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|7] "" XXX
- SG_ Cruise_Distance : 28|3@1+ (1,0) [0|3] "" XXX
- SG_ Cruise_Disengaged : 35|1@1+ (1,0) [0|3] "" XXX
- SG_ Cruise_Activated : 36|1@1+ (1,0) [0|3] "" XXX
- SG_ Cruise_Set_Speed : 40|8@1+ (1,0) [0|255] "" XXX
- SG_ Cruise_Fault : 48|1@1+ (1,0) [0|1] "" XXX
- SG_ Brake_Pedal : 51|1@1+ (1,0) [0|3] "" XXX
- SG_ Car_Follow : 52|1@1+ (1,0) [0|3] "" XXX
- SG_ Far_Distance : 56|4@1+ (1,0) [0|15] "" XXX
- SG_ Cruise_State : 60|4@1+ (1,0) [0|15] "" XXX
-
-BO_ 802 ES_LKAS_State: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Keep_Hands_On_Wheel : 12|1@1+ (1,0) [0|1] "" XXX
- SG_ Empty_Box : 13|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal1 : 14|3@1+ (1,0) [0|7] "" XXX
- SG_ LKAS_ACTIVE : 17|1@1+ (1,0) [0|3] "" XXX
- SG_ Signal2 : 18|5@1+ (1,0) [0|7] "" XXX
- SG_ Backward_Speed_Limit_Menu : 23|1@1+ (1,0) [0|1] "" XXX
- SG_ LKAS_ENABLE_3 : 24|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal3 : 25|1@1+ (1,0) [0|1] "" XXX
- SG_ LKAS_ENABLE_2 : 26|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal4 : 27|1@1+ (1,0) [0|1] "" XXX
- SG_ LKAS_Left_Line_Visible : 28|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal6 : 29|1@1+ (1,0) [0|1] "" XXX
- SG_ LKAS_Right_Line_Visible : 30|1@1+ (1,0) [0|1] "" XXX
- SG_ Signal7 : 31|1@1+ (1,0) [0|1] "" XXX
- SG_ FCW_Cont_Beep : 32|1@1+ (1,0) [0|1] "" XXX
- SG_ FCW_Repeated_Beep : 33|1@1+ (1,0) [0|1] "" XXX
- SG_ Throttle_Management_Activated : 34|1@1+ (1,0) [0|1] "" XXX
- SG_ Traffic_light_Ahead : 35|1@1+ (1,0) [0|1] "" XXX
- SG_ Right_Depart : 36|1@1+ (1,0) [0|3] "" XXX
- SG_ Signal5 : 37|27@1+ (1,0) [0|1] "" XXX
-
-BO_ 1677 Dash_State: 8 XXX
- SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
- SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
- SG_ Units : 29|3@1+ (1,0) [0|7] "" XXX
-
-CM_ SG_ 801 Cruise_State "0 = Normal, 3 = Hold";
-CM_ SG_ 802 Traffic_light_Ahead "Crosstrek 2018 = car in front has moved";
-CM_ SG_ 940 FOG_LIGHTS2 "yellow fog light in the dash";
-CM_ SG_ 940 Highbeam "01 = low beam, 11 = high beam";
-CM_ SG_ 1677 Units "1 = imperial, 6 = metric";
-VAL_ 72 Gear 2 "N" 3 "R" 4 "P" 121 "D" 137 "1" 145 "2" 153 "3" 161 "4" 169 "5" 177 "6";
diff --git a/opendbc/subaru_global_2017_generated.dbc b/opendbc/subaru_global_2017_generated.dbc
new file mode 100644
index 00000000..39063a30
--- /dev/null
+++ b/opendbc/subaru_global_2017_generated.dbc
@@ -0,0 +1,306 @@
+CM_ "AUTOGENERATED FILE, DO NOT EDIT"
+
+
+CM_ "Imported file _subaru_global.dbc starts here"
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX X
+
+
+BO_ 2 Steering: 8 XXX
+ SG_ Steering_Angle : 7|16@0- (0.1,0) [0|65535] "" XXX
+ SG_ Counter : 25|3@1+ (1,0) [0|7] "" XXX
+ SG_ CHECKSUM : 32|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 64 Throttle: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Engine_RPM : 16|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Cruise : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Combo : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Signal1 : 56|4@1+ (1,0) [0|15] "" XXX
+ SG_ Off_Accel : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 316 Brake_Status: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|46@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Brake : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 59|3@1+ (1,0) [0|1] "" XXX
+ SG_ Brake : 62|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 63|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 326 Cruise_Buttons: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|30@1+ (1,0) [0|1073741823] "" XXX
+ SG_ Main : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Set : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ Resume : 44|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 45|19@1+ (1,0) [0|524287] "" XXX
+
+BO_ 315 G_Sensor: 8 XXX
+ SG_ Lateral : 48|8@1- (-0.1,0) [0|255] "m/s2" XXX
+ SG_ Longitudinal : 56|8@1- (-0.1,0) [0|255] "m/s2" XXX
+
+BO_ 314 Wheel_Speeds: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ FR : 12|13@1+ (0.057,0) [0|255] "kph" XXX
+ SG_ RR : 25|13@1+ (0.057,0) [0|255] "kph" XXX
+ SG_ FL : 51|13@1+ (0.057,0) [0|255] "kph" XXX
+ SG_ RL : 38|13@1+ (0.057,0) [0|255] "kph" XXX
+
+BO_ 280 STOP_START: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ State : 63|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 281 Steering_Torque: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Steer_Error_1 : 12|1@0+ (1,0) [0|1] "" XXX
+ SG_ Steer_Torque_Sensor : 16|11@1- (-1,0) [-1000|1000] "" XXX
+ SG_ Steer_Error_2 : 28|1@1+ (1,0) [0|1] "" XXX
+ SG_ Steer_Warning : 29|1@1+ (1,0) [0|1] "" XXX
+ SG_ Steering_Angle : 32|16@1- (-0.0217,0) [-600|600] "" X
+ SG_ Steer_Torque_Output : 48|11@1- (-1,0) [-1000|1000] "" XXX
+
+BO_ 312 Brake_Pressure_L_R: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Brake_1 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_2 : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 313 Brake_Pedal: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Speed : 16|12@1+ (0.05625,0) [0|255] "kph" XXX
+ SG_ Signal2 : 28|6@1+ (1,0) [0|63] "" XXX
+ SG_ Brake_Lights : 34|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 35|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal : 36|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Signal4 : 48|16@1+ (1,0) [0|65535] "" XXX
+
+BO_ 290 ES_LKAS: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ SET_1 : 12|1@0+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Output : 16|13@1- (-1,0) [-8191|8191] "" XXX
+ SG_ LKAS_Request : 29|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 544 ES_Brake: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Brake_Pressure : 16|16@1+ (1,0) [0|65535] "" XXX
+ SG_ Signal2 : 32|4@1+ (1,0) [0|15] "" XXX
+ SG_ Cruise_Brake_Lights : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Brake_Fault : 37|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Brake_Active : 38|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 39|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 40|24@1+ (1,0) [0|16777215] "" XXX
+
+BO_ 577 Cruise_Status: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Cruise_On : 54|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 55|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Active : 57|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 552 BSD_RCTA: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ R_ADJACENT : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_ADJACENT : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_APPROACHING : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_APPROACHING : 59|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 912 Dashlights: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ ICY_ROAD : 32|2@1+ (1,0) [0|3] "" XXX
+ SG_ SEATBELT_FL : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_BLINKER : 50|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_BLINKER : 51|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 940 BodyInfo: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ DOOR_OPEN_FL : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_FR : 33|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RL : 34|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RR : 35|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_TRUNK : 36|1@0+ (1,0) [0|1] "" XXX
+ SG_ DASH_BTN_LIGHTS : 56|1@0+ (1,0) [0|1] "" XXX
+ SG_ Lowbeam : 57|1@1+ (1,0) [0|1] "" XXX
+ SG_ Highbeam : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ FOG_LIGHTS2 : 60|1@1+ (1,0) [0|1] "" XXX
+ SG_ WIPERS : 62|1@0+ (1,0) [0|1] "" XXX
+ SG_ BRAKE : 54|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 801 ES_DashStatus: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ PCB_Off : 12|1@1+ (1,0) [0|1] "" XXX
+ SG_ LDW_Off : 13|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal1 : 14|10@1+ (1,0) [0|1023] "" XXX
+ SG_ Cruise_Soft_Disable : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 25|3@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Distance : 28|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal3 : 31|1@1+ (1,0) [0|1] "" XXX
+ SG_ Conventional_Cruise : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal4 : 33|2@1+ (1,0) [0|3] "" XXX
+ SG_ Cruise_Disengaged : 35|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal5 : 37|3@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Set_Speed : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ Cruise_Fault : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_On : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal6 : 50|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Lights : 51|1@1+ (1,0) [0|1] "" XXX
+ SG_ Car_Follow : 52|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal7 : 53|3@1+ (1,0) [0|1] "" XXX
+ SG_ Far_Distance : 56|4@1+ (1,0) [0|15] "" XXX
+ SG_ Cruise_State : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 802 ES_LKAS_State: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Keep_Hands_On_Wheel : 12|1@1+ (1,0) [0|1] "" XXX
+ SG_ Empty_Box : 13|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal1 : 14|3@1+ (1,0) [0|7] "" XXX
+ SG_ LKAS_ACTIVE : 17|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 18|5@1+ (1,0) [0|31] "" XXX
+ SG_ Backward_Speed_Limit_Menu : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_ENABLE_3 : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Left_Line_Light_Blink : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_ENABLE_2 : 26|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Right_Line_Light_Blink : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Left_Line_Visible : 28|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Left_Line_Green : 29|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Right_Line_Visible : 30|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Right_Line_Green : 31|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Alert : 32|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal3 : 36|28@1+ (1,0) [0|1] "" XXX
+
+BO_ 722 AC_State: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ AC_Mode : 37|3@1+ (1,0) [0|1] "" XXX
+ SG_ AC_ON : 24|2@1+ (1,0) [0|1] "" XXX
+
+BO_ 1677 Dash_State: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Units : 29|3@1+ (1,0) [0|7] "" XXX
+
+CM_ SG_ 64 Throttle_Combo "Throttle Cruise + Pedal";
+CM_ SG_ 313 Brake_Lights "Driver or Cruise Brake on";
+CM_ SG_ 544 Cruise_Brake_Lights "1 = switch on brake lights";
+CM_ SG_ 801 PCB_Off "Pre-Collision Braking off";
+CM_ SG_ 801 Brake_Lights "Driver or Cruise brake on";
+CM_ SG_ 801 Cruise_State "0 = Normal, 1 = Hold+User Brake, 2 = Ready, 3 = Hold";
+CM_ SG_ 801 Far_Distance "1=0-5m, 2=5-10m, 3=10-15m, 4=15-20m, 5=20-25m, 6=25-30m, 7=30-35m, 8=35-40m, 9=40-45m, 10=45-50m, 11=50-55m, 12=55-60m, 13=60-65m, 14=65-70m, 15=75m+";
+CM_ SG_ 801 Cruise_Soft_Disable "Eyesight soft disable (eg direct sunlight)";
+CM_ SG_ 802 LKAS_Alert "1 = FCW_Cont_Beep, 2 = FCW_Repeated_Beep, 3 = Throttle_Management_Activated_Warning, 4 = Throttle_Management_Activated_Alert, 8 = Traffic_Light_Ahead, 9 = Apply_Brake_to_Hold Position, 11 = LDW_Right, 12 = LDW_Left, 13 = Stay_Alert, 14 = Lead_Vehicle_Start_Alert";
+CM_ SG_ 912 ICY_ROAD "1 = DASHLIGHT ON, 2 = WARNING, 3 = OFF";
+CM_ SG_ 940 Highbeam "01 = low beam, 11 = high beam";
+CM_ SG_ 940 FOG_LIGHTS2 "yellow fog light in the dash";
+CM_ SG_ 1677 Units "AU/EU: 1 = imperial, 3 = metric US: 3 = imperial, 4 = metric";
+
+CM_ "subaru_global_2017.dbc starts here"
+
+
+BO_ 72 Transmission: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Gear : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ RPM : 40|16@1+ (1,0) [0|65535] "" XXX
+
+BO_ 73 CVT: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ CVT_Gear : 24|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 545 ES_Distance: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|3@1+ (1,0) [0|7] "" XXX
+ SG_ Cruise_Fault : 15|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Throttle : 16|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX
+ SG_ Car_Follow : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 33|3@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Brake_Active : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ Distance_Swap : 37|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_EPB : 38|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal4 : 39|1@0+ (1,0) [0|1] "" XXX
+ SG_ Close_Distance : 40|8@1+ (1,0) [0|1] "" XXX
+ SG_ Signal5 : 48|8@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Cancel : 56|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Set : 57|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Resume : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal6 : 59|5@1+ (1,0) [0|1] "" XXX
+
+BO_ 546 ES_Status: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|3@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Fault : 15|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_RPM : 16|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Signal2 : 28|1@0+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 29|1@0+ (1,0) [0|1] "" XXX
+ SG_ Brake_Lights : 30|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Hold : 31|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 32|32@1+ (1,0) [0|1] "" XXX
+
+BO_ 576 CruiseControl: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Signal1 : 12|28@1+ (1,0) [0|268435455] "" XXX
+ SG_ Cruise_On : 40|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 41|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 42|22@1+ (1,0) [0|4194303] "" XXX
+
+CM_ SG_ 545 Cruise_Throttle "RPM-like output signal";
+CM_ SG_ 545 Cruise_EPB "1 = Electric Parking Brake set";
+CM_ SG_ 545 Distance_Swap "Switch from Close to Far distance";
+CM_ SG_ 546 Cruise_RPM "ES RPM output for ECM and TCM";
+CM_ SG_ 546 Signal3 "0 when cruise_activated = 1";
+VAL_ 72 Gear 2 "N" 3 "R" 4 "P" 121 "D" 137 "1" 145 "2" 153 "3" 161 "4" 169 "5" 177 "6";
diff --git a/opendbc/subaru_outback_2015_generated.dbc b/opendbc/subaru_outback_2015_generated.dbc
new file mode 100644
index 00000000..62e3e848
--- /dev/null
+++ b/opendbc/subaru_outback_2015_generated.dbc
@@ -0,0 +1,273 @@
+CM_ "AUTOGENERATED FILE, DO NOT EDIT"
+
+
+CM_ "Imported file _subaru_preglobal_2015.dbc starts here"
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX X
+
+
+BO_ 2 Steering: 8 XXX
+ SG_ Steering_Angle : 7|16@0- (0.1,0) [-500|500] "degree" XXX
+ SG_ Counter : 27|3@0+ (1,0) [0|7] "" XXX
+ SG_ Checksum : 39|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 208 G_Sensor: 8 XXX
+ SG_ Steering_Angle : 0|16@1- (-0.1,0) [-500|500] "" XXX
+ SG_ Lateral : 16|16@1- (-0.0035,1) [-255|255] "" XXX
+ SG_ Longitudinal : 48|16@1- (-0.00035,0) [-255|255] "" XXX
+
+BO_ 209 Brake_Pedal: 8 XXX
+ SG_ Speed : 0|16@1+ (0.05625,0) [0|255] "KPH" XXX
+ SG_ Brake_Pedal : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 210 Brake_2: 8 XXX
+ SG_ Brake_Light : 35|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Related : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ Right_Brake : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Left_Brake : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 211 Brake_Type: 8 XXX
+ SG_ Brake_Light : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Speed_Counter : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Cruise_On : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal_On : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 48|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 212 Wheel_Speeds: 8 XXX
+ SG_ FL : 0|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ FR : 16|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ RL : 32|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ RR : 48|16@1+ (0.0592,0) [0|255] "KPH" XXX
+
+BO_ 320 Throttle: 8 XXX
+ SG_ Throttle_Pedal : 0|8@1+ (0.392157,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Not_Full_Throttle : 14|1@1+ (1,0) [0|1] "" XXX
+ SG_ Engine_RPM : 16|14@1+ (1,0) [0|32767] "" XXX
+ SG_ Off_Throttle : 30|1@1+ (1,0) [0|1] "" XXX
+ SG_ Throttle_Cruise : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Combo : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Body : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Off_Throttle_2 : 56|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 321 Engine: 8 XXX
+ SG_ Engine_Torque : 0|15@1+ (1,0) [0|255] "" XXX
+ SG_ Engine_Stop : 15|1@1+ (1,0) [0|1] "" XXX
+ SG_ Wheel_Torque : 16|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Engine_RPM : 32|12@1+ (1,0) [0|8191] "" XXX
+
+BO_ 324 CruiseControl: 8 XXX
+ SG_ OnOffButton : 2|1@1+ (1,0) [0|1] "" XXX
+ SG_ SET_BUTTON : 3|1@1+ (1,0) [0|1] "" XXX
+ SG_ RES_BUTTON : 4|1@1+ (1,0) [0|1] "" XXX
+ SG_ Button : 13|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_On : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal_On : 51|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 328 Transmission: 8 XXX
+ SG_ Manual_Gear : 4|4@1+ (1,0) [0|15] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Transmission_Engine : 16|15@1+ (1,0) [0|65535] "" XXX
+ SG_ Gear : 48|4@1+ (1,0) [0|15] "" XXX
+ SG_ Gear_2 : 52|4@1+ (1,0) [0|15] "" XXX
+ SG_ Paddle_Shift : 60|2@1+ (1,0) [0|3] "" XXX
+
+BO_ 329 CVT_Ratio: 8 XXX
+
+BO_ 336 Brake_Pressure: 8 XXX
+ SG_ Brake_Pressure_Right : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Pressure_Left : 8|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 338 Stalk: 8 XXX
+ SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Brake_Light : 52|1@1+ (1,0) [0|1] "" XXX
+ SG_ Runlights : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ Headlights : 59|1@1+ (1,0) [0|1] "" XXX
+ SG_ Highbeam : 60|1@1+ (1,0) [0|1] "" XXX
+ SG_ Wiper : 62|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 352 ES_Brake: 8 XXX
+ SG_ Brake_Pressure : 0|16@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Light : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Error : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_On : 22|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 353 ES_CruiseThrottle: 8 XXX
+ SG_ Throttle_Cruise : 0|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Cruise_Activated : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 17|3@1+ (1,0) [0|7] "" XXX
+ SG_ Brake_On : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ DistanceSwap : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Standstill : 22|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ CloseDistance : 24|8@1+ (0.0196,0) [0|255] "m" XXX
+ SG_ Signal4 : 32|9@1+ (1,0) [0|255] "" XXX
+ SG_ Standstill_2 : 41|1@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Error : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal5 : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 44|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal6 : 47|1@1+ (1,0) [0|1] "" XXX
+ SG_ Button : 48|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal7 : 51|5@1+ (1,0) [0|31] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 354 ES_RPM: 8 XXX
+ SG_ Brake : 8|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 9|1@1+ (1,0) [0|1] "" XXX
+ SG_ RPM : 16|16@1+ (1,0) [0|65535] "" XXX
+ SG_ Checksum : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
+
+BO_ 356 ES_LKAS: 8 XXX
+ SG_ Counter : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ LKAS_Command : 8|13@1- (-1,0) [-4096|4096] "" XXX
+ SG_ LKAS_Active : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 359 ES_LDW: 8 XXX
+ SG_ All_depart_2015 : 0|1@1+ (1,0) [0|1] "" XXX
+ SG_ Right_Line_2017 : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Left_Line_2017 : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1All_Depart : 28|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig2All_Depart : 31|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Inactive_2017 : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Active : 37|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1Right_Depart : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1Right_Depart_Front : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig2Right_Depart : 50|1@1+ (1,0) [0|1] "" XXX
+ SG_ Left_Depart_Front : 51|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig3All_Depart : 52|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 604 BSD_RCTA: 8 XXX
+ SG_ Counter : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ State : 5|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_ADJACENT : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_ADJACENT : 33|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_APPROACHING : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_APPROACHING : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_RCTA : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_RCTA : 47|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 642 Dashlights: 8 XXX
+ SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ SEATBELT_FL : 40|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_BLINKER : 44|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_BLINKER : 45|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 880 Steering_Torque_2: 8 XXX
+ SG_ Steering_Voltage_Flat : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Steer_Torque_Sensor : 29|11@1- (-1,0) [-1000|1000] "" XXX
+ SG_ Counter : 40|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 884 BodyInfo: 8 XXX
+ SG_ DOOR_OPEN_FR : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_FL : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RL : 26|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RR : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_Hatch : 28|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 864 Engine_Temp: 8 XXX
+ SG_ Oil_Temp : 16|8@1+ (1,-40) [0|255] "" XXX
+ SG_ Coolant_Temp : 24|8@1+ (1,-40) [0|255] "" XXX
+ SG_ Cruise_Activated : 45|1@1+ (1,0) [0|1] "" XXX
+ SG_ Saved_Speed : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 866 Fuel: 8 XXX
+
+BO_ 1745 Dash_State: 8 XXX
+ SG_ Units : 15|1@1+ (1,0) [0|1] "" XXX
+
+CM_ SG_ 320 Off_Throttle_2 "Less sensitive";
+CM_ SG_ 320 Throttle_Body "Throttle related";
+CM_ SG_ 328 Gear "15 = P, 14 = R, 0 = N, 1-6=gear";
+CM_ SG_ 328 Gear_2 "15 = P, 14 = R, 0 = N, 1-6=gear";
+CM_ SG_ 353 Button "1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 resume deep";
+CM_ SG_ 354 RPM "20hz version of Transmission_Engine under Transmission";
+CM_ SG_ 359 Sig1Right_Depart "right depart, hill steep and seatbelt disengage";
+CM_ SG_ 359 LKAS_Inactive_2017 "1 when not steering, 0 when lkas steering";
+CM_ SG_ 359 Sig1Right_Depart_Front "object in front, right depart, hill steep and seatbelt disengage alert ";
+CM_ SG_ 359 Left_Depart_Front "warning after acceleration into car in front and left depart";
+CM_ SG_ 359 Sig1All_Depart "Left and right depart";
+CM_ SG_ 359 Sig2All_Depart "Left and right depart";
+CM_ SG_ 359 All_depart_2015 "always 1 on 2017";
+CM_ SG_ 604 R_APPROACHING "Faster car approaching in far right lane";
+CM_ SG_ 604 L_APPROACHING "Faster car approaching in far left lane";
+CM_ SG_ 604 R_RCTA "Rear cross traffic alert, only when in R gear";
+CM_ SG_ 604 L_RCTA "Rear cross traffic alert, only when in R gear";
+CM_ SG_ 642 Counter "Affected by signals";
+CM_ SG_ 642 SEATBELT_FL "Driver seatbelt";
+CM_ SG_ 880 Steering_Voltage_Flat "receives later than 371";
+
+VAL_ 328 Gear 0 "N" 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 14 "R" 15 "P";
+VAL_ 1745 Units 0 "Metric" 1 "Imperial";
+
+CM_ "subaru_outback_2015.dbc starts here"
+
+
+BO_ 358 ES_DashStatus: 8 XXX
+ SG_ Not_Ready_Startup : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ Seatbelt_Disengage : 12|2@1+ (1,0) [0|3] "" XXX
+ SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX
+ SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 17|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal1 : 18|1@1+ (1,0) [0|1] "" XXX
+ SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|1] "" XXX
+ SG_ Driver_Input : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ Distance_Bars : 21|3@1+ (1,0) [0|7] "" XXX
+ SG_ Cruise_Set_Speed : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ ES_Error : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_On_2 : 34|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 37|3@1+ (1,0) [0|7] "" XXX
+ SG_ Steep_Hill_Disengage : 44|1@1+ (1,0) [0|3] "" XXX
+ SG_ Lead_Car : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ Obstacle_Distance : 48|4@1+ (5,0) [0|15] "m" XXX
+
+BO_ 881 Steering_Torque: 8 XXX
+ SG_ Steering_Motor_Flat : 0|10@1+ (32,0) [0|1000] "" XXX
+ SG_ Steer_Torque_Output : 16|11@1- (-32,0) [-1000|1000] "" XXX
+ SG_ LKA_Lockout : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ Steer_Torque_Sensor : 29|11@1- (1,0) [-1000|1000] "" XXX
+ SG_ Steering_Angle : 40|16@1- (-0.033,0) [-600|600] "" XXX
+
+CM_ SG_ 358 Disengage_Alert "seatbelt and steep hill disengage";
+CM_ SG_ 358 ES_Error "No engagement until restart";
+CM_ SG_ 358 Lead_Car "front car detected";
diff --git a/opendbc/subaru_outback_2019_generated.dbc b/opendbc/subaru_outback_2019_generated.dbc
new file mode 100644
index 00000000..0d5c14bc
--- /dev/null
+++ b/opendbc/subaru_outback_2019_generated.dbc
@@ -0,0 +1,273 @@
+CM_ "AUTOGENERATED FILE, DO NOT EDIT"
+
+
+CM_ "Imported file _subaru_preglobal_2015.dbc starts here"
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX X
+
+
+BO_ 2 Steering: 8 XXX
+ SG_ Steering_Angle : 7|16@0- (0.1,0) [-500|500] "degree" XXX
+ SG_ Counter : 27|3@0+ (1,0) [0|7] "" XXX
+ SG_ Checksum : 39|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 208 G_Sensor: 8 XXX
+ SG_ Steering_Angle : 0|16@1- (-0.1,0) [-500|500] "" XXX
+ SG_ Lateral : 16|16@1- (-0.0035,1) [-255|255] "" XXX
+ SG_ Longitudinal : 48|16@1- (-0.00035,0) [-255|255] "" XXX
+
+BO_ 209 Brake_Pedal: 8 XXX
+ SG_ Speed : 0|16@1+ (0.05625,0) [0|255] "KPH" XXX
+ SG_ Brake_Pedal : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 210 Brake_2: 8 XXX
+ SG_ Brake_Light : 35|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Related : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ Right_Brake : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Left_Brake : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 211 Brake_Type: 8 XXX
+ SG_ Brake_Light : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Speed_Counter : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Cruise_On : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal_On : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 48|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 212 Wheel_Speeds: 8 XXX
+ SG_ FL : 0|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ FR : 16|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ RL : 32|16@1+ (0.0592,0) [0|255] "KPH" XXX
+ SG_ RR : 48|16@1+ (0.0592,0) [0|255] "KPH" XXX
+
+BO_ 320 Throttle: 8 XXX
+ SG_ Throttle_Pedal : 0|8@1+ (0.392157,0) [0|255] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Not_Full_Throttle : 14|1@1+ (1,0) [0|1] "" XXX
+ SG_ Engine_RPM : 16|14@1+ (1,0) [0|32767] "" XXX
+ SG_ Off_Throttle : 30|1@1+ (1,0) [0|1] "" XXX
+ SG_ Throttle_Cruise : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Combo : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ Throttle_Body : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ Off_Throttle_2 : 56|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 321 Engine: 8 XXX
+ SG_ Engine_Torque : 0|15@1+ (1,0) [0|255] "" XXX
+ SG_ Engine_Stop : 15|1@1+ (1,0) [0|1] "" XXX
+ SG_ Wheel_Torque : 16|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Engine_RPM : 32|12@1+ (1,0) [0|8191] "" XXX
+
+BO_ 324 CruiseControl: 8 XXX
+ SG_ OnOffButton : 2|1@1+ (1,0) [0|1] "" XXX
+ SG_ SET_BUTTON : 3|1@1+ (1,0) [0|1] "" XXX
+ SG_ RES_BUTTON : 4|1@1+ (1,0) [0|1] "" XXX
+ SG_ Button : 13|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_On : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_Pedal_On : 51|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 328 Transmission: 8 XXX
+ SG_ Manual_Gear : 4|4@1+ (1,0) [0|15] "" XXX
+ SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
+ SG_ Transmission_Engine : 16|15@1+ (1,0) [0|65535] "" XXX
+ SG_ Gear : 48|4@1+ (1,0) [0|15] "" XXX
+ SG_ Gear_2 : 52|4@1+ (1,0) [0|15] "" XXX
+ SG_ Paddle_Shift : 60|2@1+ (1,0) [0|3] "" XXX
+
+BO_ 329 CVT_Ratio: 8 XXX
+
+BO_ 336 Brake_Pressure: 8 XXX
+ SG_ Brake_Pressure_Right : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Pressure_Left : 8|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 338 Stalk: 8 XXX
+ SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Brake_Light : 52|1@1+ (1,0) [0|1] "" XXX
+ SG_ Runlights : 58|1@1+ (1,0) [0|1] "" XXX
+ SG_ Headlights : 59|1@1+ (1,0) [0|1] "" XXX
+ SG_ Highbeam : 60|1@1+ (1,0) [0|1] "" XXX
+ SG_ Wiper : 62|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 352 ES_Brake: 8 XXX
+ SG_ Brake_Pressure : 0|16@1+ (1,0) [0|255] "" XXX
+ SG_ Brake_Light : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Error : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Brake_On : 22|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 353 ES_CruiseThrottle: 8 XXX
+ SG_ Throttle_Cruise : 0|12@1+ (1,0) [0|4095] "" XXX
+ SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ Cruise_Activated : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal2 : 17|3@1+ (1,0) [0|7] "" XXX
+ SG_ Brake_On : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ DistanceSwap : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ Standstill : 22|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal3 : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ CloseDistance : 24|8@1+ (0.0196,0) [0|255] "m" XXX
+ SG_ Signal4 : 32|9@1+ (1,0) [0|255] "" XXX
+ SG_ Standstill_2 : 41|1@1+ (1,0) [0|1] "" XXX
+ SG_ ES_Error : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal5 : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 44|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal6 : 47|1@1+ (1,0) [0|1] "" XXX
+ SG_ Button : 48|3@1+ (1,0) [0|7] "" XXX
+ SG_ Signal7 : 51|5@1+ (1,0) [0|31] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 354 ES_RPM: 8 XXX
+ SG_ Brake : 8|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 9|1@1+ (1,0) [0|1] "" XXX
+ SG_ RPM : 16|16@1+ (1,0) [0|65535] "" XXX
+ SG_ Checksum : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
+
+BO_ 356 ES_LKAS: 8 XXX
+ SG_ Counter : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ LKAS_Command : 8|13@1- (-1,0) [-4096|4096] "" XXX
+ SG_ LKAS_Active : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 359 ES_LDW: 8 XXX
+ SG_ All_depart_2015 : 0|1@1+ (1,0) [0|1] "" XXX
+ SG_ Right_Line_2017 : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ Left_Line_2017 : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1All_Depart : 28|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig2All_Depart : 31|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Inactive_2017 : 36|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_Active : 37|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1Right_Depart : 48|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig1Right_Depart_Front : 49|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig2Right_Depart : 50|1@1+ (1,0) [0|1] "" XXX
+ SG_ Left_Depart_Front : 51|1@1+ (1,0) [0|1] "" XXX
+ SG_ Sig3All_Depart : 52|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 604 BSD_RCTA: 8 XXX
+ SG_ Counter : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ State : 5|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_ADJACENT : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_ADJACENT : 33|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_APPROACHING : 42|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_APPROACHING : 43|1@1+ (1,0) [0|1] "" XXX
+ SG_ R_RCTA : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ L_RCTA : 47|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 642 Dashlights: 8 XXX
+ SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
+ SG_ SEATBELT_FL : 40|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_BLINKER : 44|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_BLINKER : 45|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 880 Steering_Torque_2: 8 XXX
+ SG_ Steering_Voltage_Flat : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ Steer_Torque_Sensor : 29|11@1- (-1,0) [-1000|1000] "" XXX
+ SG_ Counter : 40|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 884 BodyInfo: 8 XXX
+ SG_ DOOR_OPEN_FR : 24|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_FL : 25|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RL : 26|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_RR : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ DOOR_OPEN_Hatch : 28|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 864 Engine_Temp: 8 XXX
+ SG_ Oil_Temp : 16|8@1+ (1,-40) [0|255] "" XXX
+ SG_ Coolant_Temp : 24|8@1+ (1,-40) [0|255] "" XXX
+ SG_ Cruise_Activated : 45|1@1+ (1,0) [0|1] "" XXX
+ SG_ Saved_Speed : 56|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 866 Fuel: 8 XXX
+
+BO_ 1745 Dash_State: 8 XXX
+ SG_ Units : 15|1@1+ (1,0) [0|1] "" XXX
+
+CM_ SG_ 320 Off_Throttle_2 "Less sensitive";
+CM_ SG_ 320 Throttle_Body "Throttle related";
+CM_ SG_ 328 Gear "15 = P, 14 = R, 0 = N, 1-6=gear";
+CM_ SG_ 328 Gear_2 "15 = P, 14 = R, 0 = N, 1-6=gear";
+CM_ SG_ 353 Button "1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 resume deep";
+CM_ SG_ 354 RPM "20hz version of Transmission_Engine under Transmission";
+CM_ SG_ 359 Sig1Right_Depart "right depart, hill steep and seatbelt disengage";
+CM_ SG_ 359 LKAS_Inactive_2017 "1 when not steering, 0 when lkas steering";
+CM_ SG_ 359 Sig1Right_Depart_Front "object in front, right depart, hill steep and seatbelt disengage alert ";
+CM_ SG_ 359 Left_Depart_Front "warning after acceleration into car in front and left depart";
+CM_ SG_ 359 Sig1All_Depart "Left and right depart";
+CM_ SG_ 359 Sig2All_Depart "Left and right depart";
+CM_ SG_ 359 All_depart_2015 "always 1 on 2017";
+CM_ SG_ 604 R_APPROACHING "Faster car approaching in far right lane";
+CM_ SG_ 604 L_APPROACHING "Faster car approaching in far left lane";
+CM_ SG_ 604 R_RCTA "Rear cross traffic alert, only when in R gear";
+CM_ SG_ 604 L_RCTA "Rear cross traffic alert, only when in R gear";
+CM_ SG_ 642 Counter "Affected by signals";
+CM_ SG_ 642 SEATBELT_FL "Driver seatbelt";
+CM_ SG_ 880 Steering_Voltage_Flat "receives later than 371";
+
+VAL_ 328 Gear 0 "N" 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 14 "R" 15 "P";
+VAL_ 1745 Units 0 "Metric" 1 "Imperial";
+
+CM_ "subaru_outback_2019.dbc starts here"
+
+
+BO_ 358 ES_DashStatus: 8 XXX
+ SG_ Not_Ready_Startup : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ Seatbelt_Disengage : 12|2@1+ (1,0) [0|3] "" XXX
+ SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX
+ SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_Activated : 17|1@1+ (1,0) [0|1] "" XXX
+ SG_ Signal1 : 18|1@1+ (1,0) [0|1] "" XXX
+ SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|1] "" XXX
+ SG_ Driver_Input : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ Distance_Bars : 21|3@1+ (1,0) [0|7] "" XXX
+ SG_ Cruise_Set_Speed : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ ES_Error : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ Cruise_On_2 : 34|1@1+ (1,0) [0|1] "" XXX
+ SG_ Counter : 37|3@1+ (1,0) [0|7] "" XXX
+ SG_ Steep_Hill_Disengage : 44|1@1+ (1,0) [0|3] "" XXX
+ SG_ Lead_Car : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ Obstacle_Distance : 48|4@1+ (5,0) [0|15] "m" XXX
+
+BO_ 881 Steering_Torque: 8 XXX
+ SG_ Steering_Motor_Flat : 0|10@1+ (32,0) [0|1000] "" XXX
+ SG_ Steer_Torque_Output : 16|11@1- (-32,0) [-1000|1000] "" XXX
+ SG_ LKA_Lockout : 27|1@1+ (1,0) [0|1] "" XXX
+ SG_ Steer_Torque_Sensor : 29|11@1- (-1,0) [-1000|1000] "" XXX
+ SG_ Steering_Angle : 40|16@1- (-0.033,0) [-600|600] "" XXX
+
+CM_ SG_ 358 Disengage_Alert "seatbelt and steep hill disengage";
+CM_ SG_ 358 ES_Error "No engagement until restart";
+CM_ SG_ 358 Lead_Car "front car detected";
diff --git a/panda/board/board.h b/panda/board/board.h
index 28516299..84fca546 100644
--- a/panda/board/board.h
+++ b/panda/board/board.h
@@ -23,7 +23,7 @@ void detect_board_type(void) {
// SPI lines floating: white (TODO: is this reliable? Not really, we have to enable ESP/GPS to be able to detect this on the UART)
set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 1);
- if(!detect_with_pull(GPIOB, 1, PULL_UP)){
+ if(!detect_with_pull(GPIOB, 1, PULL_UP) && detect_with_pull(GPIOB, 15, PULL_UP)){
hw_type = HW_TYPE_DOS;
current_board = &board_dos;
} else if((detect_with_pull(GPIOA, 4, PULL_DOWN)) || (detect_with_pull(GPIOA, 5, PULL_DOWN)) || (detect_with_pull(GPIOA, 6, PULL_DOWN)) || (detect_with_pull(GPIOA, 7, PULL_DOWN))){
diff --git a/panda/board/get_sdk.sh b/panda/board/get_sdk.sh
index 3a009a5a..84964244 100755
--- a/panda/board/get_sdk.sh
+++ b/panda/board/get_sdk.sh
@@ -1,3 +1,3 @@
#!/bin/bash
sudo apt-get install gcc-arm-none-eabi python-pip
-sudo pip install libusb1 pycrypto requests
+sudo pip install libusb1 pycryptodome requests
diff --git a/panda/board/get_sdk_mac.sh b/panda/board/get_sdk_mac.sh
index 24b93b54..2daba2a1 100755
--- a/panda/board/get_sdk_mac.sh
+++ b/panda/board/get_sdk_mac.sh
@@ -4,4 +4,4 @@ sudo easy_install pip
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew tap ArmMbed/homebrew-formulae
brew install python dfu-util arm-none-eabi-gcc
-pip install --user libusb1 pycrypto requests
+pip install --user libusb1 pycryptodome requests
diff --git a/panda/board/safety.h b/panda/board/safety.h
index 32d9d3f5..108832dc 100644
--- a/panda/board/safety.h
+++ b/panda/board/safety.h
@@ -38,6 +38,7 @@
#define SAFETY_VOLKSWAGEN_PQ 21U
#define SAFETY_SUBARU_LEGACY 22U
#define SAFETY_HYUNDAI_LEGACY 23U
+#define SAFETY_HYUNDAI_COMMUNITY 24U
uint16_t current_safety_mode = SAFETY_SILENT;
const safety_hooks *current_hooks = &nooutput_hooks;
diff --git a/panda/board/safety/safety_nissan.h b/panda/board/safety/safety_nissan.h
index 0dec23e8..d1ca0c83 100644
--- a/panda/board/safety/safety_nissan.h
+++ b/panda/board/safety/safety_nissan.h
@@ -56,7 +56,7 @@ static int nissan_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
// X-Trail 0x15c, Leaf 0x239
if ((addr == 0x15c) || (addr == 0x239)) {
if (addr == 0x15c){
- gas_pressed = ((GET_BYTE(to_push, 5) << 2) | ((GET_BYTE(to_push, 6) >> 6) & 0x3)) > 1;
+ gas_pressed = ((GET_BYTE(to_push, 5) << 2) | ((GET_BYTE(to_push, 6) >> 6) & 0x3)) > 3;
} else {
gas_pressed = GET_BYTE(to_push, 0) > 3;
}
diff --git a/rednose/helpers/ekf_sym.py b/rednose/helpers/ekf_sym.py
index 2f480bc6..6df607e5 100644
--- a/rednose/helpers/ekf_sym.py
+++ b/rednose/helpers/ekf_sym.py
@@ -157,7 +157,7 @@ def gen_code(folder, name, f_sym, dt_sym, x_sym, obs_eqs, dim_x, dim_err, eskf_p
class EKF_sym():
def __init__(self, folder, name, Q, x_initial, P_initial, dim_main, dim_main_err, # pylint: disable=dangerous-default-value
- N=0, dim_augment=0, dim_augment_err=0, maha_test_kinds=[], global_vars=None):
+ N=0, dim_augment=0, dim_augment_err=0, maha_test_kinds=[], global_vars=None, max_rewind_age=1.0):
"""Generates process function and all observation functions for the kalman filter."""
self.msckf = N > 0
self.N = N
@@ -184,6 +184,7 @@ class EKF_sym():
self.Q = Q
# rewind stuff
+ self.max_rewind_age = max_rewind_age
self.rewind_t = []
self.rewind_states = []
self.rewind_obscache = []
@@ -379,7 +380,7 @@ class EKF_sym():
# rewind
if self.filter_time is not None and t < self.filter_time:
- if len(self.rewind_t) == 0 or t < self.rewind_t[0] or t < self.rewind_t[-1] - 1.0:
+ if len(self.rewind_t) == 0 or t < self.rewind_t[0] or t < self.rewind_t[-1] - self.max_rewind_age:
print("observation too old at %.3f with filter at %.3f, ignoring" % (t, self.filter_time))
return None
rewound = self.rewind(t)
diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript
index d7e575d0..0ccbe6bd 100644
--- a/selfdrive/boardd/SConscript
+++ b/selfdrive/boardd/SConscript
@@ -1,9 +1,8 @@
-Import('env', 'common', 'cereal', 'messaging')
+Import('env', 'common', 'cereal', 'messaging', 'cython_dependencies')
-env.Program('boardd.cc', LIBS=['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'])
+env.Program('boardd', ['boardd.cc', 'panda.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'],
- ['libcan_list_to_can_capnp.a', 'boardd_api_impl.pyx', 'boardd_setup.py'],
- "cd selfdrive/boardd && python3 boardd_setup.py build_ext --inplace")
-
+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")
diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc
index c44af473..a3bb2b0b 100644
--- a/selfdrive/boardd/boardd.cc
+++ b/selfdrive/boardd/boardd.cc
@@ -1,5 +1,4 @@
#include
-#include
#include
#include
#include
@@ -8,11 +7,15 @@
#include
#include
#include
-#include
#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
@@ -24,12 +27,8 @@
#include "common/timing.h"
#include "messaging.hpp"
-#include
-#include
+#include "panda.h"
-// double the FIFO size
-#define RECV_SIZE (0x1000)
-#define TIMEOUT 0
#define MAX_IR_POWER 0.5f
#define MIN_IR_POWER 0.0f
@@ -38,60 +37,47 @@
#define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a')
#define VOLTAGE_K 0.091 // LPF gain for 5s tau (dt/tau / (dt/tau + 1))
-namespace {
-
-volatile sig_atomic_t do_exit = 0;
-
-struct __attribute__((packed)) timestamp_t {
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t weekday;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
-};
-
-libusb_context *ctx = NULL;
-libusb_device_handle *dev_handle = NULL;
-pthread_mutex_t usb_lock;
-
-bool spoofing_started = false;
-bool fake_send = false;
-bool loopback_can = false;
-cereal::HealthData::HwType hw_type = cereal::HealthData::HwType::UNKNOWN;
-bool is_pigeon = false;
-float voltage_f = 12.5; // filtered voltage
-uint32_t no_ignition_cnt = 0;
-bool connected_once = false;
-bool ignition_last = false;
-
-#ifndef __x86_64__
+#ifdef QCOM
const uint32_t NO_IGNITION_CNT_MAX = 2 * 60 * 60 * 30; // turn off charge after 30 hrs
const float VBATT_START_CHARGING = 11.5;
const float VBATT_PAUSE_CHARGING = 11.0;
#endif
-bool safety_setter_thread_initialized = false;
-pthread_t safety_setter_thread_handle;
+namespace {
-bool pigeon_thread_initialized = false;
-pthread_t pigeon_thread_handle;
+Panda * panda = NULL;
+std::atomic safety_setter_thread_running(false);
+volatile sig_atomic_t do_exit = 0;
+bool spoofing_started = false;
+bool fake_send = false;
+bool connected_once = false;
-bool pigeon_needs_init;
+struct tm get_time(){
+ time_t rawtime;
+ time(&rawtime);
-void pigeon_init();
-void *pigeon_thread(void *crap);
+ struct tm sys_time;
+ gmtime_r(&rawtime, &sys_time);
-void *safety_setter_thread(void *s) {
+ return sys_time;
+}
+
+bool time_valid(struct tm sys_time){
+ return 1900 + sys_time.tm_year >= 2019;
+}
+
+void safety_setter_thread() {
+ LOGD("Starting safety setter thread");
// diagnostic only is the default, needed for VIN query
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::ELM327), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
+ panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327);
// switch to SILENT when CarVin param is read
while (1) {
- if (do_exit) return NULL;
+ if (do_exit || !panda->connected){
+ safety_setter_thread_running = false;
+ return;
+ };
+
std::vector value_vin = read_db_bytes("CarVin");
if (value_vin.size() > 0) {
// sanity check VIN format
@@ -104,14 +90,15 @@ void *safety_setter_thread(void *s) {
}
// VIN query done, stop listening to OBDII
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
+ panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
std::vector params;
LOGW("waiting for params to set safety model");
while (1) {
- if (do_exit) return NULL;
+ if (do_exit || !panda->connected){
+ safety_setter_thread_running = false;
+ return;
+ };
params = read_db_bytes("CarParams");
if (params.size() > 0) break;
@@ -125,465 +112,103 @@ void *safety_setter_thread(void *s) {
capnp::FlatArrayMessageReader cmsg(amsg);
cereal::CarParams::Reader car_params = cmsg.getRoot();
+ cereal::CarParams::SafetyModel safety_model = car_params.getSafetyModel();
- int safety_model = int(car_params.getSafetyModel());
auto safety_param = car_params.getSafetyParam();
- LOGW("setting safety model: %d with param %d", safety_model, safety_param);
+ LOGW("setting safety model: %d with param %d", (int)safety_model, safety_param);
- pthread_mutex_lock(&usb_lock);
+ panda->set_safety_model(safety_model, safety_param);
- // set in the mutex to avoid race
- safety_setter_thread_initialized = false;
-
- libusb_control_transfer(dev_handle, 0x40, 0xdc, safety_model, safety_param, NULL, 0, TIMEOUT);
-
- pthread_mutex_unlock(&usb_lock);
-
- return NULL;
+ safety_setter_thread_running = false;
}
-// must be called before threads or with mutex
+
bool usb_connect() {
- int err, err2;
- unsigned char hw_query[1] = {0};
- unsigned char fw_sig_buf[128];
- unsigned char fw_sig_hex_buf[16];
- unsigned char serial_buf[16];
- const char *serial;
- int serial_sz = 0;
-
- ignition_last = false;
-
- if (dev_handle != NULL){
- libusb_close(dev_handle);
- dev_handle = NULL;
+ try {
+ assert(panda == NULL);
+ panda = new Panda();
+ } catch (std::exception &e) {
+ return false;
}
- dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc);
- if (dev_handle == NULL) { goto fail; }
-
- err = libusb_set_configuration(dev_handle, 1);
- if (err != 0) { goto fail; }
-
- err = libusb_claim_interface(dev_handle, 0);
- if (err != 0) { goto fail; }
-
- if (loopback_can) {
- libusb_control_transfer(dev_handle, 0xc0, 0xe5, 1, 0, NULL, 0, TIMEOUT);
+ if (getenv("BOARDD_LOOPBACK")) {
+ panda->set_loopback(true);
}
- // get panda fw
- err = libusb_control_transfer(dev_handle, 0xc0, 0xd3, 0, 0, fw_sig_buf, 64, TIMEOUT);
- err2 = libusb_control_transfer(dev_handle, 0xc0, 0xd4, 0, 0, fw_sig_buf + 64, 64, TIMEOUT);
- if ((err == 64) && (err2 == 64)) {
- printf("FW signature read\n");
- write_db_value("PandaFirmware", (const char *)fw_sig_buf, 128);
+ const char *fw_sig_buf = panda->get_firmware_version();
+ if (fw_sig_buf){
+ write_db_value("PandaFirmware", fw_sig_buf, 128);
+ // Convert to hex for offroad
+ char fw_sig_hex_buf[16] = {0};
for (size_t i = 0; i < 8; i++){
- fw_sig_hex_buf[2*i] = NIBBLE_TO_HEX(fw_sig_buf[i] >> 4);
- fw_sig_hex_buf[2*i+1] = NIBBLE_TO_HEX(fw_sig_buf[i] & 0xF);
+ fw_sig_hex_buf[2*i] = NIBBLE_TO_HEX((uint8_t)fw_sig_buf[i] >> 4);
+ fw_sig_hex_buf[2*i+1] = NIBBLE_TO_HEX((uint8_t)fw_sig_buf[i] & 0xF);
}
- write_db_value("PandaFirmwareHex", (const char *)fw_sig_hex_buf, 16);
- }
- else { goto fail; }
+
+ write_db_value("PandaFirmwareHex", fw_sig_hex_buf, 16);
+ LOGW("fw signature: %.*s", 16, fw_sig_hex_buf);
+
+ delete[] fw_sig_buf;
+ } else { return false; }
// get panda serial
- err = libusb_control_transfer(dev_handle, 0xc0, 0xd0, 0, 0, serial_buf, 16, TIMEOUT);
+ const char *serial_buf = panda->get_serial();
+ if (serial_buf) {
+ size_t serial_sz = strnlen(serial_buf, 16);
- if (err > 0) {
- serial = (const char *)serial_buf;
- serial_sz = strnlen(serial, err);
- write_db_value("PandaDongleId", serial, serial_sz);
- printf("panda serial: %.*s\n", serial_sz, serial);
- }
- else { goto fail; }
+ write_db_value("PandaDongleId", serial_buf, serial_sz);
+ LOGW("panda serial: %.*s", serial_sz, serial_buf);
+
+ delete[] serial_buf;
+ } else { return false; }
// power on charging, only the first time. Panda can also change mode and it causes a brief disconneciton
#ifndef __x86_64__
if (!connected_once) {
- libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CDP), 0, NULL, 0, TIMEOUT);
+ panda->set_usb_power_mode(cereal::HealthData::UsbPowerMode::CDP);
}
#endif
- connected_once = true;
- libusb_control_transfer(dev_handle, 0xc0, 0xc1, 0, 0, hw_query, 1, TIMEOUT);
+ if (panda->has_rtc){
+ struct tm sys_time = get_time();
+ struct tm rtc_time = panda->get_rtc();
- hw_type = (cereal::HealthData::HwType)(hw_query[0]);
- is_pigeon = (hw_type == cereal::HealthData::HwType::GREY_PANDA) ||
- (hw_type == cereal::HealthData::HwType::BLACK_PANDA) ||
- (hw_type == cereal::HealthData::HwType::UNO);
- if (is_pigeon) {
- LOGW("panda with gps detected");
- pigeon_needs_init = true;
- if (!pigeon_thread_initialized) {
- err = pthread_create(&pigeon_thread_handle, NULL, pigeon_thread, NULL);
- assert(err == 0);
- pigeon_thread_initialized = true;
- }
- }
-
- if (hw_type == cereal::HealthData::HwType::UNO){
- // Get time from system
- time_t rawtime;
- time(&rawtime);
-
- struct tm sys_time;
- gmtime_r(&rawtime, &sys_time);
-
- // Get time from RTC
- timestamp_t rtc_time;
- libusb_control_transfer(dev_handle, 0xc0, 0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time), TIMEOUT);
-
- //printf("System: %d-%d-%d\t%d:%d:%d\n", 1900 + sys_time.tm_year, 1 + sys_time.tm_mon, sys_time.tm_mday, sys_time.tm_hour, sys_time.tm_min, sys_time.tm_sec);
- //printf("RTC: %d-%d-%d\t%d:%d:%d\n", rtc_time.year, rtc_time.month, rtc_time.day, rtc_time.hour, rtc_time.minute, rtc_time.second);
-
- // Update system time from RTC if it looks off, and RTC time is good
- if (1900 + sys_time.tm_year < 2019 && rtc_time.year >= 2019){
+ if (!time_valid(sys_time) && time_valid(rtc_time)) {
LOGE("System time wrong, setting from RTC");
- struct tm new_time = { 0 };
- new_time.tm_year = rtc_time.year - 1900;
- new_time.tm_mon = rtc_time.month - 1;
- new_time.tm_mday = rtc_time.day;
- new_time.tm_hour = rtc_time.hour;
- new_time.tm_min = rtc_time.minute;
- new_time.tm_sec = rtc_time.second;
-
setenv("TZ","UTC",1);
- const struct timeval tv = {mktime(&new_time), 0};
+ const struct timeval tv = {mktime(&rtc_time), 0};
settimeofday(&tv, 0);
}
}
+ connected_once = true;
return true;
-fail:
- return false;
}
// must be called before threads or with mutex
void usb_retry_connect() {
- LOG("attempting to connect");
+ LOGW("attempting to connect");
while (!usb_connect()) { usleep(100*1000); }
LOGW("connected to board");
}
-void handle_usb_issue(int err, const char func[]) {
- LOGE_100("usb error %d \"%s\" in %s", err, libusb_strerror((enum libusb_error)err), func);
- if (err == -4) {
- LOGE("lost connection");
- usb_retry_connect();
- }
- // TODO: check other errors, is simply retrying okay?
-}
-
void can_recv(PubMaster &pm) {
- int err;
- uint32_t data[RECV_SIZE/4];
- int recv;
-
uint64_t start_time = nanos_since_boot();
- // do recv
- pthread_mutex_lock(&usb_lock);
-
- do {
- err = libusb_bulk_transfer(dev_handle, 0x81, (uint8_t*)data, RECV_SIZE, &recv, TIMEOUT);
- if (err != 0) { handle_usb_issue(err, __func__); }
- if (err == -8) { LOGE_100("overflow got 0x%x", recv); };
-
- // timeout is okay to exit, recv still happened
- if (err == -7) { break; }
- } while(err != 0);
-
- pthread_mutex_unlock(&usb_lock);
-
- // return if length is 0
- if (recv <= 0) {
- return;
- } else if (recv == RECV_SIZE) {
- LOGW("Receive buffer full");
- }
-
// create message
capnp::MallocMessageBuilder msg;
cereal::Event::Builder event = msg.initRoot();
event.setLogMonoTime(start_time);
- size_t num_msg = recv / 0x10;
- auto canData = event.initCan(num_msg);
- // populate message
- for (int i = 0; i < num_msg; i++) {
- if (data[i*4] & 4) {
- // extended
- canData[i].setAddress(data[i*4] >> 3);
- //printf("got extended: %x\n", data[i*4] >> 3);
- } else {
- // normal
- canData[i].setAddress(data[i*4] >> 21);
- }
- canData[i].setBusTime(data[i*4+1] >> 16);
- int len = data[i*4+1]&0xF;
- canData[i].setDat(kj::arrayPtr((uint8_t*)&data[i*4+2], len));
- canData[i].setSrc((data[i*4+1] >> 4) & 0xff);
+ int recv = panda->can_receive(event);
+ if (recv){
+ pm.send("can", msg);
}
-
- pm.send("can", msg);
}
-void can_health(PubMaster &pm) {
- int cnt;
- int err;
-
- // copied from panda/board/main.c
- struct __attribute__((packed)) health {
- uint32_t uptime;
- uint32_t voltage;
- uint32_t current;
- uint32_t can_rx_errs;
- uint32_t can_send_errs;
- uint32_t can_fwd_errs;
- uint32_t gmlan_send_errs;
- uint32_t faults;
- uint8_t ignition_line;
- uint8_t ignition_can;
- uint8_t controls_allowed;
- uint8_t gas_interceptor_detected;
- uint8_t car_harness_status;
- uint8_t usb_power_mode;
- uint8_t safety_model;
- uint8_t fault_status;
- uint8_t power_save_enabled;
- } health;
-
- // create message
- capnp::MallocMessageBuilder msg;
- cereal::Event::Builder event = msg.initRoot();
- event.setLogMonoTime(nanos_since_boot());
- auto healthData = event.initHealth();
-
- bool received = false;
-
- // recv from board
- if (dev_handle != NULL) {
- pthread_mutex_lock(&usb_lock);
- cnt = libusb_control_transfer(dev_handle, 0xc0, 0xd2, 0, 0, (unsigned char*)&health, sizeof(health), TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
-
- received = (cnt == sizeof(health));
- }
-
- // No panda connected, send empty health packet
- if (!received){
- healthData.setHwType(cereal::HealthData::HwType::UNKNOWN);
- pm.send("health", msg);
- return;
- }
-
- if (spoofing_started) {
- health.ignition_line = 1;
- }
-
- voltage_f = VOLTAGE_K * (health.voltage / 1000.0) + (1.0 - VOLTAGE_K) * voltage_f; // LPF
-
- // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node
- if (health.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) {
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- }
-
- bool ignition = ((health.ignition_line != 0) || (health.ignition_can != 0));
-
- if (ignition) {
- no_ignition_cnt = 0;
- } else {
- no_ignition_cnt += 1;
- }
-
-#ifndef __x86_64__
- bool cdp_mode = health.usb_power_mode == (uint8_t)(cereal::HealthData::UsbPowerMode::CDP);
- bool no_ignition_exp = no_ignition_cnt > NO_IGNITION_CNT_MAX;
- if ((no_ignition_exp || (voltage_f < VBATT_PAUSE_CHARGING)) && cdp_mode && !ignition) {
- std::vector disable_power_down = read_db_bytes("DisablePowerDown");
- if (disable_power_down.size() != 1 || disable_power_down[0] != '1') {
- printf("TURN OFF CHARGING!\n");
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CLIENT), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- printf("POWER DOWN DEVICE\n");
- system("service call power 17 i32 0 i32 1");
- }
- }
- if (!no_ignition_exp && (voltage_f > VBATT_START_CHARGING) && !cdp_mode) {
- printf("TURN ON CHARGING!\n");
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CDP), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- }
- // set power save state enabled when car is off and viceversa when it's on
- if (ignition && (health.power_save_enabled == 1)) {
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0xc0, 0xe7, 0, 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- }
- if (!ignition && (health.power_save_enabled == 0)) {
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0xc0, 0xe7, 1, 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- }
- // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
- if (!ignition && (health.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- }
-#endif
-
- // clear VIN, CarParams, and set new safety on car start
- if (ignition && !ignition_last) {
- int result = delete_db_value("CarVin");
- assert((result == 0) || (result == ERR_NO_VALUE));
- result = delete_db_value("CarParams");
- assert((result == 0) || (result == ERR_NO_VALUE));
-
- if (!safety_setter_thread_initialized) {
- err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL);
- assert(err == 0);
- safety_setter_thread_initialized = true;
- }
- }
-
- // Get fan RPM
- uint16_t fan_speed_rpm = 0;
-
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0xc0, 0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm), TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
-
- // Write to rtc once per minute when no ignition present
- if ((hw_type == cereal::HealthData::HwType::UNO) && !ignition && (no_ignition_cnt % 120 == 1)){
- // Get time from system
- time_t rawtime;
- time(&rawtime);
-
- struct tm sys_time;
- gmtime_r(&rawtime, &sys_time);
-
- // Write time to RTC if it looks reasonable
- if (1900 + sys_time.tm_year >= 2019){
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xa1, (uint16_t)(1900 + sys_time.tm_year), 0, NULL, 0, TIMEOUT);
- libusb_control_transfer(dev_handle, 0x40, 0xa2, (uint16_t)(1 + sys_time.tm_mon), 0, NULL, 0, TIMEOUT);
- libusb_control_transfer(dev_handle, 0x40, 0xa3, (uint16_t)sys_time.tm_mday, 0, NULL, 0, TIMEOUT);
- // libusb_control_transfer(dev_handle, 0x40, 0xa4, (uint16_t)(1 + sys_time.tm_wday), 0, NULL, 0, TIMEOUT);
- libusb_control_transfer(dev_handle, 0x40, 0xa5, (uint16_t)sys_time.tm_hour, 0, NULL, 0, TIMEOUT);
- libusb_control_transfer(dev_handle, 0x40, 0xa6, (uint16_t)sys_time.tm_min, 0, NULL, 0, TIMEOUT);
- libusb_control_transfer(dev_handle, 0x40, 0xa7, (uint16_t)sys_time.tm_sec, 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
- }
- }
-
- ignition_last = ignition;
-
- // set fields
- healthData.setUptime(health.uptime);
- healthData.setVoltage(health.voltage);
- healthData.setCurrent(health.current);
- healthData.setIgnitionLine(health.ignition_line);
- healthData.setIgnitionCan(health.ignition_can);
- healthData.setControlsAllowed(health.controls_allowed);
- healthData.setGasInterceptorDetected(health.gas_interceptor_detected);
- healthData.setHasGps(is_pigeon);
- healthData.setCanRxErrs(health.can_rx_errs);
- healthData.setCanSendErrs(health.can_send_errs);
- healthData.setCanFwdErrs(health.can_fwd_errs);
- healthData.setGmlanSendErrs(health.gmlan_send_errs);
- healthData.setHwType(hw_type);
- healthData.setUsbPowerMode(cereal::HealthData::UsbPowerMode(health.usb_power_mode));
- healthData.setSafetyModel(cereal::CarParams::SafetyModel(health.safety_model));
- healthData.setFanSpeedRpm(fan_speed_rpm);
- healthData.setFaultStatus(cereal::HealthData::FaultStatus(health.fault_status));
- healthData.setPowerSaveEnabled((bool)(health.power_save_enabled));
-
- // Convert faults bitset to capnp list
- std::bitset fault_bits(health.faults);
- auto faults = healthData.initFaults(fault_bits.count());
-
- size_t i = 0;
- for (size_t f = size_t(cereal::HealthData::FaultType::RELAY_MALFUNCTION);
- f <= size_t(cereal::HealthData::FaultType::INTERRUPT_RATE_KLINE_INIT); f++){
- if (fault_bits.test(f)) {
- faults.set(i, cereal::HealthData::FaultType(f));
- i++;
- }
- }
- // send to health
- pm.send("health", msg);
-
- // send heartbeat back to panda
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xf3, 1, 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
-}
-
-
-void can_send(cereal::Event::Reader &event) {
- int err;
- // recv from sendcan
- if (nanos_since_boot() - event.getLogMonoTime() > 1e9) {
- //Older than 1 second. Dont send.
- return;
- }
-
- auto can_data_list = event.getSendcan();
- int msg_count = can_data_list.size();
-
- uint32_t *send = (uint32_t*)malloc(msg_count*0x10);
- memset(send, 0, msg_count*0x10);
-
- for (int i = 0; i < msg_count; i++) {
- auto cmsg = can_data_list[i];
- if (cmsg.getAddress() >= 0x800) {
- // extended
- send[i*4] = (cmsg.getAddress() << 3) | 5;
- } else {
- // normal
- send[i*4] = (cmsg.getAddress() << 21) | 1;
- }
- auto can_data = cmsg.getDat();
- assert(can_data.size() <= 8);
- send[i*4+1] = can_data.size() | (cmsg.getSrc() << 4);
- memcpy(&send[i*4+2], can_data.begin(), can_data.size());
- }
-
- // send to board
- int sent;
- pthread_mutex_lock(&usb_lock);
-
- if (!fake_send) {
- do {
- // Try sending can messages. If the receive buffer on the panda is full it will NAK
- // and libusb will try again. After 5ms, it will time out. We will drop the messages.
- err = libusb_bulk_transfer(dev_handle, 3, (uint8_t*)send, msg_count*0x10, &sent, 5);
- if (err == LIBUSB_ERROR_TIMEOUT) {
- LOGW("Transmit buffer full");
- break;
- } else if (err != 0 || msg_count*0x10 != sent) {
- LOGW("Error");
- handle_usb_issue(err, __func__);
- }
- } while(err != 0);
- }
-
- pthread_mutex_unlock(&usb_lock);
-
- // done
- free(send);
-}
-
-// **** threads ****
-
-void *can_send_thread(void *crap) {
+void can_send_thread() {
LOGD("start send thread");
Context * context = Context::create();
@@ -592,7 +217,7 @@ void *can_send_thread(void *crap) {
subscriber->setTimeout(100);
// run as fast as messages come in
- while (!do_exit) {
+ while (!do_exit && panda->connected) {
Message * msg = subscriber->receive();
if (!msg){
@@ -607,17 +232,22 @@ void *can_send_thread(void *crap) {
capnp::FlatArrayMessageReader cmsg(amsg);
cereal::Event::Reader event = cmsg.getRoot();
- can_send(event);
+
+ //Dont send if older than 1 second
+ if (nanos_since_boot() - event.getLogMonoTime() < 1e9) {
+ if (!fake_send){
+ panda->can_send(event.getSendcan());
+ }
+ }
+
delete msg;
}
delete subscriber;
delete context;
-
- return NULL;
}
-void *can_recv_thread(void *crap) {
+void can_recv_thread() {
LOGD("start recv thread");
// can = 8006
@@ -627,7 +257,7 @@ void *can_recv_thread(void *crap) {
const uint64_t dt = 10000000ULL;
uint64_t next_frame_time = nanos_since_boot() + dt;
- while (!do_exit) {
+ while (!do_exit && panda->connected) {
can_recv(pm);
uint64_t cur_time = nanos_since_boot();
@@ -642,34 +272,157 @@ void *can_recv_thread(void *crap) {
next_frame_time += dt;
}
- return NULL;
}
-void *can_health_thread(void *crap) {
+void can_health_thread() {
LOGD("start health thread");
- // health = 8011
PubMaster pm({"health"});
- // run at 2hz
- while (!do_exit) {
- can_health(pm);
+ uint32_t no_ignition_cnt = 0;
+ bool ignition_last = false;
+ float voltage_f = 12.5; // filtered voltage
+
+ // Broadcast empty health message when panda is not yet connected
+ while (!panda){
+ capnp::MallocMessageBuilder msg;
+ cereal::Event::Builder event = msg.initRoot();
+ event.setLogMonoTime(nanos_since_boot());
+ auto healthData = event.initHealth();
+
+ healthData.setHwType(cereal::HealthData::HwType::UNKNOWN);
+ pm.send("health", msg);
usleep(500*1000);
}
- return NULL;
+ // run at 2hz
+ while (!do_exit && panda->connected) {
+ capnp::MallocMessageBuilder msg;
+ cereal::Event::Builder event = msg.initRoot();
+ event.setLogMonoTime(nanos_since_boot());
+ auto healthData = event.initHealth();
+
+ health_t health = panda->get_health();
+
+ if (spoofing_started) {
+ health.ignition_line = 1;
+ }
+
+ voltage_f = VOLTAGE_K * (health.voltage / 1000.0) + (1.0 - VOLTAGE_K) * voltage_f; // LPF
+
+ // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node
+ if (health.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) {
+ panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
+ }
+
+ bool ignition = ((health.ignition_line != 0) || (health.ignition_can != 0));
+
+ if (ignition) {
+ no_ignition_cnt = 0;
+ } else {
+ no_ignition_cnt += 1;
+ }
+
+#ifdef QCOM
+ bool cdp_mode = health.usb_power_mode == (uint8_t)(cereal::HealthData::UsbPowerMode::CDP);
+ bool no_ignition_exp = no_ignition_cnt > NO_IGNITION_CNT_MAX;
+ if ((no_ignition_exp || (voltage_f < VBATT_PAUSE_CHARGING)) && cdp_mode && !ignition) {
+ std::vector disable_power_down = read_db_bytes("DisablePowerDown");
+ if (disable_power_down.size() != 1 || disable_power_down[0] != '1') {
+ LOGW("TURN OFF CHARGING!\n");
+ panda->set_usb_power_mode(cereal::HealthData::UsbPowerMode::CLIENT);
+ LOGW("POWER DOWN DEVICE\n");
+ system("service call power 17 i32 0 i32 1");
+ }
+ }
+ if (!no_ignition_exp && (voltage_f > VBATT_START_CHARGING) && !cdp_mode) {
+ LOGW("TURN ON CHARGING!\n");
+ panda->set_usb_power_mode(cereal::HealthData::UsbPowerMode::CDP);
+ }
+#endif
+
+#ifndef __x86_64__
+ bool power_save_desired = !ignition;
+ if (health.power_save_enabled != power_save_desired){
+ panda->set_power_saving(power_save_desired);
+ }
+
+ // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
+ if (!ignition && (health.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
+ panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
+ }
+#endif
+
+ // clear VIN, CarParams, and set new safety on car start
+ if (ignition && !ignition_last) {
+ int result = delete_db_value("CarVin");
+ assert((result == 0) || (result == ERR_NO_VALUE));
+ result = delete_db_value("CarParams");
+ assert((result == 0) || (result == ERR_NO_VALUE));
+
+ if (!safety_setter_thread_running) {
+ safety_setter_thread_running = true;
+ std::thread(safety_setter_thread).detach();
+ } else {
+ LOGW("Safety setter thread already running");
+ }
+ }
+
+ // Write to rtc once per minute when no ignition present
+ if ((panda->has_rtc) && !ignition && (no_ignition_cnt % 120 == 1)){
+ // Write time to RTC if it looks reasonable
+ struct tm sys_time = get_time();
+ if (time_valid(sys_time)){
+ panda->set_rtc(sys_time);
+ }
+ }
+
+ ignition_last = ignition;
+ uint16_t fan_speed_rpm = panda->get_fan_speed();
+
+ // set fields
+ healthData.setUptime(health.uptime);
+ healthData.setVoltage(health.voltage);
+ healthData.setCurrent(health.current);
+ healthData.setIgnitionLine(health.ignition_line);
+ healthData.setIgnitionCan(health.ignition_can);
+ healthData.setControlsAllowed(health.controls_allowed);
+ healthData.setGasInterceptorDetected(health.gas_interceptor_detected);
+ healthData.setHasGps(panda->is_pigeon);
+ healthData.setCanRxErrs(health.can_rx_errs);
+ healthData.setCanSendErrs(health.can_send_errs);
+ healthData.setCanFwdErrs(health.can_fwd_errs);
+ healthData.setGmlanSendErrs(health.gmlan_send_errs);
+ healthData.setHwType(panda->hw_type);
+ healthData.setUsbPowerMode(cereal::HealthData::UsbPowerMode(health.usb_power_mode));
+ healthData.setSafetyModel(cereal::CarParams::SafetyModel(health.safety_model));
+ healthData.setFanSpeedRpm(fan_speed_rpm);
+ healthData.setFaultStatus(cereal::HealthData::FaultStatus(health.fault_status));
+ healthData.setPowerSaveEnabled((bool)(health.power_save_enabled));
+
+ // Convert faults bitset to capnp list
+ std::bitset fault_bits(health.faults);
+ auto faults = healthData.initFaults(fault_bits.count());
+
+ size_t i = 0;
+ for (size_t f = size_t(cereal::HealthData::FaultType::RELAY_MALFUNCTION);
+ f <= size_t(cereal::HealthData::FaultType::INTERRUPT_RATE_KLINE_INIT); f++){
+ if (fault_bits.test(f)) {
+ faults.set(i, cereal::HealthData::FaultType(f));
+ i++;
+ }
+ }
+ pm.send("health", msg);
+ panda->send_heartbeat();
+ usleep(500*1000);
+ }
}
-void *hardware_control_thread(void *crap) {
+void hardware_control_thread() {
LOGD("start hardware control thread");
SubMaster sm({"thermal", "frontFrame"});
- // Wait for hardware type to be set.
- while (hw_type == cereal::HealthData::HwType::UNKNOWN){
- usleep(100*1000);
- }
// Only control fan speed on UNO
- if (hw_type != cereal::HealthData::HwType::UNO) return NULL;
-
+ if (panda->hw_type != cereal::HealthData::HwType::UNO) return;
uint64_t last_front_frame_t = 0;
uint16_t prev_fan_speed = 999;
@@ -677,16 +430,14 @@ void *hardware_control_thread(void *crap) {
uint16_t prev_ir_pwr = 999;
unsigned int cnt = 0;
- while (!do_exit) {
+ while (!do_exit && panda->connected) {
cnt++;
- sm.update(1000);
+ sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update?
+
if (sm.updated("thermal")){
uint16_t fan_speed = sm["thermal"].getThermal().getFanSpeed();
if (fan_speed != prev_fan_speed || cnt % 100 == 0){
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xb1, fan_speed, 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
-
+ panda->set_fan_speed(fan_speed);
prev_fan_speed = fan_speed;
}
}
@@ -710,61 +461,32 @@ void *hardware_control_thread(void *crap) {
}
if (ir_pwr != prev_ir_pwr || cnt % 100 == 0 || ir_pwr >= 50.0){
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xb0, ir_pwr, 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
+ panda->set_ir_pwr(ir_pwr);
prev_ir_pwr = ir_pwr;
}
}
-
- return NULL;
}
#define pigeon_send(x) _pigeon_send(x, sizeof(x)-1)
-
-void hexdump(unsigned char *d, int l) __attribute__((unused));
-void hexdump(unsigned char *d, int l) {
- for (int i = 0; i < l; i++) {
- if (i!=0 && i%0x10 == 0) printf("\n");
- printf("%2.2X ", d[i]);
- }
- printf("\n");
-}
-
void _pigeon_send(const char *dat, int len) {
- int sent;
- unsigned char a[0x20];
- int err;
+ unsigned char a[0x20+1];
a[0] = 1;
for (int i=0; iusb_bulk_write(2, a, ll+1);
}
}
void pigeon_set_power(int power) {
- pthread_mutex_lock(&usb_lock);
- int err = libusb_control_transfer(dev_handle, 0xc0, 0xd9, power, 0, NULL, 0, TIMEOUT);
- if (err < 0) { handle_usb_issue(err, __func__); }
- pthread_mutex_unlock(&usb_lock);
+ panda->usb_write(0xd9, power, 0);
}
void pigeon_set_baud(int baud) {
- int err;
- pthread_mutex_lock(&usb_lock);
- err = libusb_control_transfer(dev_handle, 0xc0, 0xe2, 1, 0, NULL, 0, TIMEOUT);
- if (err < 0) { handle_usb_issue(err, __func__); }
- err = libusb_control_transfer(dev_handle, 0xc0, 0xe4, 1, baud/300, NULL, 0, TIMEOUT);
- if (err < 0) { handle_usb_issue(err, __func__); }
- pthread_mutex_unlock(&usb_lock);
+ panda->usb_write(0xe2, 1, 0);
+ panda->usb_write(0xe4, 1, baud/300);
}
void pigeon_init() {
@@ -827,24 +549,22 @@ static void pigeon_publish_raw(PubMaster &pm, unsigned char *dat, int alen) {
}
-void *pigeon_thread(void *crap) {
+void pigeon_thread() {
+ if (!panda->is_pigeon){ return; };
+
// ubloxRaw = 8042
PubMaster pm({"ubloxRaw"});
// run at ~100hz
unsigned char dat[0x1000];
uint64_t cnt = 0;
- while (!do_exit) {
- if (pigeon_needs_init) {
- pigeon_needs_init = false;
- pigeon_init();
- }
+
+ pigeon_init();
+
+ while (!do_exit && panda->connected) {
int alen = 0;
while (alen < 0xfc0) {
- pthread_mutex_lock(&usb_lock);
- int len = libusb_control_transfer(dev_handle, 0xc0, 0xe0, 1, 0, dat+alen, 0x40, TIMEOUT);
- if (len < 0) { handle_usb_issue(len, __func__); }
- pthread_mutex_unlock(&usb_lock);
+ int len = panda->usb_read(0xe0, 1, 0, dat+alen, 0x40);
if (len <= 0) break;
//printf("got %d\n", len);
@@ -863,7 +583,6 @@ void *pigeon_thread(void *crap) {
usleep(10*1000);
cnt++;
}
- return NULL;
}
}
@@ -887,64 +606,21 @@ int main() {
fake_send = true;
}
- if (getenv("BOARDD_LOOPBACK")){
- loopback_can = true;
+ while (!do_exit){
+ std::vector threads;
+ threads.push_back(std::thread(can_health_thread));
+
+ // connect to the board
+ usb_retry_connect();
+
+ threads.push_back(std::thread(can_send_thread));
+ threads.push_back(std::thread(can_recv_thread));
+ threads.push_back(std::thread(hardware_control_thread));
+ threads.push_back(std::thread(pigeon_thread));
+
+ for (auto &t : threads) t.join();
+
+ delete panda;
+ panda = NULL;
}
-
- err = pthread_mutex_init(&usb_lock, NULL);
- assert(err == 0);
-
- // init libusb
- err = libusb_init(&ctx);
- assert(err == 0);
-
-#if LIBUSB_API_VERSION >= 0x01000106
- libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
-#else
- libusb_set_debug(ctx, 3);
-#endif
-
- pthread_t can_health_thread_handle;
- err = pthread_create(&can_health_thread_handle, NULL,
- can_health_thread, NULL);
- assert(err == 0);
-
- // connect to the board
- pthread_mutex_lock(&usb_lock);
- usb_retry_connect();
- pthread_mutex_unlock(&usb_lock);
-
- // create threads
- pthread_t can_send_thread_handle;
- err = pthread_create(&can_send_thread_handle, NULL,
- can_send_thread, NULL);
- assert(err == 0);
-
- pthread_t can_recv_thread_handle;
- err = pthread_create(&can_recv_thread_handle, NULL,
- can_recv_thread, NULL);
- assert(err == 0);
-
- pthread_t hardware_control_thread_handle;
- err = pthread_create(&hardware_control_thread_handle, NULL,
- hardware_control_thread, NULL);
- assert(err == 0);
-
- // join threads
-
- err = pthread_join(can_recv_thread_handle, NULL);
- assert(err == 0);
-
- err = pthread_join(can_send_thread_handle, NULL);
- assert(err == 0);
-
- err = pthread_join(can_health_thread_handle, NULL);
- assert(err == 0);
-
- //while (!do_exit) usleep(1000);
-
- // destruct libusb
-
- libusb_close(dev_handle);
- libusb_exit(ctx);
}
diff --git a/selfdrive/boardd/boardd_setup.py b/selfdrive/boardd/boardd_setup.py
index cf71901c..4b085901 100644
--- a/selfdrive/boardd/boardd_setup.py
+++ b/selfdrive/boardd/boardd_setup.py
@@ -1,15 +1,8 @@
-import subprocess
from distutils.core import Extension, setup
-
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
-from common.basedir import BASEDIR
-import os
-PHONELIBS = os.path.join(BASEDIR, 'phonelibs')
-
-ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
libraries = ['can_list_to_can_capnp', 'capnp', 'kj']
setup(name='Boardd API Implementation',
diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc
new file mode 100644
index 00000000..5820fa40
--- /dev/null
+++ b/selfdrive/boardd/panda.cc
@@ -0,0 +1,318 @@
+#include
+#include
+#include
+
+#include "common/swaglog.h"
+
+#include "panda.h"
+
+Panda::Panda(){
+ int err;
+
+ err = pthread_mutex_init(&usb_lock, NULL);
+ if (err != 0) { goto fail; }
+
+ // init libusb
+ err = libusb_init(&ctx);
+ if (err != 0) { goto fail; }
+
+#if LIBUSB_API_VERSION >= 0x01000106
+ libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
+#else
+ libusb_set_debug(ctx, 3);
+#endif
+
+ dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc);
+ if (dev_handle == NULL) { goto fail; }
+
+ if (libusb_kernel_driver_active(dev_handle, 0) == 1) {
+ libusb_detach_kernel_driver(dev_handle, 0);
+ }
+
+ err = libusb_set_configuration(dev_handle, 1);
+ if (err != 0) { goto fail; }
+
+ err = libusb_claim_interface(dev_handle, 0);
+ if (err != 0) { goto fail; }
+
+ hw_type = get_hw_type();
+ is_pigeon =
+ (hw_type == cereal::HealthData::HwType::GREY_PANDA) ||
+ (hw_type == cereal::HealthData::HwType::BLACK_PANDA) ||
+ (hw_type == cereal::HealthData::HwType::UNO);
+ has_rtc = (hw_type == cereal::HealthData::HwType::UNO);
+
+ return;
+
+fail:
+ cleanup();
+ throw std::runtime_error("Error connecting to panda");
+}
+
+Panda::~Panda(){
+ pthread_mutex_lock(&usb_lock);
+ cleanup();
+ connected = false;
+ pthread_mutex_unlock(&usb_lock);
+}
+
+void Panda::cleanup(){
+ if (dev_handle){
+ libusb_release_interface(dev_handle, 0);
+ libusb_close(dev_handle);
+ }
+
+ if (ctx) {
+ libusb_exit(ctx);
+ }
+}
+
+void Panda::handle_usb_issue(int err, const char func[]) {
+ LOGE_100("usb error %d \"%s\" in %s", err, libusb_strerror((enum libusb_error)err), func);
+ if (err == LIBUSB_ERROR_NO_DEVICE) {
+ LOGE("lost connection");
+ connected = false;
+ }
+ // TODO: check other errors, is simply retrying okay?
+}
+
+int Panda::usb_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout) {
+ int err;
+ const uint8_t bmRequestType = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
+
+ pthread_mutex_lock(&usb_lock);
+ do {
+ err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, NULL, 0, timeout);
+ if (err < 0) handle_usb_issue(err, __func__);
+ } while (err < 0 && connected);
+
+ pthread_mutex_unlock(&usb_lock);
+
+ return err;
+}
+
+int Panda::usb_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) {
+ int err;
+ const uint8_t bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
+
+ pthread_mutex_lock(&usb_lock);
+ do {
+ err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout);
+ if (err < 0) handle_usb_issue(err, __func__);
+ } while (err < 0 && connected);
+ pthread_mutex_unlock(&usb_lock);
+
+ return err;
+}
+
+int Panda::usb_bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) {
+ int err;
+ int transferred = 0;
+
+ pthread_mutex_lock(&usb_lock);
+ do {
+ // Try sending can messages. If the receive buffer on the panda is full it will NAK
+ // and libusb will try again. After 5ms, it will time out. We will drop the messages.
+ err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout);
+
+ if (err == LIBUSB_ERROR_TIMEOUT) {
+ LOGW("Transmit buffer full");
+ break;
+ } else if (err != 0 || length != transferred) {
+ handle_usb_issue(err, __func__);
+ }
+ } while(err != 0 && connected);
+
+ pthread_mutex_unlock(&usb_lock);
+ return transferred;
+}
+
+int Panda::usb_bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) {
+ int err;
+ int transferred = 0;
+
+ pthread_mutex_lock(&usb_lock);
+
+ do {
+ err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout);
+
+ if (err == LIBUSB_ERROR_TIMEOUT) {
+ break; // timeout is okay to exit, recv still happened
+ } else if (err == LIBUSB_ERROR_OVERFLOW) {
+ LOGE_100("overflow got 0x%x", transferred);
+ } else if (err != 0) {
+ handle_usb_issue(err, __func__);
+ }
+
+ } while(err != 0 && connected);
+
+ pthread_mutex_unlock(&usb_lock);
+
+ return transferred;
+}
+
+void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param){
+ usb_write(0xdc, (uint16_t)safety_model, safety_param);
+}
+
+cereal::HealthData::HwType Panda::get_hw_type() {
+ unsigned char hw_query[1] = {0};
+
+ usb_read(0xc1, 0, 0, hw_query, 1);
+ return (cereal::HealthData::HwType)(hw_query[0]);
+}
+
+void Panda::set_rtc(struct tm sys_time){
+ // tm struct has year defined as years since 1900
+ usb_write(0xa1, (uint16_t)(1900 + sys_time.tm_year), 0);
+ usb_write(0xa2, (uint16_t)(1 + sys_time.tm_mon), 0);
+ usb_write(0xa3, (uint16_t)sys_time.tm_mday, 0);
+ // usb_write(0xa4, (uint16_t)(1 + sys_time.tm_wday), 0);
+ usb_write(0xa5, (uint16_t)sys_time.tm_hour, 0);
+ usb_write(0xa6, (uint16_t)sys_time.tm_min, 0);
+ usb_write(0xa7, (uint16_t)sys_time.tm_sec, 0);
+}
+
+struct tm Panda::get_rtc(){
+ struct __attribute__((packed)) timestamp_t {
+ uint16_t year; // Starts at 0
+ uint8_t month;
+ uint8_t day;
+ uint8_t weekday;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ } rtc_time = {0};
+
+ usb_read(0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time));
+
+ struct tm new_time = { 0 };
+ new_time.tm_year = rtc_time.year - 1900; // tm struct has year defined as years since 1900
+ new_time.tm_mon = rtc_time.month - 1;
+ new_time.tm_mday = rtc_time.day;
+ new_time.tm_hour = rtc_time.hour;
+ new_time.tm_min = rtc_time.minute;
+ new_time.tm_sec = rtc_time.second;
+
+ return new_time;
+}
+
+void Panda::set_fan_speed(uint16_t fan_speed){
+ usb_write(0xb1, fan_speed, 0);
+}
+
+uint16_t Panda::get_fan_speed(){
+ uint16_t fan_speed_rpm = 0;
+ usb_read(0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm));
+ return fan_speed_rpm;
+}
+
+void Panda::set_ir_pwr(uint16_t ir_pwr) {
+ usb_write(0xb0, ir_pwr, 0);
+}
+
+health_t Panda::get_health(){
+ health_t health {0};
+ usb_read(0xd2, 0, 0, (unsigned char*)&health, sizeof(health));
+ return health;
+}
+
+void Panda::set_loopback(bool loopback){
+ usb_write(0xe5, loopback, 0);
+}
+
+const char* Panda::get_firmware_version(){
+ const char* fw_sig_buf = new char[128]();
+
+ int read_1 = usb_read(0xd3, 0, 0, (unsigned char*)fw_sig_buf, 64);
+ int read_2 = usb_read(0xd4, 0, 0, (unsigned char*)fw_sig_buf + 64, 64);
+
+ if ((read_1 == 64) && (read_2 == 64)) {
+ return fw_sig_buf;
+ }
+
+ delete[] fw_sig_buf;
+ return NULL;
+}
+
+const char* Panda::get_serial(){
+ const char* serial_buf = new char[16]();
+
+ int err = usb_read(0xd0, 0, 0, (unsigned char*)serial_buf, 16);
+
+ if (err >= 0) {
+ return serial_buf;
+ }
+
+ delete[] serial_buf;
+ return NULL;
+
+}
+
+void Panda::set_power_saving(bool power_saving){
+ usb_write(0xe7, power_saving, 0);
+}
+
+void Panda::set_usb_power_mode(cereal::HealthData::UsbPowerMode power_mode){
+ usb_write(0xe6, (uint16_t)power_mode, 0);
+}
+
+void Panda::send_heartbeat(){
+ usb_write(0xf3, 1, 0);
+}
+
+void Panda::can_send(capnp::List::Reader can_data_list){
+ int msg_count = can_data_list.size();
+
+ uint32_t *send = new uint32_t[msg_count*0x10]();
+
+ for (int i = 0; i < msg_count; i++) {
+ auto cmsg = can_data_list[i];
+ if (cmsg.getAddress() >= 0x800) { // extended
+ send[i*4] = (cmsg.getAddress() << 3) | 5;
+ } else { // normal
+ send[i*4] = (cmsg.getAddress() << 21) | 1;
+ }
+ auto can_data = cmsg.getDat();
+ assert(can_data.size() <= 8);
+ send[i*4+1] = can_data.size() | (cmsg.getSrc() << 4);
+ memcpy(&send[i*4+2], can_data.begin(), can_data.size());
+ }
+
+ usb_bulk_write(3, (unsigned char*)send, msg_count*0x10, 5);
+
+ delete[] send;
+}
+
+int Panda::can_receive(cereal::Event::Builder &event){
+ uint32_t data[RECV_SIZE/4];
+ int recv = usb_bulk_read(0x81, (unsigned char*)data, RECV_SIZE);
+
+ // return if length is 0
+ if (recv <= 0) {
+ return 0;
+ } else if (recv == RECV_SIZE) {
+ LOGW("Receive buffer full");
+ }
+
+ size_t num_msg = recv / 0x10;
+ auto canData = event.initCan(num_msg);
+
+ // populate message
+ for (int i = 0; i < num_msg; i++) {
+ if (data[i*4] & 4) {
+ // extended
+ canData[i].setAddress(data[i*4] >> 3);
+ //printf("got extended: %x\n", data[i*4] >> 3);
+ } else {
+ // normal
+ canData[i].setAddress(data[i*4] >> 21);
+ }
+ canData[i].setBusTime(data[i*4+1] >> 16);
+ int len = data[i*4+1]&0xF;
+ canData[i].setDat(kj::arrayPtr((uint8_t*)&data[i*4+2], len));
+ canData[i].setSrc((data[i*4+1] >> 4) & 0xff);
+ }
+
+ return recv;
+}
diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h
new file mode 100644
index 00000000..3586cda7
--- /dev/null
+++ b/selfdrive/boardd/panda.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+
+#include "cereal/gen/cpp/car.capnp.h"
+#include "cereal/gen/cpp/log.capnp.h"
+
+// double the FIFO size
+#define RECV_SIZE (0x1000)
+#define TIMEOUT 0
+
+// copied from panda/board/main.c
+struct __attribute__((packed)) health_t {
+ uint32_t uptime;
+ uint32_t voltage;
+ uint32_t current;
+ uint32_t can_rx_errs;
+ uint32_t can_send_errs;
+ uint32_t can_fwd_errs;
+ uint32_t gmlan_send_errs;
+ uint32_t faults;
+ uint8_t ignition_line;
+ uint8_t ignition_can;
+ uint8_t controls_allowed;
+ uint8_t gas_interceptor_detected;
+ uint8_t car_harness_status;
+ uint8_t usb_power_mode;
+ uint8_t safety_model;
+ uint8_t fault_status;
+ uint8_t power_save_enabled;
+};
+
+class Panda {
+ private:
+ libusb_context *ctx = NULL;
+ libusb_device_handle *dev_handle = NULL;
+ pthread_mutex_t usb_lock;
+ void handle_usb_issue(int err, const char func[]);
+ void cleanup();
+
+ public:
+ Panda();
+ ~Panda();
+
+ bool connected = true;
+ cereal::HealthData::HwType hw_type = cereal::HealthData::HwType::UNKNOWN;
+ bool is_pigeon = false;
+ bool has_rtc = false;
+
+ // HW communication
+ int usb_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout=TIMEOUT);
+ int usb_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout=TIMEOUT);
+ int usb_bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT);
+ int usb_bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT);
+
+ // Panda functionality
+ cereal::HealthData::HwType get_hw_type();
+ void set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param=0);
+ void set_rtc(struct tm sys_time);
+ struct tm get_rtc();
+ void set_fan_speed(uint16_t fan_speed);
+ uint16_t get_fan_speed();
+ void set_ir_pwr(uint16_t ir_pwr);
+ health_t get_health();
+ void set_loopback(bool loopback);
+ const char* get_firmware_version();
+ const char* get_serial();
+ void set_power_saving(bool power_saving);
+ void set_usb_power_mode(cereal::HealthData::UsbPowerMode power_mode);
+ void send_heartbeat();
+ void can_send(capnp::List::Reader can_data_list);
+ int can_receive(cereal::Event::Builder &event);
+
+};
diff --git a/selfdrive/camerad/cameras/camera_frame_stream.cc b/selfdrive/camerad/cameras/camera_frame_stream.cc
index 45e50132..aecca564 100644
--- a/selfdrive/camerad/cameras/camera_frame_stream.cc
+++ b/selfdrive/camerad/cameras/camera_frame_stream.cc
@@ -94,8 +94,6 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = {
};
void cameras_init(DualCameraState *s) {
- memset(s, 0, sizeof(*s));
-
camera_init(&s->rear, CAMERA_ID_IMX298, 20);
s->rear.transform = (mat3){{
1.0, 0.0, 0.0,
diff --git a/selfdrive/camerad/cameras/camera_qcom.cc b/selfdrive/camerad/cameras/camera_qcom.cc
index 79e6c8f0..dfed6523 100644
--- a/selfdrive/camerad/cameras/camera_qcom.cc
+++ b/selfdrive/camerad/cameras/camera_qcom.cc
@@ -12,7 +12,6 @@
#include
#include
-#include
#include
#include "msmb_isp.h"
#include "msmb_ispif.h"
@@ -108,8 +107,6 @@ static void camera_release_buffer(void* cookie, int buf_idx) {
static void camera_init(CameraState *s, int camera_id, int camera_num,
uint32_t pixel_clock, uint32_t line_length_pclk,
unsigned int max_gain, unsigned int fps) {
- memset(s, 0, sizeof(*s));
-
s->camera_num = camera_num;
s->camera_id = camera_id;
@@ -125,9 +122,9 @@ static void camera_init(CameraState *s, int camera_id, int camera_num,
s->self_recover = 0;
- zsock_t *ops_sock = zsock_new_push(">inproc://cameraops");
- assert(ops_sock);
- s->ops_sock = zsock_resolve(ops_sock);
+ s->ops_sock = zsock_new_push(">inproc://cameraops");
+ assert(s->ops_sock);
+ s->ops_sock_handle = zsock_resolve(s->ops_sock);
tbuffer_init2(&s->camera_tb, FRAME_BUF_COUNT, "frame",
camera_release_buffer, s);
@@ -262,8 +259,6 @@ static int imx179_s5k3p8sp_apply_exposure(CameraState *s, int gain, int integ_li
}
void cameras_init(DualCameraState *s) {
- memset(s, 0, sizeof(*s));
-
char project_name[1024] = {0};
property_get("ro.boot.project_name", project_name, "");
@@ -397,7 +392,9 @@ static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) {
if (err == 0) {
s->cur_exposure_frac = exposure_frac;
+ pthread_mutex_lock(&s->frame_info_lock);
s->cur_gain_frac = gain_frac;
+ pthread_mutex_unlock(&s->frame_info_lock);
}
//LOGD("set exposure: %f %f - %d", exposure_frac, gain_frac, err);
@@ -414,16 +411,20 @@ static void do_autoexposure(CameraState *s, float grey_frac) {
const unsigned int exposure_time_min = 16;
const unsigned int exposure_time_max = frame_length - 11; // copied from set_exposure()
+ float cur_gain_frac = s->cur_gain_frac;
float exposure_factor = pow(1.05, (target_grey - grey_frac) / 0.05);
- if (s->cur_gain_frac > 0.125 && exposure_factor < 1) {
- s->cur_gain_frac *= exposure_factor;
+ if (cur_gain_frac > 0.125 && exposure_factor < 1) {
+ cur_gain_frac *= exposure_factor;
} else if (s->cur_integ_lines * exposure_factor <= exposure_time_max && s->cur_integ_lines * exposure_factor >= exposure_time_min) { // adjust exposure time first
s->cur_exposure_frac *= exposure_factor;
- } else if (s->cur_gain_frac * exposure_factor <= gain_frac_max && s->cur_gain_frac * exposure_factor >= gain_frac_min) {
- s->cur_gain_frac *= exposure_factor;
+ } else if (cur_gain_frac * exposure_factor <= gain_frac_max && cur_gain_frac * exposure_factor >= gain_frac_min) {
+ cur_gain_frac *= exposure_factor;
}
+ pthread_mutex_lock(&s->frame_info_lock);
+ s->cur_gain_frac = cur_gain_frac;
+ pthread_mutex_unlock(&s->frame_info_lock);
- set_exposure(s, s->cur_exposure_frac, s->cur_gain_frac);
+ set_exposure(s, s->cur_exposure_frac, cur_gain_frac);
} else { // keep the old for others
float new_exposure = s->cur_exposure_frac;
@@ -448,7 +449,7 @@ void camera_autoexposure(CameraState *s, float grey_frac) {
.grey_frac = grey_frac,
};
- zmq_send(s->ops_sock, &msg, sizeof(msg), ZMQ_DONTWAIT);
+ zmq_send(s->ops_sock_handle, &msg, sizeof(msg), ZMQ_DONTWAIT);
}
static uint8_t* get_eeprom(int eeprom_fd, size_t *out_len) {
@@ -1795,15 +1796,16 @@ static void do_autofocus(CameraState *s) {
const int dac_up = s->device == DEVICE_LP3? LP3_AF_DAC_UP:OP3T_AF_DAC_UP;
const int dac_down = s->device == DEVICE_LP3? LP3_AF_DAC_DOWN:OP3T_AF_DAC_DOWN;
+ float lens_true_pos = s->lens_true_pos;
if (!isnan(err)) {
// learn lens_true_pos
- s->lens_true_pos -= err*focus_kp;
+ lens_true_pos -= err*focus_kp;
}
// stay off the walls
- s->lens_true_pos = clamp(s->lens_true_pos, dac_down, dac_up);
-
- int target = clamp(s->lens_true_pos - sag, dac_down, dac_up);
+ lens_true_pos = clamp(lens_true_pos, dac_down, dac_up);
+ int target = clamp(lens_true_pos - sag, dac_down, dac_up);
+ s->lens_true_pos = lens_true_pos;
/*char debug[4096];
char *pdebug = debug;
@@ -1956,6 +1958,8 @@ static void camera_close(CameraState *s) {
}
free(s->eeprom);
+
+ zsock_destroy(&s->ops_sock);
}
diff --git a/selfdrive/camerad/cameras/camera_qcom.h b/selfdrive/camerad/cameras/camera_qcom.h
index 063b813c..812f1a59 100644
--- a/selfdrive/camerad/cameras/camera_qcom.h
+++ b/selfdrive/camerad/cameras/camera_qcom.h
@@ -1,9 +1,10 @@
-#ifndef CAMERA_H
-#define CAMERA_H
+#pragma once
#include
#include
#include
+#include
+#include
#include "messaging.hpp"
#include "msmb_isp.h"
@@ -61,7 +62,8 @@ typedef struct CameraState {
int device;
- void* ops_sock;
+ void* ops_sock_handle;
+ zsock_t * ops_sock;
uint32_t pixel_clock;
uint32_t line_length_pclk;
@@ -94,7 +96,7 @@ typedef struct CameraState {
int cur_frame_length;
int cur_integ_lines;
- float digital_gain;
+ std::atomic digital_gain;
StreamState ss[3];
@@ -111,9 +113,9 @@ typedef struct CameraState {
uint16_t cur_lens_pos;
uint64_t last_sag_ts;
float last_sag_acc_z;
- float lens_true_pos;
+ std::atomic lens_true_pos;
- int self_recover; // af recovery counter, neg is patience, pos is active
+ std::atomic self_recover; // af recovery counter, neg is patience, pos is active
int fps;
@@ -142,5 +144,3 @@ int sensor_write_regs(CameraState *s, struct msm_camera_i2c_reg_array* arr, size
#ifdef __cplusplus
} // extern "C"
#endif
-
-#endif
diff --git a/selfdrive/camerad/main.cc b/selfdrive/camerad/main.cc
index 4e1ce307..658ab55b 100644
--- a/selfdrive/camerad/main.cc
+++ b/selfdrive/camerad/main.cc
@@ -332,6 +332,7 @@ void* frontview_thread(void *arg) {
//double t2 = millis_since_boot();
//LOGD("front process: %.2fms", t2-t1);
}
+ clReleaseCommandQueue(q);
return NULL;
}
@@ -345,6 +346,11 @@ void* processing_thread(void *arg) {
err = set_realtime_priority(51);
LOG("setpriority returns %d", err);
+#if defined(QCOM) && !defined(QCOM_REPLAY)
+ std::unique_ptr rgb_roi_buf = std::make_unique((s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)*3);
+ std::unique_ptr conv_result = std::make_unique((s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y));
+#endif
+
// init cl stuff
#ifdef __APPLE__
cl_command_queue q = clCreateCommandQueue(s->context, s->device_id, 0, &err);
@@ -416,13 +422,12 @@ void* processing_thread(void *arg) {
/*double t10 = millis_since_boot();*/
// cache rgb roi and write to cl
- uint8_t *rgb_roi_buf = new uint8_t[(s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)*3];
int roi_id = cnt % ((ROI_X_MAX-ROI_X_MIN+1)*(ROI_Y_MAX-ROI_Y_MIN+1)); // rolling roi
int roi_x_offset = roi_id % (ROI_X_MAX-ROI_X_MIN+1);
int roi_y_offset = roi_id / (ROI_X_MAX-ROI_X_MIN+1);
for (int r=0;r<(s->rgb_height/NUM_SEGMENTS_Y);r++) {
- memcpy(rgb_roi_buf + r * (s->rgb_width/NUM_SEGMENTS_X) * 3,
+ memcpy(rgb_roi_buf.get() + r * (s->rgb_width/NUM_SEGMENTS_X) * 3,
(uint8_t *) s->rgb_bufs[rgb_idx].addr + \
(ROI_Y_MIN + roi_y_offset) * s->rgb_height/NUM_SEGMENTS_Y * FULL_STRIDE_X * 3 + \
(ROI_X_MIN + roi_x_offset) * s->rgb_width/NUM_SEGMENTS_X * 3 + r * FULL_STRIDE_X * 3,
@@ -430,7 +435,7 @@ void* processing_thread(void *arg) {
}
err = clEnqueueWriteBuffer (q, s->rgb_conv_roi_cl, true, 0,
- s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * 3 * sizeof(uint8_t), rgb_roi_buf, 0, 0, 0);
+ s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * 3 * sizeof(uint8_t), rgb_roi_buf.get(), 0, 0, 0);
assert(err == 0);
/*double t11 = millis_since_boot();
@@ -453,48 +458,45 @@ void* processing_thread(void *arg) {
clWaitForEvents(1, &conv_event);
clReleaseEvent(conv_event);
- int16_t *conv_result = new int16_t[(s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)];
err = clEnqueueReadBuffer(q, s->rgb_conv_result_cl, true, 0,
- s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * sizeof(int16_t), conv_result, 0, 0, 0);
+ s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * sizeof(int16_t), conv_result.get(), 0, 0, 0);
assert(err == 0);
/*t11 = millis_since_boot();
printf("conv time: %f ms\n", t11 - t10);
t10 = millis_since_boot();*/
- get_lapmap_one(conv_result, &s->lapres[roi_id], s->rgb_width/NUM_SEGMENTS_X, s->rgb_height/NUM_SEGMENTS_Y);
+ get_lapmap_one(conv_result.get(), &s->lapres[roi_id], s->rgb_width/NUM_SEGMENTS_X, s->rgb_height/NUM_SEGMENTS_Y);
/*t11 = millis_since_boot();
printf("pool time: %f ms\n", t11 - t10);
t10 = millis_since_boot();*/
- delete [] rgb_roi_buf;
- delete [] conv_result;
-
/*t11 = millis_since_boot();
printf("process time: %f ms\n ----- \n", t11 - t10);
t10 = millis_since_boot();*/
// setup self recover
+ const float lens_true_pos = s->cameras.rear.lens_true_pos;
if (is_blur(&s->lapres[0]) &&
- (s->cameras.rear.lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_DOWN:OP3T_AF_DAC_DOWN)+1 ||
- s->cameras.rear.lens_true_pos > (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_UP:OP3T_AF_DAC_UP)-1) &&
+ (lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_DOWN:OP3T_AF_DAC_DOWN)+1 ||
+ lens_true_pos > (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_UP:OP3T_AF_DAC_UP)-1) &&
s->cameras.rear.self_recover < 2) {
// truly stuck, needs help
s->cameras.rear.self_recover -= 1;
if (s->cameras.rear.self_recover < -FOCUS_RECOVER_PATIENCE) {
LOGW("rear camera bad state detected. attempting recovery from %.1f, recover state is %d",
- s->cameras.rear.lens_true_pos, s->cameras.rear.self_recover);
- s->cameras.rear.self_recover = FOCUS_RECOVER_STEPS + ((s->cameras.rear.lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M:OP3T_AF_DAC_M))?1:0); // parity determined by which end is stuck at
+ lens_true_pos, s->cameras.rear.self_recover.load());
+ s->cameras.rear.self_recover = FOCUS_RECOVER_STEPS + ((lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M:OP3T_AF_DAC_M))?1:0); // parity determined by which end is stuck at
}
- } else if ((s->cameras.rear.lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M - LP3_AF_DAC_3SIG:OP3T_AF_DAC_M - OP3T_AF_DAC_3SIG) ||
- s->cameras.rear.lens_true_pos > (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M + LP3_AF_DAC_3SIG:OP3T_AF_DAC_M + OP3T_AF_DAC_3SIG)) &&
+ } else if ((lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M - LP3_AF_DAC_3SIG:OP3T_AF_DAC_M - OP3T_AF_DAC_3SIG) ||
+ lens_true_pos > (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M + LP3_AF_DAC_3SIG:OP3T_AF_DAC_M + OP3T_AF_DAC_3SIG)) &&
s->cameras.rear.self_recover < 2) {
// in suboptimal position with high prob, but may still recover by itself
s->cameras.rear.self_recover -= 1;
if (s->cameras.rear.self_recover < -(FOCUS_RECOVER_PATIENCE*3)) {
- LOGW("rear camera bad state detected. attempting recovery from %.1f, recover state is %d", s->cameras.rear.lens_true_pos, s->cameras.rear.self_recover);
- s->cameras.rear.self_recover = FOCUS_RECOVER_STEPS/2 + ((s->cameras.rear.lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M:OP3T_AF_DAC_M))?1:0);
+ LOGW("rear camera bad state detected. attempting recovery from %.1f, recover state is %d", lens_true_pos, s->cameras.rear.self_recover.load());
+ s->cameras.rear.self_recover = FOCUS_RECOVER_STEPS/2 + ((lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M:OP3T_AF_DAC_M))?1:0);
}
} else if (s->cameras.rear.self_recover < 0) {
s->cameras.rear.self_recover += 1; // reset if fine
@@ -504,7 +506,9 @@ void* processing_thread(void *arg) {
double t2 = millis_since_boot();
+#ifndef QCOM2
uint8_t *bgr_ptr = (uint8_t*)s->rgb_bufs[rgb_idx].addr;
+#endif
double yt1 = millis_since_boot();
@@ -668,6 +672,7 @@ void* processing_thread(void *arg) {
LOGD("queued: %.2fms, yuv: %.2f, | processing: %.3fms", (t2-t1), (yt2-yt1), (t5-t1));
}
+ clReleaseCommandQueue(q);
return NULL;
}
@@ -1173,25 +1178,33 @@ void free_buffers(VisionState *s) {
// free bufs
for (int i=0; icamera_bufs[i]);
+ visionbuf_free(&s->front_camera_bufs[i]);
visionbuf_free(&s->focus_bufs[i]);
visionbuf_free(&s->stats_bufs[i]);
}
- for (int i=0; ifront_camera_bufs[i]);
- }
-
for (int i=0; irgb_bufs[i]);
- }
-
- for (int i=0; irgb_front_bufs[i]);
}
for (int i=0; iyuv_ion[i]);
+ visionbuf_free(&s->yuv_front_ion[i]);
}
+
+ clReleaseMemObject(s->rgb_conv_roi_cl);
+ clReleaseMemObject(s->rgb_conv_result_cl);
+ clReleaseMemObject(s->rgb_conv_filter_cl);
+
+ clReleaseProgram(s->prg_debayer_rear);
+ clReleaseProgram(s->prg_debayer_front);
+ clReleaseKernel(s->krnl_debayer_rear);
+ clReleaseKernel(s->krnl_debayer_front);
+
+ clReleaseProgram(s->prg_rgb_laplacian);
+ clReleaseKernel(s->krnl_rgb_laplacian);
+
}
void party(VisionState *s) {
@@ -1255,7 +1268,7 @@ int main(int argc, char *argv[]) {
signal(SIGINT, (sighandler_t)set_do_exit);
signal(SIGTERM, (sighandler_t)set_do_exit);
- VisionState state = {0};
+ VisionState state = {};
VisionState *s = &state;
clu_init();
diff --git a/selfdrive/camerad/snapshot/snapshot.py b/selfdrive/camerad/snapshot/snapshot.py
index 4ba10bf4..317618c0 100755
--- a/selfdrive/camerad/snapshot/snapshot.py
+++ b/selfdrive/camerad/snapshot/snapshot.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
import os
-import json
import signal
import subprocess
import time
@@ -8,9 +7,7 @@ from PIL import Image
from common.basedir import BASEDIR
from common.params import Params
from selfdrive.camerad.snapshot.visionipc import VisionIPC
-
-with open(BASEDIR + "/selfdrive/controls/lib/alerts_offroad.json") as json_file:
- OFFROAD_ALERTS = json.load(json_file)
+from selfdrive.controls.lib.alertmanager import set_offroad_alert
def jpeg_write(fn, dat):
@@ -26,7 +23,7 @@ def snapshot():
return None
params.put("IsTakingSnapshot", "1")
- params.put("Offroad_IsTakingSnapshot", json.dumps(OFFROAD_ALERTS["Offroad_IsTakingSnapshot"]))
+ set_offroad_alert("Offroad_IsTakingSnapshot", True)
time.sleep(2.0) # Give thermald time to read the param, or if just started give camerad time to start
# Check if camerad is already started
@@ -64,7 +61,7 @@ def snapshot():
proc.communicate()
params.put("IsTakingSnapshot", "0")
- params.delete("Offroad_IsTakingSnapshot")
+ set_offroad_alert("Offroad_IsTakingSnapshot", False)
return ret
diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py
index 09edb031..7701f90a 100644
--- a/selfdrive/car/__init__.py
+++ b/selfdrive/car/__init__.py
@@ -40,8 +40,8 @@ def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor
return tire_stiffness_front, tire_stiffness_rear
-def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None):
- return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc}
+def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None):
+ return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc}
def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS):
diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py
index 478db237..e79b03cc 100644
--- a/selfdrive/car/car_helpers.py
+++ b/selfdrive/car/car_helpers.py
@@ -27,6 +27,13 @@ def get_startup_event(car_recognized, controller_available):
return event
+def get_one_can(logcan):
+ while True:
+ can = messaging.recv_one_retry(logcan)
+ if len(can.can) > 0:
+ return can
+
+
def load_interfaces(brand_names):
ret = {}
for brand_name in brand_names:
@@ -114,7 +121,7 @@ def fingerprint(logcan, sendcan, has_relay):
done = False
while not done:
- a = messaging.get_one_can(logcan)
+ a = get_one_can(logcan)
for can in a.can:
# need to independently try to fingerprint both bus 0 and 1 to work
diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py
index f25cc69f..b81526e9 100644
--- a/selfdrive/car/chrysler/carcontroller.py
+++ b/selfdrive/car/chrysler/carcontroller.py
@@ -11,7 +11,6 @@ class CarController():
self.prev_frame = -1
self.hud_count = 0
self.car_fingerprint = CP.carFingerprint
- self.alert_active = False
self.gone_fast_yet = False
self.steer_rate_limited = False
diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py
index d935e8ea..b6fdb113 100644
--- a/selfdrive/car/chrysler/carstate.py
+++ b/selfdrive/car/chrysler/carstate.py
@@ -103,6 +103,13 @@ class CarState(CarStateBase):
("WHEEL_SPEEDS", 50),
("STEERING", 100),
("ACC_2", 50),
+ ("GEAR", 50),
+ ("ACCEL_GAS_134", 50),
+ ("DASHBOARD", 15),
+ ("STEERING_LEVERS", 10),
+ ("SEATBELT_STATUS", 2),
+ ("DOORS", 1),
+ ("TRACTION_BUTTON", 1),
]
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
@@ -115,6 +122,10 @@ class CarState(CarStateBase):
("CAR_MODEL", "LKAS_HUD", -1),
("LKAS_STATUS_OK", "LKAS_HEARTBIT", -1)
]
- checks = []
+ checks = [
+ ("LKAS_COMMAND", 100),
+ ("LKAS_HEARTBIT", 10),
+ ("LKAS_HUD", 4),
+ ]
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py
index 294b96c5..fbc469eb 100755
--- a/selfdrive/car/chrysler/interface.py
+++ b/selfdrive/car/chrysler/interface.py
@@ -14,8 +14,6 @@ class CarInterface(CarInterfaceBase):
def get_params(candidate, fingerprint=None, has_relay=False, car_fw=None):
if fingerprint is None:
fingerprint = gen_empty_fingerprint()
- if car_fw is None:
- car_fw = []
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "chrysler"
@@ -72,8 +70,6 @@ class CarInterface(CarInterfaceBase):
# speeds
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
- ret.buttonEvents = []
-
# events
events = self.create_common_events(ret, extra_gears=[car.CarState.GearShifter.low],
gas_resume_speed=2.)
diff --git a/selfdrive/car/chrysler/radar_interface.py b/selfdrive/car/chrysler/radar_interface.py
index 40a7c5a7..3139efad 100755
--- a/selfdrive/car/chrysler/radar_interface.py
+++ b/selfdrive/car/chrysler/radar_interface.py
@@ -1,16 +1,15 @@
#!/usr/bin/env python3
-import os
from opendbc.can.parser import CANParser
from cereal import car
from selfdrive.car.interfaces import RadarInterfaceBase
+from selfdrive.car.chrysler.values import DBC
RADAR_MSGS_C = list(range(0x2c2, 0x2d4+2, 2)) # c_ messages 706,...,724
RADAR_MSGS_D = list(range(0x2a2, 0x2b4+2, 2)) # d_ messages
LAST_MSG = max(RADAR_MSGS_C + RADAR_MSGS_D)
NUMBER_MSGS = len(RADAR_MSGS_C) + len(RADAR_MSGS_D)
-def _create_radar_can_parser():
- dbc_f = 'chrysler_pacifica_2017_hybrid_private_fusion.dbc'
+def _create_radar_can_parser(car_fingerprint):
msg_n = len(RADAR_MSGS_C)
# list of [(signal name, message name or number, initial values), (...)]
# [('RADAR_STATE', 1024, 0),
@@ -37,7 +36,7 @@ def _create_radar_can_parser():
[20]*msg_n + # 20Hz (0.05s)
[20]*msg_n)) # 20Hz (0.05s)
- return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1)
+ return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1)
def _address_to_track(address):
if address in RADAR_MSGS_C:
@@ -49,7 +48,7 @@ def _address_to_track(address):
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
super().__init__(CP)
- self.rcp = _create_radar_can_parser()
+ self.rcp = _create_radar_can_parser(CP.carFingerprint)
self.updated_messages = set()
self.trigger_msg = LAST_MSG
diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py
index 2070947c..b7fb53f5 100644
--- a/selfdrive/car/chrysler/values.py
+++ b/selfdrive/car/chrysler/values.py
@@ -4,7 +4,6 @@ from selfdrive.car import dbc_dict
from cereal import car
Ecu = car.CarParams.Ecu
-
class SteerLimitParams:
STEER_MAX = 261 # 262 faults
STEER_DELTA_UP = 3 # 3 is stock. 100 is fine. 200 is too much it seems
@@ -82,32 +81,18 @@ FINGERPRINTS = {
DBC = {
- CAR.PACIFICA_2017_HYBRID: dbc_dict(
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
- CAR.PACIFICA_2018: dbc_dict( # Same DBC file works.
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
- CAR.PACIFICA_2020: dbc_dict( # Same DBC file works.
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
- CAR.PACIFICA_2018_HYBRID: dbc_dict( # Same DBC file works.
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
- CAR.PACIFICA_2019_HYBRID: dbc_dict( # Same DBC file works.
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
- CAR.JEEP_CHEROKEE: dbc_dict( # Same DBC file works.
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
- CAR.JEEP_CHEROKEE_2019: dbc_dict( # Same DBC file works.
- 'chrysler_pacifica_2017_hybrid', # 'pt'
- 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar'
+ CAR.PACIFICA_2017_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
+ CAR.PACIFICA_2018: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
+ CAR.PACIFICA_2020: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
+ CAR.PACIFICA_2018_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
+ CAR.PACIFICA_2019_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
+ CAR.JEEP_CHEROKEE: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
+ CAR.JEEP_CHEROKEE_2019: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'),
}
STEER_THRESHOLD = 120
ECU_FINGERPRINT = {
- Ecu.fwdCamera: [0x292], # lkas cmd
+ Ecu.fwdCamera: [0x292], # lkas cmd
}
diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py
index 59e61914..6d6c82f0 100755
--- a/selfdrive/car/ford/interface.py
+++ b/selfdrive/car/ford/interface.py
@@ -14,7 +14,7 @@ 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
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "ford"
ret.safetyModel = car.CarParams.SafetyModel.ford
diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py
index b01814bc..20a435b0 100755
--- a/selfdrive/car/ford/radar_interface.py
+++ b/selfdrive/car/ford/radar_interface.py
@@ -8,14 +8,13 @@ from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_MSGS = list(range(0x500, 0x540))
def _create_radar_can_parser(car_fingerprint):
- dbc_f = DBC[car_fingerprint]['radar']
msg_n = len(RADAR_MSGS)
signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n,
RADAR_MSGS * 3,
[0] * msg_n + [0] * msg_n + [0] * msg_n))
checks = list(zip(RADAR_MSGS, [20]*msg_n))
- return CANParser(dbc_f, signals, checks, 1)
+ return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1)
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index 1328b11f..0fc3d278 100755
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -16,13 +16,13 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "gm"
- ret.safetyModel = car.CarParams.SafetyModel.gm # default to gm
+ ret.safetyModel = car.CarParams.SafetyModel.gm
ret.enableCruise = False # stock cruise control is kept off
- # GM port is considered a community feature, since it disables AEB;
+ # GM port is a community feature
# TODO: make a port that uses a car harness and it only intercepts the camera
ret.communityFeature = True
diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py
index f2f8c3ce..dc2c2f7b 100755
--- a/selfdrive/car/gm/radar_interface.py
+++ b/selfdrive/car/gm/radar_interface.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
from __future__ import print_function
import math
-import time
from cereal import car
from opendbc.can.parser import CANParser
from selfdrive.car.gm.values import DBC, CAR, CanBus
@@ -17,30 +16,28 @@ NUM_SLOTS = 20
LAST_RADAR_MSG = RADAR_HEADER_MSG + NUM_SLOTS
def create_radar_can_parser(car_fingerprint):
-
- dbc_f = DBC[car_fingerprint]['radar']
- if car_fingerprint in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS):
- # C1A-ARS3-A by Continental
- radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS))
- signals = list(zip(['FLRRNumValidTargets',
- 'FLRRSnsrBlckd', 'FLRRYawRtPlsblityFlt',
- 'FLRRHWFltPrsntInt', 'FLRRAntTngFltPrsnt',
- 'FLRRAlgnFltPrsnt', 'FLRRSnstvFltPrsntInt'] +
- ['TrkRange'] * NUM_SLOTS + ['TrkRangeRate'] * NUM_SLOTS +
- ['TrkRangeAccel'] * NUM_SLOTS + ['TrkAzimuth'] * NUM_SLOTS +
- ['TrkWidth'] * NUM_SLOTS + ['TrkObjectID'] * NUM_SLOTS,
- [RADAR_HEADER_MSG] * 7 + radar_targets * 6,
- [0] * 7 +
- [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS +
- [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS +
- [0.0] * NUM_SLOTS + [0] * NUM_SLOTS))
-
- checks = []
-
- return CANParser(dbc_f, signals, checks, CanBus.OBSTACLE)
- else:
+ if car_fingerprint not in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS):
return None
+ # C1A-ARS3-A by Continental
+ radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS))
+ signals = list(zip(['FLRRNumValidTargets',
+ 'FLRRSnsrBlckd', 'FLRRYawRtPlsblityFlt',
+ 'FLRRHWFltPrsntInt', 'FLRRAntTngFltPrsnt',
+ 'FLRRAlgnFltPrsnt', 'FLRRSnstvFltPrsntInt'] +
+ ['TrkRange'] * NUM_SLOTS + ['TrkRangeRate'] * NUM_SLOTS +
+ ['TrkRangeAccel'] * NUM_SLOTS + ['TrkAzimuth'] * NUM_SLOTS +
+ ['TrkWidth'] * NUM_SLOTS + ['TrkObjectID'] * NUM_SLOTS,
+ [RADAR_HEADER_MSG] * 7 + radar_targets * 6,
+ [0] * 7 +
+ [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS +
+ [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS +
+ [0.0] * NUM_SLOTS + [0] * NUM_SLOTS))
+
+ checks = []
+
+ return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CanBus.OBSTACLE)
+
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
super().__init__(CP)
@@ -53,8 +50,7 @@ class RadarInterface(RadarInterfaceBase):
def update(self, can_strings):
if self.rcp is None:
- time.sleep(self.radar_ts) # nothing to do
- return car.RadarData.new_message()
+ return super().update(None)
vls = self.rcp.update_strings(can_strings)
self.updated_messages.update(vls)
diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py
index 4845e482..4aaa98aa 100644
--- a/selfdrive/car/honda/carstate.py
+++ b/selfdrive/car/honda/carstate.py
@@ -172,7 +172,7 @@ class CarState(CarStateBase):
self.v_cruise_pcm_prev = 0
self.cruise_mode = 0
- def update(self, cp, cp_cam):
+ def update(self, cp, cp_cam, cp_body):
ret = car.CarState.new_message()
# car params
@@ -322,6 +322,12 @@ class CarState(CarStateBase):
self.stock_hud = cp_cam.vl["ACC_HUD"]
self.stock_brake = cp_cam.vl["BRAKE_COMMAND"]
+ if self.CP.carFingerprint in (CAR.CRV_5G, ):
+ # BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0
+ # more info here: https://github.com/commaai/openpilot/pull/1867
+ ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]['BSM_ALERT'] == 1
+ ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]['BSM_ALERT'] == 1
+
return ret
@staticmethod
@@ -354,3 +360,17 @@ class CarState(CarStateBase):
bus_cam = 1 if CP.carFingerprint in HONDA_BOSCH and not CP.isPandaBlack else 2
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, bus_cam)
+
+ @staticmethod
+ def get_body_can_parser(CP):
+ signals = []
+ checks = []
+
+ if CP.carFingerprint == CAR.CRV_5G:
+ signals += [("BSM_ALERT", "BSM_STATUS_RIGHT", 0),
+ ("BSM_ALERT", "BSM_STATUS_LEFT", 0)]
+
+ bus_body = 0 # B-CAN is forwarded to ACC-CAN radar side (CAN 0 on fake ethernet port)
+ return CANParser(DBC[CP.carFingerprint]['body'], signals, checks, bus_body)
+
+ return None
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index 7e5c46c8..ac8bfe3b 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -83,7 +83,7 @@ class CarInterface(CarInterfaceBase):
self.compute_gb = compute_gb_honda
@staticmethod
- def compute_gb(accel, speed):
+ def compute_gb(accel, speed): # pylint: disable=method-hidden
raise NotImplementedError
@staticmethod
@@ -189,9 +189,9 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 1.
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
ret.longitudinalTuning.kpBP = [0., 5., 35.]
- ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5]
+ ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5]
ret.longitudinalTuning.kiBP = [0., 35.]
- ret.longitudinalTuning.kiV = [0.54, 0.36]
+ ret.longitudinalTuning.kiV = [0.18, 0.12]
elif candidate in (CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH):
stop_and_go = True
@@ -426,10 +426,12 @@ class CarInterface(CarInterfaceBase):
# ******************* do can recv *******************
self.cp.update_strings(can_strings)
self.cp_cam.update_strings(can_strings)
+ if self.cp_body:
+ self.cp_body.update_strings(can_strings)
- ret = self.CS.update(self.cp, self.cp_cam)
+ ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
- ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
+ ret.canValid = self.cp.can_valid and self.cp_cam.can_valid and (self.cp_body is None or self.cp_body.can_valid)
ret.yawRate = self.VM.yaw_rate(ret.steeringAngle * CV.DEG_TO_RAD, ret.vEgo)
# FIXME: read sendcan for brakelights
brakelights_threshold = 0.02 if self.CS.CP.carFingerprint == CAR.CIVIC else 0.1
diff --git a/selfdrive/car/honda/radar_interface.py b/selfdrive/car/honda/radar_interface.py
index a921534c..6acec73d 100755
--- a/selfdrive/car/honda/radar_interface.py
+++ b/selfdrive/car/honda/radar_interface.py
@@ -1,12 +1,10 @@
#!/usr/bin/env python3
-import os
-import time
from cereal import car
from opendbc.can.parser import CANParser
from selfdrive.car.interfaces import RadarInterfaceBase
+from selfdrive.car.honda.values import DBC
-def _create_nidec_can_parser():
- dbc_f = 'acura_ilx_2016_nidec.dbc'
+def _create_nidec_can_parser(car_fingerprint):
radar_messages = [0x400] + list(range(0x430, 0x43A)) + list(range(0x440, 0x446))
signals = list(zip(['RADAR_STATE'] +
['LONG_DIST'] * 16 + ['NEW_TRACK'] * 16 + ['LAT_DIST'] * 16 +
@@ -14,8 +12,7 @@ def _create_nidec_can_parser():
[0x400] + radar_messages[1:] * 4,
[0] + [255] * 16 + [1] * 16 + [0] * 16 + [0] * 16))
checks = list(zip([0x445], [20]))
- fn = os.path.splitext(dbc_f)[0].encode('utf8')
- return CANParser(fn, signals, checks, 1)
+ return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1)
class RadarInterface(RadarInterfaceBase):
@@ -30,7 +27,10 @@ class RadarInterface(RadarInterfaceBase):
self.delay = int(round(0.1 / CP.radarTimeStep)) # 0.1s delay of radar
# Nidec
- self.rcp = _create_nidec_can_parser()
+ if self.radar_off_can:
+ self.rcp = None
+ else:
+ self.rcp = _create_nidec_can_parser(CP.carFingerprint)
self.trigger_msg = 0x445
self.updated_messages = set()
@@ -38,9 +38,7 @@ class RadarInterface(RadarInterfaceBase):
# in Bosch radar and we are only steering for now, so sleep 0.05s to keep
# radard at 20Hz and return no points
if self.radar_off_can:
- if 'NO_RADAR_SLEEP' not in os.environ:
- time.sleep(self.radar_ts)
- return car.RadarData.new_message()
+ return super().update(None)
vls = self.rcp.update_strings(can_strings)
self.updated_messages.update(vls)
diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py
index 32bc2d37..713c38ae 100644
--- a/selfdrive/car/honda/values.py
+++ b/selfdrive/car/honda/values.py
@@ -885,10 +885,23 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TXM-A050\x00\x00',
+ b'36161-TXM-A060\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TXM-A230\x00\x00',
],
+ (Ecu.vsa, 0x18da28f1, None): [
+ b'57114-TXM-A040\x00\x00',
+ ],
+ (Ecu.shiftByWire, 0x18da0bf1, None): [
+ b'54008-TWA-A910\x00\x00',
+ ],
+ (Ecu.gateway, 0x18daeff1, None): [
+ b'38897-TXM-A020\x00\x00',
+ ],
+ (Ecu.combinationMeter, 0x18da60f1, None): [
+ b'78109-TXM-A020\x00\x00',
+ ],
},
CAR.HRV: {
(Ecu.gateway, 0x18daeff1, None): [b'38897-T7A-A010\x00\x00'],
@@ -909,7 +922,7 @@ DBC = {
CAR.CIVIC_BOSCH: dbc_dict('honda_civic_hatchback_ex_2017_can_generated', None),
CAR.CIVIC_BOSCH_DIESEL: dbc_dict('honda_civic_sedan_16_diesel_2019_can_generated', None),
CAR.CRV: dbc_dict('honda_crv_touring_2016_can_generated', 'acura_ilx_2016_nidec'),
- CAR.CRV_5G: dbc_dict('honda_crv_ex_2017_can_generated', None),
+ CAR.CRV_5G: dbc_dict('honda_crv_ex_2017_can_generated', None, body_dbc='honda_crv_ex_2017_body_generated'),
CAR.CRV_EU: dbc_dict('honda_crv_executive_2016_can_generated', 'acura_ilx_2016_nidec'),
CAR.CRV_HYBRID: dbc_dict('honda_crv_hybrid_2019_can_generated', None),
CAR.FIT: dbc_dict('honda_fit_ex_2018_can_generated', 'acura_ilx_2016_nidec'),
@@ -974,4 +987,4 @@ ECU_FINGERPRINT = {
Ecu.fwdCamera: [0xE4, 0x194], # steer torque cmd
}
-HONDA_BOSCH = [CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, CAR.CRV_HYBRID, CAR.INSIGHT]
+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])
diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py
index 1e4ad401..61d9de05 100644
--- a/selfdrive/car/hyundai/carstate.py
+++ b/selfdrive/car/hyundai/carstate.py
@@ -41,8 +41,7 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = cp.vl["SCC11"]['SCCInfoDisplay'] == 4.
if ret.cruiseState.enabled:
- is_set_speed_in_mph = int(cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"])
- speed_conv = CV.MPH_TO_MS if is_set_speed_in_mph else CV.KPH_TO_MS
+ speed_conv = CV.MPH_TO_MS if cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] else CV.KPH_TO_MS
ret.cruiseState.speed = cp.vl["SCC11"]['VSetDis'] * speed_conv
else:
ret.cruiseState.speed = 0
@@ -282,7 +281,7 @@ class CarState(CarStateBase):
signals = [
# sig_name, sig_address, default
- ("CF_Lkas_Bca_R", "LKAS11", 0),
+ ("CF_Lkas_LdwsActivemode", "LKAS11", 0),
("CF_Lkas_LdwsSysState", "LKAS11", 0),
("CF_Lkas_SysWarning", "LKAS11", 0),
("CF_Lkas_LdwsLHWarning", "LKAS11", 0),
@@ -299,6 +298,8 @@ class CarState(CarStateBase):
("CF_Lkas_LdwsOpt_USM", "LKAS11", 0)
]
- checks = []
+ checks = [
+ ("LKAS11", 100)
+ ]
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py
index b5969d01..1e7b7510 100644
--- a/selfdrive/car/hyundai/hyundaican.py
+++ b/selfdrive/car/hyundai/hyundaican.py
@@ -20,7 +20,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
values["CF_Lkas_Chksum"] = 0
if car_fingerprint in [CAR.SONATA, CAR.PALISADE]:
- values["CF_Lkas_Bca_R"] = int(left_lane) + (int(right_lane) << 1)
+ values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
values["CF_Lkas_LdwsOpt_USM"] = 2
# FcwOpt_USM 5 = Orange blinking car + lanes
@@ -40,9 +40,9 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
elif car_fingerprint == CAR.HYUNDAI_GENESIS:
# This field is actually LdwsActivemode
# Genesis and Optima fault when forwarding while engaged
- values["CF_Lkas_Bca_R"] = 2
+ values["CF_Lkas_LdwsActivemode"] = 2
elif car_fingerprint == CAR.KIA_OPTIMA:
- values["CF_Lkas_Bca_R"] = 0
+ values["CF_Lkas_LdwsActivemode"] = 0
dat = packer.make_can_msg("LKAS11", 0, values)[2]
diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py
index c6b4780f..553d48a2 100644
--- a/selfdrive/car/hyundai/interface.py
+++ b/selfdrive/car/hyundai/interface.py
@@ -82,6 +82,13 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]]
ret.minSteerSpeed = 60 * CV.KPH_TO_MS
+ elif candidate == CAR.GENESIS_G70:
+ ret.lateralTuning.pid.kf = 0.00005
+ ret.mass = 1640. + STD_CARGO_KG
+ ret.wheelbase = 2.84
+ ret.steerRatio = 16.5
+ ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]]
elif candidate == CAR.GENESIS_G80:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 2060. + STD_CARGO_KG
@@ -111,10 +118,10 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KONA:
- ret.lateralTuning.pid.kf = 0.00006
+ ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1275. + STD_CARGO_KG
ret.wheelbase = 2.7
- ret.steerRatio = 13.73 # Spec
+ ret.steerRatio = 13.73 * 1.15 # Spec
tire_stiffness_factor = 0.385
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
@@ -143,9 +150,18 @@ class CarInterface(CarInterfaceBase):
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]]
+ elif candidate == CAR.VELOSTER:
+ ret.lateralTuning.pid.kf = 0.00005
+ ret.mass = 3558. * CV.LB_TO_KG
+ ret.wheelbase = 2.80
+ ret.steerRatio = 13.75 * 1.15
+ 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]]
# 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]:
+ if candidate in [CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_2019,
+ CAR.KIA_OPTIMA, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70]:
ret.safetyModel = car.CarParams.SafetyModel.hyundaiLegacy
ret.centerToFront = ret.wheelbase * 0.4
@@ -170,9 +186,6 @@ class CarInterface(CarInterfaceBase):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
- # TODO: button presses
- ret.buttonEvents = []
-
events = self.create_common_events(ret)
#TODO: addd abs(self.CS.angle_steers) > 90 to 'steerTempUnavailable' event
diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py
index b5bdcd83..fdbe837a 100644
--- a/selfdrive/car/hyundai/radar_interface.py
+++ b/selfdrive/car/hyundai/radar_interface.py
@@ -1,6 +1,4 @@
#!/usr/bin/env python3
-import os
-import time
from cereal import car
from opendbc.can.parser import CANParser
from selfdrive.car.interfaces import RadarInterfaceBase
@@ -33,10 +31,7 @@ class RadarInterface(RadarInterfaceBase):
def update(self, can_strings):
if self.radar_off_can:
- if 'NO_RADAR_SLEEP' not in os.environ:
- time.sleep(0.05) # radard runs on RI updates
-
- return car.RadarData.new_message()
+ return super().update(None)
vls = self.rcp.update_strings(can_strings)
self.updated_messages.update(vls)
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py
index b993d620..9a39cb8f 100644
--- a/selfdrive/car/hyundai/values.py
+++ b/selfdrive/car/hyundai/values.py
@@ -17,6 +17,7 @@ class SteerLimitParams:
class CAR:
ELANTRA = "HYUNDAI ELANTRA LIMITED ULTIMATE 2017"
ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT"
+ GENESIS_G70 = "GENESIS G70 2018"
GENESIS_G80 = "GENESIS G80 2017"
GENESIS_G90 = "GENESIS G90 2017"
HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016"
@@ -27,13 +28,13 @@ class CAR:
KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
KIA_SORENTO = "KIA SORENTO GT LINE 2018"
KIA_STINGER = "KIA STINGER GT2 2018"
- KONA = "HYUNDAI KONA 2019"
+ KONA = "HYUNDAI KONA 2020"
KONA_EV = "HYUNDAI KONA ELECTRIC 2019"
SANTA_FE = "HYUNDAI SANTA FE LIMITED 2019"
- SANTA_FE_1 = "HYUNDAI SANTA FE has no scc"
SONATA = "HYUNDAI SONATA 2020"
SONATA_2019 = "HYUNDAI SONATA 2019"
PALISADE = "HYUNDAI PALISADE 2020"
+ VELOSTER = "HYUNDAI VELOSTER 2019"
class Buttons:
@@ -85,20 +86,18 @@ FINGERPRINTS = {
CAR.SONATA_2019: [
{66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1397: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2008: 8, 2009: 8, 2012: 8, 2013: 8, 2014: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8},
],
- CAR.KIA_OPTIMA: [
- {
- 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1186: 2, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 1952: 8, 1960: 8, 1988: 8, 1996: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
- },
- {
- 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 897: 8, 899: 8, 902: 8, 903: 6, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1265: 4, 1268: 8, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1491: 8, 1492: 8
- },
- ],
+ CAR.KIA_OPTIMA: [{
+ 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 558: 8, 593: 8, 608: 8, 640: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 909: 8, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1186: 2, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1268: 8, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1492: 8, 1530: 8, 1532: 5, 1792: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
+ }],
CAR.KIA_SORENTO: [{
67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1384: 8, 1407: 8, 1411: 8, 1419: 8, 1425: 2, 1427: 6, 1444: 8, 1456: 4, 1470: 8, 1489: 1
}],
CAR.KIA_STINGER: [{
67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 576: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 4, 1379: 8, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1456: 4, 1470: 8
}],
+ CAR.GENESIS_G70: [{
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 544: 8, 576: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832:8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1168: 7, 1170: 8, 1173:8, 1184: 8, 1186: 2, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1379: 8, 1384: 8, 1407: 8, 1419:8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 2015: 8
+ }],
CAR.GENESIS_G80: [{
67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1024: 2, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8
},
@@ -119,9 +118,9 @@ FINGERPRINTS = {
},
{
68:8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 8, 576:8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1473: 8, 1476: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8
- }],
+ }],
CAR.KONA: [{
- 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 354: 3, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 909: 8, 916: 8, 1040: 8, 1078: 4, 1107: 5, 1136: 8, 1156: 8, 1170: 8, 1173: 8, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1384: 8, 1394: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 2004: 8, 2009: 8, 2012: 8
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 354: 3, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832 : 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1170: 8, 1173: 8, 1186: 2, 1191: 2, 1193: 8, 1265: 4,1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1378: 8, 1384: 8, 1394: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8
}],
CAR.KONA_EV: [{
127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8
@@ -136,14 +135,20 @@ FINGERPRINTS = {
68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 576: 8, 593: 8, 688: 5, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 909: 8, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1168: 7, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1265: 4, 1268: 8, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1371: 8, 1407: 8, 1419: 8, 1420: 8, 1425: 2, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1476: 8, 1535: 8
}],
CAR.PALISADE: [{
- 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 549: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1123: 8, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 2000: 8, 2005: 8, 2008: 8
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 549: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1123: 8, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8
}],
+ CAR.VELOSTER: [{
+ 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 558: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1181: 5, 1186: 2, 1191: 2, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1378: 4, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 1872: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
+ }]
}
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.GENESIS_G70, CAR.KONA]
+
FW_VERSIONS = {
CAR.SONATA: {
(Ecu.fwdRadar, 0x7d0, None): [
@@ -181,7 +186,10 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [ b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00',],
(Ecu.eps, 0x7d4, None): [b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104'],
(Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822'],
- (Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0'],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ ],
},
CAR.KIA_OPTIMA_H: {
(Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ',],
@@ -190,16 +198,58 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00DEP MFC AT USA LHD 1.00 1.01 95740-G5010 170424',],
(Ecu.transmission, 0x7e1, None): [b"\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\xf4'\\\x91",],
},
- CAR.PALISADE: {
- (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04',],
+ CAR.PALISADE: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04',
+ b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04',
+ ],
(Ecu.esp, 0x7d1, None): [
b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330',
b'\xf1\x00LX ESC \v 102\x19\x05\a 58910-S8330\xf1\xa01.02',
+ b'\xf1\x00LX ESC \v 103\x19\t\x10 58910-S8360\xf1\xa01.03',
],
(Ecu.engine, 0x7e0, None): [b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00',],
(Ecu.eps, 0x7d4, None): [b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103',],
- (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.03 99211-S8100 190125',],
- (Ecu.transmission, 0x7e1, None): [b'\xf1\x87LDKVBN424201KF26\xba\xaa\x9a\xa9\x99\x99\x89\x98\x89\x99\xa8\x99\x88\x99\x98\x89\x88\x99\xa8\x89v\x7f\xf7\xffwf_\xffq\xa6\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.03 99211-S8100 190125',
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.05 99211-S8100 190909',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87LDKVBN424201KF26\xba\xaa\x9a\xa9\x99\x99\x89\x98\x89\x99\xa8\x99\x88\x99\x98\x89\x88\x99\xa8\x89v\x7f\xf7\xffwf_\xffq\xa6\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',
+ b'\xf1\x87LDLVBN560098KF26\x86fff\x87vgfg\x88\x96xfw\x86gfw\x86g\x95\xf6\xffeU_\xff\x92c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',
+ ],
+ },
+ CAR.VELOSTER: {
+ (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00JS__ SCC H-CUP 1.00 1.02 95650-J3200 ', ],
+ (Ecu.esp, 0x7d1, None): [b'\xf1\x00\x00\x00\x00\x00\x00\x00', ],
+ (Ecu.engine, 0x7e0, None): [b'\x01TJS-JNU06F200H0A', ],
+ (Ecu.eps, 0x7d4, None): [b'\xf1\x00JSL MDPS C 1.00 1.03 56340-J3000 8308', ],
+ (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00JS LKAS AT USA LHD 1.00 1.02 95740-J3000 K32', ],
+ (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJS0T16NS1\xba\x02\xb8\x80', ],
+ },
+ CAR.GENESIS_G70: {
+ (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 \xf1\xa01.02', ],
+ (Ecu.esp, 0x7d1, None): [b'\xf1\x00\x00\x00\x00\x00\x00\x00', ],
+ (Ecu.engine, 0x7e0, None): [b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00', ],
+ (Ecu.eps, 0x7d4, None): [b'\xf1\x00IK MDPS R 1.00 1.06 57700-G9420 4I4VL106', ],
+ (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00IK MFC AT USA LHD 1.00 1.01 95740-G9000 170920', ],
+ (Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDJLT17895112DN4\x88fVf\x99\x88\x88\x88\x87fVe\x88vhwwUFU\x97eFex\x99\xff\xb7\x82\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda', ],
+ },
+ CAR.KONA: {
+ (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00OS__ SCC F-CUP 1.00 1.00 95655-J9200 \xf1\xa01.00', ],
+ (Ecu.esp, 0x7d1, None): [b'\xf1\x816V5RAK00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00\xf1\xa01.05', ],
+ (Ecu.engine, 0x7e0, None): [b'"\x01TOS-0NU06F301J02', ],
+ (Ecu.eps, 0x7d4, None): [b'\xf1\x00OS MDPS C 1.00 1.05 56310J9030\x00 4OSDC105', ],
+ (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00OS9 LKAS AT USA LHD 1.00 1.00 95740-J9300 g21', ],
+ (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2VE051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VE051\x00\x00DOS4T16NS3\x00\x00\x00\x00', ],
+ },
+ CAR.KIA_OPTIMA: {
+ (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 '],
+ (Ecu.esp, 0x7d1, None): [b'\xf1\x00JF ESC \v 11 \x18\x030 58920-D5180',],
+ (Ecu.engine, 0x7e0, None): [b'\x01TJFAJNU06F201H03'],
+ (Ecu.eps, 0x7d4, None): [b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409'],
+ (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00JFA LKAS AT USA LHD 1.00 1.02 95895-D5000 h31'],
+ (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJF0T16NL0\t\xd2GW'],
}
}
@@ -210,21 +260,22 @@ CHECKSUM = {
FEATURES = {
# which message has the gear
- "use_cluster_gears": [CAR.ELANTRA, CAR.KONA, CAR.ELANTRA_GT_I30],
- "use_tcu_gears": [CAR.KIA_OPTIMA, CAR.SONATA_2019],
- "use_elect_gears": [CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ],
+ "use_cluster_gears": set([CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA]),
+ "use_tcu_gears": set([CAR.KIA_OPTIMA, CAR.SONATA_2019, CAR.VELOSTER]),
+ "use_elect_gears": set([CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ]),
# these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
- "use_fca": [CAR.SONATA, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ, CAR.KONA, CAR.KONA_EV, CAR.KIA_FORTE, CAR.PALISADE],
+ "use_fca": set([CAR.SONATA, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_FORTE, CAR.PALISADE, CAR.GENESIS_G70, CAR.KONA]),
- "use_bsm": [CAR.SONATA, CAR.PALISADE, CAR.HYUNDAI_GENESIS, CAR.GENESIS_G80, CAR.GENESIS_G90],
+ "use_bsm": set([CAR.SONATA, CAR.PALISADE, CAR.HYUNDAI_GENESIS, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.KONA]),
}
-EV_HYBRID = [CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV]
+EV_HYBRID = set([CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV])
DBC = {
CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None),
CAR.ELANTRA_GT_I30: dbc_dict('hyundai_kia_generic', None),
+ CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None),
CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None),
CAR.GENESIS_G90: dbc_dict('hyundai_kia_generic', None),
CAR.HYUNDAI_GENESIS: dbc_dict('hyundai_kia_generic', None),
@@ -241,6 +292,7 @@ DBC = {
CAR.SONATA: dbc_dict('hyundai_kia_generic', None),
CAR.SONATA_2019: dbc_dict('hyundai_kia_generic', None),
CAR.PALISADE: dbc_dict('hyundai_kia_generic', None),
+ CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None),
}
STEER_THRESHOLD = 150
diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py
index c73aa938..bd5c8eb4 100644
--- a/selfdrive/car/interfaces.py
+++ b/selfdrive/car/interfaces.py
@@ -27,6 +27,7 @@ class CarInterfaceBase():
self.CS = CarState(CP)
self.cp = self.CS.get_can_parser(CP)
self.cp_cam = self.CS.get_cam_can_parser(CP)
+ self.cp_body = self.CS.get_body_can_parser(CP)
self.CC = None
if CarController is not None:
@@ -41,7 +42,7 @@ class CarInterfaceBase():
raise NotImplementedError
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
raise NotImplementedError
# returns a set of default params to avoid repetition in car specific params
@@ -136,13 +137,12 @@ class RadarInterfaceBase():
self.pts = {}
self.delay = 0
self.radar_ts = CP.radarTimeStep
+ self.no_radar_sleep = 'NO_RADAR_SLEEP' in os.environ
def update(self, can_strings):
ret = car.RadarData.new_message()
-
- if 'NO_RADAR_SLEEP' not in os.environ:
+ if not self.no_radar_sleep:
time.sleep(self.radar_ts) # radard runs on RI updates
-
return ret
class CarStateBase:
@@ -175,3 +175,7 @@ class CarStateBase:
@staticmethod
def get_cam_can_parser(CP):
return None
+
+ @staticmethod
+ def get_body_can_parser(CP):
+ return None
diff --git a/selfdrive/car/mazda/carstate.py b/selfdrive/car/mazda/carstate.py
index 18a26cc3..03f3a026 100644
--- a/selfdrive/car/mazda/carstate.py
+++ b/selfdrive/car/mazda/carstate.py
@@ -162,8 +162,8 @@ class CarState(CarStateBase):
@staticmethod
def get_cam_can_parser(CP):
- signals = [ ]
- checks = [ ]
+ signals = []
+ checks = []
if CP.carFingerprint == CAR.CX5:
signals += [
diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py
index 059d7341..dfa959da 100755
--- a/selfdrive/car/mazda/interface.py
+++ b/selfdrive/car/mazda/interface.py
@@ -15,7 +15,7 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "mazda"
@@ -70,9 +70,6 @@ class CarInterface(CarInterfaceBase):
ret = self.CS.update(self.cp, self.cp_cam)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
- # TODO: button presses
- ret.buttonEvents = []
-
# events
events = self.create_common_events(ret)
diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py
index 617f7e23..d0298ec8 100755
--- a/selfdrive/car/mock/interface.py
+++ b/selfdrive/car/mock/interface.py
@@ -33,7 +33,7 @@ class CarInterface(CarInterfaceBase):
return accel
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "mock"
ret.safetyModel = car.CarParams.SafetyModel.noOutput
diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py
index 5d988cb9..5838d67a 100644
--- a/selfdrive/car/nissan/carcontroller.py
+++ b/selfdrive/car/nissan/carcontroller.py
@@ -2,7 +2,7 @@ from cereal import car
from common.numpy_fast import clip, interp
from selfdrive.car.nissan import nissancan
from opendbc.can.packer import CANPacker
-from selfdrive.car.nissan.values import CAR
+from selfdrive.car.nissan.values import CAR, STEER_THRESHOLD
# Steer angle limits
ANGLE_DELTA_BP = [0., 5., 15.]
@@ -53,7 +53,11 @@ class CarController():
else:
# Scale max torque based on how much torque the driver is applying to the wheel
self.lkas_max_torque = max(
- 0, LKAS_MAX_TORQUE - 0.4 * abs(CS.out.steeringTorque))
+ # Scale max torque down to half LKAX_MAX_TORQUE as a minimum
+ LKAS_MAX_TORQUE * 0.5,
+ # Start scaling torque at STEER_THRESHOLD
+ LKAS_MAX_TORQUE - 0.6 * max(0, abs(CS.out.steeringTorque) - STEER_THRESHOLD)
+ )
else:
apply_angle = CS.out.steeringAngle
diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py
index d43db51b..f2076183 100644
--- a/selfdrive/car/nissan/carstate.py
+++ b/selfdrive/car/nissan/carstate.py
@@ -1,4 +1,5 @@
import copy
+from collections import deque
from cereal import car
from opendbc.can.can_define import CANDefine
from selfdrive.car.interfaces import CarStateBase
@@ -6,12 +7,14 @@ from selfdrive.config import Conversions as CV
from opendbc.can.parser import CANParser
from selfdrive.car.nissan.values import CAR, DBC, STEER_THRESHOLD
+TORQUE_SAMPLES = 12
class CarState(CarStateBase):
def __init__(self, CP):
super().__init__(CP)
can_define = CANDefine(DBC[CP.carFingerprint]['pt'])
+ self.steeringTorqueSamples = deque(TORQUE_SAMPLES*[0], TORQUE_SAMPLES)
self.shifter_values = can_define.dv["GEARBOX"]["GEAR_SHIFTER"]
def update(self, cp, cp_adas, cp_cam):
@@ -60,7 +63,9 @@ class CarState(CarStateBase):
ret.cruiseState.speed = speed * conversion
ret.steeringTorque = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_DRIVER"]
- ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
+ self.steeringTorqueSamples.append(ret.steeringTorque)
+ # Filtering driver torque to prevent steeringPressed false positives
+ ret.steeringPressed = bool(abs(sum(self.steeringTorqueSamples) / TORQUE_SAMPLES) > STEER_THRESHOLD)
ret.steeringAngle = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"]
diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py
index cc9547ae..9c419c5a 100644
--- a/selfdrive/car/nissan/interface.py
+++ b/selfdrive/car/nissan/interface.py
@@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "nissan"
diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py
index 4271b7f0..0630a8cb 100644
--- a/selfdrive/car/nissan/values.py
+++ b/selfdrive/car/nissan/values.py
@@ -2,7 +2,7 @@
from selfdrive.car import dbc_dict
-STEER_THRESHOLD = 1.75
+STEER_THRESHOLD = 1.0
class CAR:
XTRAIL = "NISSAN X-TRAIL 2017"
diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py
index 06863b71..744fd0bc 100644
--- a/selfdrive/car/subaru/carcontroller.py
+++ b/selfdrive/car/subaru/carcontroller.py
@@ -1,7 +1,6 @@
-#from common.numpy_fast import clip
from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.subaru import subarucan
-from selfdrive.car.subaru.values import DBC
+from selfdrive.car.subaru.values import DBC, PREGLOBAL_CARS
from opendbc.can.packer import CANPacker
@@ -18,49 +17,71 @@ class CarControllerParams():
class CarController():
def __init__(self, dbc_name, CP, VM):
- self.lkas_active = False
self.apply_steer_last = 0
self.es_distance_cnt = -1
+ self.es_accel_cnt = -1
self.es_lkas_cnt = -1
+ self.fake_button_prev = 0
self.steer_rate_limited = False
self.params = CarControllerParams()
self.packer = CANPacker(DBC[CP.carFingerprint]['pt'])
def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line):
- """ Controls thread """
- P = self.params
-
- # Send CAN commands.
can_sends = []
- ### STEER ###
+ # *** steering ***
+ if (frame % self.params.STEER_STEP) == 0:
- if (frame % P.STEER_STEP) == 0:
-
- final_steer = actuators.steer if enabled else 0.
- apply_steer = int(round(final_steer * P.STEER_MAX))
+ apply_steer = int(round(actuators.steer * self.params.STEER_MAX))
# limits due to driver torque
new_steer = int(round(apply_steer))
- apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, P)
+ apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
self.steer_rate_limited = new_steer != apply_steer
if not enabled:
apply_steer = 0
- can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, P.STEER_STEP))
+ if CS.CP.carFingerprint in PREGLOBAL_CARS:
+ can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, self.params.STEER_STEP))
+ else:
+ can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, self.params.STEER_STEP))
self.apply_steer_last = apply_steer
- if self.es_distance_cnt != CS.es_distance_msg["Counter"]:
- can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, pcm_cancel_cmd))
- self.es_distance_cnt = CS.es_distance_msg["Counter"]
- if self.es_lkas_cnt != CS.es_lkas_msg["Counter"]:
- can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, visual_alert, left_line, right_line))
- self.es_lkas_cnt = CS.es_lkas_msg["Counter"]
+ # *** alerts and pcm cancel ***
+
+ if CS.CP.carFingerprint in PREGLOBAL_CARS:
+ if self.es_accel_cnt != CS.es_accel_msg["Counter"]:
+ # 1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 = resume deep
+ # disengage ACC when OP is disengaged
+ if pcm_cancel_cmd:
+ fake_button = 1
+ # turn main on if off and past start-up state
+ elif not CS.out.cruiseState.available and CS.ready:
+ fake_button = 1
+ else:
+ fake_button = CS.button
+
+ # unstick previous mocked button press
+ if fake_button == 1 and self.fake_button_prev == 1:
+ fake_button = 0
+ self.fake_button_prev = fake_button
+
+ can_sends.append(subarucan.create_es_throttle_control(self.packer, fake_button, CS.es_accel_msg))
+ self.es_accel_cnt = CS.es_accel_msg["Counter"]
+
+ else:
+ if self.es_distance_cnt != CS.es_distance_msg["Counter"]:
+ can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, pcm_cancel_cmd))
+ self.es_distance_cnt = CS.es_distance_msg["Counter"]
+
+ if self.es_lkas_cnt != CS.es_lkas_msg["Counter"]:
+ can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, visual_alert, left_line, right_line))
+ self.es_lkas_cnt = CS.es_lkas_msg["Counter"]
return can_sends
diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py
index c2406f2f..5b5e2359 100644
--- a/selfdrive/car/subaru/carstate.py
+++ b/selfdrive/car/subaru/carstate.py
@@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine
from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser
-from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD
+from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD, CAR, PREGLOBAL_CARS
class CarState(CarStateBase):
@@ -20,7 +20,10 @@ class CarState(CarStateBase):
ret.gas = cp.vl["Throttle"]['Throttle_Pedal'] / 255.
ret.gasPressed = ret.gas > 1e-5
- ret.brakePressed = cp.vl["Brake_Pedal"]['Brake_Pedal'] > 1e-5
+ if self.car_fingerprint in PREGLOBAL_CARS:
+ ret.brakePressed = cp.vl["Brake_Pedal"]['Brake_Pedal'] > 2
+ else:
+ ret.brakePressed = cp.vl["Brake_Pedal"]['Brake_Pedal'] > 1e-5
ret.brakeLights = ret.brakePressed
ret.wheelSpeeds.fl = cp.vl["Wheel_Speeds"]['FL'] * CV.KPH_TO_MS
@@ -51,8 +54,12 @@ class CarState(CarStateBase):
ret.cruiseState.enabled = cp.vl["CruiseControl"]['Cruise_Activated'] != 0
ret.cruiseState.available = cp.vl["CruiseControl"]['Cruise_On'] != 0
ret.cruiseState.speed = cp_cam.vl["ES_DashStatus"]['Cruise_Set_Speed'] * CV.KPH_TO_MS
- # EDM Impreza: 1 = mph, UDM Forester: 7 = mph
- if cp.vl["Dash_State"]['Units'] in [1, 7]:
+
+ # UDM Forester, Legacy: mph = 0
+ if self.car_fingerprint in [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL] and cp.vl["Dash_State"]['Units'] == 0:
+ ret.cruiseState.speed *= CV.MPH_TO_KPH
+ # EDM Global: mph = 1, 2; All Outback: mph = 1, UDM Forester: mph = 7
+ elif self.car_fingerprint not in [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL] and cp.vl["Dash_State"]['Units'] in [1, 2, 7]:
ret.cruiseState.speed *= CV.MPH_TO_KPH
ret.seatbeltUnlatched = cp.vl["Dashlights"]['SEATBELT_FL'] == 1
@@ -61,8 +68,17 @@ class CarState(CarStateBase):
cp.vl["BodyInfo"]['DOOR_OPEN_FR'],
cp.vl["BodyInfo"]['DOOR_OPEN_FL']])
- self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"])
- self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"])
+ if self.car_fingerprint in PREGLOBAL_CARS:
+ ret.steerError = cp.vl["Steering_Torque"]["LKA_Lockout"] == 1
+ self.button = cp_cam.vl["ES_CruiseThrottle"]["Button"]
+ self.ready = not cp_cam.vl["ES_DashStatus"]["Not_Ready_Startup"]
+ self.es_accel_msg = copy.copy(cp_cam.vl["ES_CruiseThrottle"])
+ else:
+ ret.steerError = cp.vl["Steering_Torque"]['Steer_Error_1'] == 1
+ ret.steerWarning = cp.vl["Steering_Torque"]['Steer_Warning'] == 1
+ ret.cruiseState.nonAdaptive = cp_cam.vl["ES_DashStatus"]['Conventional_Cruise'] == 1
+ self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"])
+ self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"])
return ret
@@ -98,51 +114,121 @@ class CarState(CarStateBase):
checks = [
# sig_address, frequency
+ ("Throttle", 100),
("Dashlights", 10),
- ("CruiseControl", 20),
+ ("Brake_Pedal", 50),
("Wheel_Speeds", 50),
+ ("Transmission", 100),
("Steering_Torque", 50),
- ("BodyInfo", 10),
]
+ if CP.carFingerprint in PREGLOBAL_CARS:
+ signals += [
+ ("LKA_Lockout", "Steering_Torque", 0),
+ ]
+ else:
+ signals += [
+ ("Steer_Error_1", "Steering_Torque", 0),
+ ("Steer_Warning", "Steering_Torque", 0),
+ ]
+
+ checks += [
+ ("Dashlights", 10),
+ ("BodyInfo", 10),
+ ("CruiseControl", 20),
+ ]
+
+ if CP.carFingerprint == CAR.FORESTER_PREGLOBAL:
+ checks += [
+ ("Dashlights", 20),
+ ("BodyInfo", 1),
+ ("CruiseControl", 50),
+ ]
+
+ if CP.carFingerprint in [CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]:
+ checks += [
+ ("Dashlights", 10),
+ ("CruiseControl", 50),
+ ]
+
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
@staticmethod
def get_cam_can_parser(CP):
- signals = [
- ("Cruise_Set_Speed", "ES_DashStatus", 0),
+ if CP.carFingerprint in PREGLOBAL_CARS:
+ signals = [
+ ("Cruise_Set_Speed", "ES_DashStatus", 0),
+ ("Not_Ready_Startup", "ES_DashStatus", 0),
- ("Counter", "ES_Distance", 0),
- ("Signal1", "ES_Distance", 0),
- ("Signal2", "ES_Distance", 0),
- ("Main", "ES_Distance", 0),
- ("Signal3", "ES_Distance", 0),
+ ("Throttle_Cruise", "ES_CruiseThrottle", 0),
+ ("Signal1", "ES_CruiseThrottle", 0),
+ ("Cruise_Activated", "ES_CruiseThrottle", 0),
+ ("Signal2", "ES_CruiseThrottle", 0),
+ ("Brake_On", "ES_CruiseThrottle", 0),
+ ("DistanceSwap", "ES_CruiseThrottle", 0),
+ ("Standstill", "ES_CruiseThrottle", 0),
+ ("Signal3", "ES_CruiseThrottle", 0),
+ ("CloseDistance", "ES_CruiseThrottle", 0),
+ ("Signal4", "ES_CruiseThrottle", 0),
+ ("Standstill_2", "ES_CruiseThrottle", 0),
+ ("ES_Error", "ES_CruiseThrottle", 0),
+ ("Signal5", "ES_CruiseThrottle", 0),
+ ("Counter", "ES_CruiseThrottle", 0),
+ ("Signal6", "ES_CruiseThrottle", 0),
+ ("Button", "ES_CruiseThrottle", 0),
+ ("Signal7", "ES_CruiseThrottle", 0),
+ ]
- ("Counter", "ES_LKAS_State", 0),
- ("Keep_Hands_On_Wheel", "ES_LKAS_State", 0),
- ("Empty_Box", "ES_LKAS_State", 0),
- ("Signal1", "ES_LKAS_State", 0),
- ("LKAS_ACTIVE", "ES_LKAS_State", 0),
- ("Signal2", "ES_LKAS_State", 0),
- ("Backward_Speed_Limit_Menu", "ES_LKAS_State", 0),
- ("LKAS_ENABLE_3", "ES_LKAS_State", 0),
- ("Signal3", "ES_LKAS_State", 0),
- ("LKAS_ENABLE_2", "ES_LKAS_State", 0),
- ("Signal4", "ES_LKAS_State", 0),
- ("LKAS_Left_Line_Visible", "ES_LKAS_State", 0),
- ("Signal6", "ES_LKAS_State", 0),
- ("LKAS_Right_Line_Visible", "ES_LKAS_State", 0),
- ("Signal7", "ES_LKAS_State", 0),
- ("FCW_Cont_Beep", "ES_LKAS_State", 0),
- ("FCW_Repeated_Beep", "ES_LKAS_State", 0),
- ("Throttle_Management_Activated", "ES_LKAS_State", 0),
- ("Traffic_light_Ahead", "ES_LKAS_State", 0),
- ("Right_Depart", "ES_LKAS_State", 0),
- ("Signal5", "ES_LKAS_State", 0),
- ]
+ checks = [
+ ("ES_DashStatus", 20),
+ ("ES_CruiseThrottle", 20),
+ ]
+ else:
+ signals = [
+ ("Cruise_Set_Speed", "ES_DashStatus", 0),
+ ("Conventional_Cruise", "ES_DashStatus", 0),
- checks = [
- ("ES_DashStatus", 10),
- ]
+ ("Counter", "ES_Distance", 0),
+ ("Signal1", "ES_Distance", 0),
+ ("Cruise_Fault", "ES_Distance", 0),
+ ("Cruise_Throttle", "ES_Distance", 0),
+ ("Signal2", "ES_Distance", 0),
+ ("Car_Follow", "ES_Distance", 0),
+ ("Signal3", "ES_Distance", 0),
+ ("Cruise_Brake_Active", "ES_Distance", 0),
+ ("Distance_Swap", "ES_Distance", 0),
+ ("Cruise_EPB", "ES_Distance", 0),
+ ("Signal4", "ES_Distance", 0),
+ ("Close_Distance", "ES_Distance", 0),
+ ("Signal5", "ES_Distance", 0),
+ ("Cruise_Cancel", "ES_Distance", 0),
+ ("Cruise_Set", "ES_Distance", 0),
+ ("Cruise_Resume", "ES_Distance", 0),
+ ("Signal6", "ES_Distance", 0),
+
+ ("Counter", "ES_LKAS_State", 0),
+ ("Keep_Hands_On_Wheel", "ES_LKAS_State", 0),
+ ("Empty_Box", "ES_LKAS_State", 0),
+ ("Signal1", "ES_LKAS_State", 0),
+ ("LKAS_ACTIVE", "ES_LKAS_State", 0),
+ ("Signal2", "ES_LKAS_State", 0),
+ ("Backward_Speed_Limit_Menu", "ES_LKAS_State", 0),
+ ("LKAS_ENABLE_3", "ES_LKAS_State", 0),
+ ("LKAS_Left_Line_Light_Blink", "ES_LKAS_State", 0),
+ ("LKAS_ENABLE_2", "ES_LKAS_State", 0),
+ ("LKAS_Right_Line_Light_Blink", "ES_LKAS_State", 0),
+ ("LKAS_Left_Line_Visible", "ES_LKAS_State", 0),
+ ("LKAS_Left_Line_Green", "ES_LKAS_State", 0),
+ ("LKAS_Right_Line_Visible", "ES_LKAS_State", 0),
+ ("LKAS_Right_Line_Green", "ES_LKAS_State", 0),
+ ("LKAS_Alert", "ES_LKAS_State", 0),
+ ("Signal3", "ES_LKAS_State", 0),
+ ]
+
+ checks = [
+ ("ES_DashStatus", 10),
+ ("ES_Distance", 20),
+ ("ES_LKAS_State", 10),
+ ]
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index 66a5d995..6d65f64f 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
from cereal import car
-from selfdrive.car.subaru.values import CAR
+from selfdrive.car.subaru.values import CAR, PREGLOBAL_CARS
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
@@ -11,16 +11,22 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
ret.carName = "subaru"
ret.radarOffCan = True
- ret.safetyModel = car.CarParams.SafetyModel.subaru
+
+ if candidate in PREGLOBAL_CARS:
+ ret.safetyModel = car.CarParams.SafetyModel.subaruLegacy
+ else:
+ ret.safetyModel = car.CarParams.SafetyModel.subaru
# 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
@@ -58,6 +64,37 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]]
+ if candidate in [CAR.FORESTER_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]:
+ ret.safetyParam = 1 # Outback 2018-2019 and Forester have reversed driver torque signal
+ ret.mass = 1568 + STD_CARGO_KG
+ ret.wheelbase = 2.67
+ ret.centerToFront = ret.wheelbase * 0.5
+ ret.steerRatio = 20 # learned, 14 stock
+ ret.steerActuatorDelay = 0.1
+ ret.lateralTuning.pid.kf = 0.000039
+ ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 10., 20.], [0., 10., 20.]]
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.05, 0.2], [0.003, 0.018, 0.025]]
+
+ if candidate == CAR.LEGACY_PREGLOBAL:
+ ret.mass = 1568 + STD_CARGO_KG
+ ret.wheelbase = 2.67
+ ret.centerToFront = ret.wheelbase * 0.5
+ ret.steerRatio = 12.5 # 14.5 stock
+ ret.steerActuatorDelay = 0.15
+ ret.lateralTuning.pid.kf = 0.00005
+ ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 20.], [0., 20.]]
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.1, 0.2], [0.01, 0.02]]
+
+ if candidate == CAR.OUTBACK_PREGLOBAL:
+ ret.mass = 1568 + STD_CARGO_KG
+ ret.wheelbase = 2.67
+ ret.centerToFront = ret.wheelbase * 0.5
+ ret.steerRatio = 20 # learned, 14 stock
+ ret.steerActuatorDelay = 0.1
+ ret.lateralTuning.pid.kf = 0.000039
+ ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 10., 20.], [0., 10., 20.]]
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.05, 0.2], [0.003, 0.018, 0.025]]
+
# TODO: get actual value, for now starting with reasonable value for
# civic and scaling by mass and wheelbase
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py
index d0850afc..8249d36b 100644
--- a/selfdrive/car/subaru/subarucan.py
+++ b/selfdrive/car/subaru/subarucan.py
@@ -5,8 +5,7 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert
def create_steering_control(packer, apply_steer, frame, steer_step):
- # counts from 0 to 15 then back to 0 + 16 for enable bit
- idx = ((frame // steer_step) % 16)
+ idx = (frame / steer_step) % 16
values = {
"Counter": idx,
@@ -24,7 +23,7 @@ def create_es_distance(packer, es_distance_msg, pcm_cancel_cmd):
values = copy.copy(es_distance_msg)
if pcm_cancel_cmd:
- values["Main"] = 1
+ values["Cruise_Cancel"] = 1
return packer.make_can_msg("ES_Distance", 0, values)
@@ -38,3 +37,31 @@ def create_es_lkas(packer, es_lkas_msg, visual_alert, left_line, right_line):
values["LKAS_Right_Line_Visible"] = int(right_line)
return packer.make_can_msg("ES_LKAS_State", 0, values)
+
+# *** Subaru Pre-global ***
+
+def subaru_preglobal_checksum(packer, values, addr):
+ dat = packer.make_can_msg(addr, 0, values)[2]
+ return (sum(dat[:7])) % 256
+
+def create_preglobal_steering_control(packer, apply_steer, frame, steer_step):
+
+ idx = (frame / steer_step) % 8
+
+ values = {
+ "Counter": idx,
+ "LKAS_Command": apply_steer,
+ "LKAS_Active": 1 if apply_steer != 0 else 0
+ }
+ values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_LKAS")
+
+ return packer.make_can_msg("ES_LKAS", 0, values)
+
+def create_es_throttle_control(packer, fake_button, es_accel_msg):
+
+ values = copy.copy(es_accel_msg)
+ values["Button"] = fake_button
+
+ values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_CruiseThrottle")
+
+ return packer.make_can_msg("ES_CruiseThrottle", 0, values)
diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py
index d31c5cfb..8cbb6fe7 100644
--- a/selfdrive/car/subaru/values.py
+++ b/selfdrive/car/subaru/values.py
@@ -8,19 +8,23 @@ class CAR:
ASCENT = "SUBARU ASCENT LIMITED 2019"
IMPREZA = "SUBARU IMPREZA LIMITED 2019"
FORESTER = "SUBARU FORESTER 2019"
+ FORESTER_PREGLOBAL = "SUBARU FORESTER 2017 - 2018"
+ LEGACY_PREGLOBAL = "SUBARU LEGACY 2015 - 2018"
+ OUTBACK_PREGLOBAL = "SUBARU OUTBACK 2015 - 2017"
+ OUTBACK_PREGLOBAL_2018 = "SUBARU OUTBACK 2018 - 2019"
FINGERPRINTS = {
- CAR.ASCENT: [
+ CAR.ASCENT: [{
# SUBARU ASCENT LIMITED 2019
- {
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1722: 8, 1743: 8, 1759: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8
}],
CAR.IMPREZA: [{
+ # SUBARU IMPREZA LIMITED 2019
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1722: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8
},
- # Crosstrek 2018 (same platform as Impreza)
+ # SUBARU CROSSTREK 2018
{
- 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 256: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8
+ 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8
}],
CAR.FORESTER: [{
# Forester Sport 2019
@@ -30,12 +34,48 @@ FINGERPRINTS = {
{
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 811: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1651: 8, 1657: 8, 1658: 8, 1677: 8, 1722: 8, 1759: 8, 1787: 5, 1788: 8
}],
+ CAR.OUTBACK_PREGLOBAL: [{
+ # OUTBACK PREMIUM 2.5i 2015
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 346: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 640: 8, 642: 8, 644: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 977: 8, 1632: 8, 1745: 8, 1786: 5, 1882: 8, 2015: 8, 2016: 8, 2024: 8, 604: 8, 885: 8, 1788: 8, 316: 8, 1614: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1743: 8, 1785: 5, 1787: 5
+ },
+ # OUTBACK PREMIUM 3.6i 2015
+ {
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 644: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 977: 8, 1632: 8, 1745: 8, 1779: 8, 1786: 5
+ },
+ # OUTBACK LIMITED 2.5i 2018
+ {
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8
+ }],
+ CAR.OUTBACK_PREGLOBAL_2018: [{
+ # OUTBACK LIMITED 3.6R 2019
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 2, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1862: 8, 1870: 8, 1920: 8, 1927: 8, 1928: 8, 1935: 8, 1968: 8, 1976: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
+ }],
+ CAR.FORESTER_PREGLOBAL: [{
+ # FORESTER PREMIUM 2.5i 2017
+ 2: 8, 112: 8, 117: 8, 128: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 340: 7, 342: 8, 352: 8, 353: 8, 354: 8, 355: 8, 356: 8, 554: 8, 604: 8, 640: 8, 641: 8, 642: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 1, 888: 8, 977: 8, 1398: 8, 1632: 8, 1743: 8, 1744: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1882: 8, 1895: 8, 1903: 8, 1986: 8, 1994: 8, 2015: 8, 2016: 8, 2024: 8, 644:8, 890:8, 1736:8
+ }],
+ CAR.LEGACY_PREGLOBAL: [{
+ # LEGACY 2.5i 2017
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1632: 8, 1640: 8, 1736: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 644: 8
+ },
+ # LEGACY 2018
+ {
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1743: 8, 1745: 8, 1778: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 2015: 8, 2016: 8, 2024: 8
+ },
+ # LEGACY 2018
+ {
+ 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 2015: 8, 2016: 8, 2024: 8
+ }],
}
STEER_THRESHOLD = {
CAR.ASCENT: 80,
CAR.IMPREZA: 80,
CAR.FORESTER: 80,
+ CAR.FORESTER_PREGLOBAL: 75,
+ CAR.LEGACY_PREGLOBAL: 75,
+ CAR.OUTBACK_PREGLOBAL: 75,
+ CAR.OUTBACK_PREGLOBAL_2018: 75,
}
ECU_FINGERPRINT = {
@@ -43,7 +83,13 @@ ECU_FINGERPRINT = {
}
DBC = {
- CAR.ASCENT: dbc_dict('subaru_global_2017', None),
- CAR.IMPREZA: dbc_dict('subaru_global_2017', None),
- CAR.FORESTER: dbc_dict('subaru_global_2017', None),
+ CAR.ASCENT: dbc_dict('subaru_global_2017_generated', None),
+ CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None),
+ CAR.FORESTER: dbc_dict('subaru_global_2017_generated', None),
+ CAR.FORESTER_PREGLOBAL: dbc_dict('subaru_forester_2017_generated', None),
+ CAR.LEGACY_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None),
+ CAR.OUTBACK_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None),
+ CAR.OUTBACK_PREGLOBAL_2018: dbc_dict('subaru_outback_2019_generated', None),
}
+
+PREGLOBAL_CARS = [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]
diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py
index 1800a71d..069d5af0 100755
--- a/selfdrive/car/tests/test_car_interfaces.py
+++ b/selfdrive/car/tests/test_car_interfaces.py
@@ -63,7 +63,7 @@ class TestCarInterfaces(unittest.TestCase):
# Run radar interface once
radar_interface.update([])
- if hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'):
+ if not car_params.radarOffCan and hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'):
radar_interface._update([radar_interface.trigger_msg])
if __name__ == "__main__":
diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py
index d4cc7164..4cf84904 100644
--- a/selfdrive/car/toyota/carstate.py
+++ b/selfdrive/car/toyota/carstate.py
@@ -182,9 +182,14 @@ class CarState(CarStateBase):
@staticmethod
def get_cam_can_parser(CP):
- signals = [("FORCE", "PRE_COLLISION", 0), ("PRECOLLISION_ACTIVE", "PRE_COLLISION", 0)]
+ signals = [
+ ("FORCE", "PRE_COLLISION", 0),
+ ("PRECOLLISION_ACTIVE", "PRE_COLLISION", 0)
+ ]
# use steering message to check if panda is connected to frc
- checks = [("STEERING_LKA", 42)]
+ checks = [
+ ("STEERING_LKA", 42)
+ ]
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py
index 7720e627..e31eaee4 100755
--- a/selfdrive/car/toyota/interface.py
+++ b/selfdrive/car/toyota/interface.py
@@ -313,7 +313,6 @@ class CarInterface(CarInterfaceBase):
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
- ret.buttonEvents = []
# events
events = self.create_common_events(ret)
diff --git a/selfdrive/car/toyota/radar_interface.py b/selfdrive/car/toyota/radar_interface.py
index 3a66beed..a7d2ec37 100755
--- a/selfdrive/car/toyota/radar_interface.py
+++ b/selfdrive/car/toyota/radar_interface.py
@@ -1,14 +1,10 @@
#!/usr/bin/env python3
-import os
-import time
from opendbc.can.parser import CANParser
from cereal import car
from selfdrive.car.toyota.values import NO_DSU_CAR, DBC, TSS2_CAR
from selfdrive.car.interfaces import RadarInterfaceBase
def _create_radar_can_parser(car_fingerprint):
- dbc_f = DBC[car_fingerprint]['radar']
-
if car_fingerprint in TSS2_CAR:
RADAR_A_MSGS = list(range(0x180, 0x190))
RADAR_B_MSGS = list(range(0x190, 0x1a0))
@@ -26,7 +22,7 @@ def _create_radar_can_parser(car_fingerprint):
checks = list(zip(RADAR_A_MSGS + RADAR_B_MSGS, [20]*(msg_a_n + msg_b_n)))
- return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1)
+ return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1)
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
@@ -53,8 +49,7 @@ class RadarInterface(RadarInterfaceBase):
def update(self, can_strings):
if self.no_radar:
- time.sleep(self.radar_ts)
- return car.RadarData.new_message()
+ return super().update(None)
vls = self.rcp.update_strings(can_strings)
self.updated_messages.update(vls)
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index 6755075d..da18bfba 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -341,6 +341,7 @@ FW_VERSIONS = {
b'8646F0603400 ',
b'8646F0605000 ',
b'8646F0606000 ',
+ b'8646F0606100 ',
],
},
CAR.CAMRYH: {
@@ -614,6 +615,7 @@ FW_VERSIONS = {
b'\x028646F1201100\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00',
b'\x028646F1201300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
b'\x028646F1202000\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',
+ b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',
],
},
@@ -711,15 +713,24 @@ FW_VERSIONS = {
(Ecu.engine, 0x700, None): [
b'\x018966353M7100\x00\x00\x00\x00',
b'\x018966353Q2300\x00\x00\x00\x00',
+ b'\x018966353R8100\x00\x00\x00\x00',
+ ],
+ (Ecu.esp, 0x7b0, None): [
+ b'F152653330\x00\x00\x00\x00\x00\x00',
],
- (Ecu.esp, 0x7b0, None): [b'F152653330\x00\x00\x00\x00\x00\x00'],
(Ecu.dsu, 0x791, None): [
b'881515306400\x00\x00\x00\x00',
b'881515306500\x00\x00\x00\x00',
],
- (Ecu.eps, 0x7a1, None): [b'8965B53271\x00\x00\x00\x00\x00\x00'],
- (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4702300\x00\x00\x00\x00'],
- (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F5301400\x00\x00\x00\x00'],
+ (Ecu.eps, 0x7a1, None): [
+ b'8965B53271\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.fwdRadar, 0x750, 0xf): [
+ b'8821F4702300\x00\x00\x00\x00',
+ ],
+ (Ecu.fwdCamera, 0x750, 0x6d): [
+ b'8646F5301400\x00\x00\x00\x00',
+ ],
},
CAR.PRIUS: {
(Ecu.engine, 0x700, None): [
@@ -932,6 +943,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x700, None): [
b'\x018966342M5000\x00\x00\x00\x00',
b'\x018966342X6000\x00\x00\x00\x00',
+ b'\x018966342W8000\x00\x00\x00\x00',
b'\x028966342W4001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00',
b'\x02896634A23001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00',
],
@@ -951,15 +963,17 @@ FW_VERSIONS = {
b'\x028965B0R01300\x00\x00\x00\x008965B0R02300\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x750, 0xf): [
+ b'\x018821F3301100\x00\x00\x00\x00',
b'\x018821F3301200\x00\x00\x00\x00',
b'\x018821F3301300\x00\x00\x00\x00',
b'\x018821F3301400\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x750, 0x6d): [
- b'\x028646F4203700\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
+ b'\x028646F4203200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00',
b'\x028646F4203300\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00',
b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',
b'\x028646F4203500\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',
+ b'\x028646F4203700\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
],
},
CAR.LEXUS_ES_TSS2: {
@@ -1063,30 +1077,36 @@ FW_VERSIONS = {
b'\x01896630E41000\x00\x00\x00\x00',
b'\x01896630E41200\x00\x00\x00\x00',
b'\x01896630E37300\x00\x00\x00\x00',
+ b'\x018966348R8500\x00\x00\x00\x00',
],
(Ecu.esp, 0x7b0, None): [
b'F152648472\x00\x00\x00\x00\x00\x00',
b'F152648473\x00\x00\x00\x00\x00\x00',
b'F152648492\x00\x00\x00\x00\x00\x00',
b'F152648493\x00\x00\x00\x00\x00\x00',
+ b'F152648474\x00\x00\x00\x00\x00\x00',
],
(Ecu.dsu, 0x791, None): [
b'881514810300\x00\x00\x00\x00',
b'881514810500\x00\x00\x00\x00',
+ b'881514810700\x00\x00\x00\x00',
],
(Ecu.eps, 0x7a1, None): [
b'8965B0E011\x00\x00\x00\x00\x00\x00',
b'8965B0E012\x00\x00\x00\x00\x00\x00',
+ b'8965B48102\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x750, 0xf): [
b'8821F4701000\x00\x00\x00\x00',
b'8821F4701100\x00\x00\x00\x00',
+ b'8821F4701300\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x750, 0x6d): [
b'8646F4801100\x00\x00\x00\x00',
b'8646F4801200\x00\x00\x00\x00',
b'8646F4802001\x00\x00\x00\x00',
b'8646F4802100\x00\x00\x00\x00',
+ b'8646F4809000\x00\x00\x00\x00',
],
},
CAR.LEXUS_RXH: {
@@ -1198,6 +1218,6 @@ DBC = {
CAR.LEXUS_NXH: dbc_dict('lexus_nx300h_2018_pt_generated', 'toyota_adas'),
}
-NO_DSU_CAR = [CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]
-TSS2_CAR = [CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]
-NO_STOP_TIMER_CAR = [CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2] # no resume button press required
+NO_DSU_CAR = set([CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2])
+TSS2_CAR = set([CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2])
+NO_STOP_TIMER_CAR = set([CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]) # no resume button press required
diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py
index a157805c..5bb5dcc1 100644
--- a/selfdrive/car/volkswagen/carcontroller.py
+++ b/selfdrive/car/volkswagen/carcontroller.py
@@ -4,8 +4,6 @@ from selfdrive.car.volkswagen import volkswagencan
from selfdrive.car.volkswagen.values import DBC, CANBUS, MQB_LDW_MESSAGES, BUTTON_STATES, CarControllerParams
from opendbc.can.packer import CANPacker
-VisualAlert = car.CarControl.HUDControl.VisualAlert
-
class CarController():
def __init__(self, dbc_name, CP, VM):
@@ -114,7 +112,7 @@ class CarController():
if frame % P.LDW_STEP == 0:
hcaEnabled = True if enabled and not CS.out.standstill else False
- if visual_alert == VisualAlert.steerRequired:
+ if visual_alert == car.CarControl.HUDControl.VisualAlert.steerRequired:
hud_alert = MQB_LDW_MESSAGES["laneAssistTakeOverSilent"]
else:
hud_alert = MQB_LDW_MESSAGES["none"]
diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py
index 0ee8ce50..a9941309 100644
--- a/selfdrive/car/volkswagen/carstate.py
+++ b/selfdrive/car/volkswagen/carstate.py
@@ -53,7 +53,7 @@ class CarState(CarStateBase):
pt_cp.vl["Gateway_72"]['ZV_HD_offen']])
# Update seatbelt fastened status.
- ret.seatbeltUnlatched = False if pt_cp.vl["Airbag_02"]["AB_Gurtschloss_FA"] == 3 else True
+ ret.seatbeltUnlatched = pt_cp.vl["Airbag_02"]["AB_Gurtschloss_FA"] != 3
# Update driver preference for metric. VW stores many different unit
# preferences, including separate units for for distance vs. speed.
diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py
index 3ec4b070..c041c6c4 100644
--- a/selfdrive/car/volkswagen/interface.py
+++ b/selfdrive/car/volkswagen/interface.py
@@ -1,6 +1,5 @@
from cereal import car
from selfdrive.car.volkswagen.values import CAR, BUTTON_STATES
-from common.params import put_nonblocking
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
@@ -19,7 +18,7 @@ class CarInterface(CarInterfaceBase):
return float(accel) / 4.0
@staticmethod
- def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value
+ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay)
# VW port is a community feature, since we don't own one to test
@@ -64,7 +63,6 @@ class CarInterface(CarInterfaceBase):
# returns a car.CarState
def update(self, c, can_strings):
- canMonoTimes = []
buttonEvents = []
# Process the most recent CAN message traffic, and check for validity
@@ -77,10 +75,11 @@ class CarInterface(CarInterfaceBase):
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False
- # Update the EON metric configuration to match the car at first startup,
+ # TODO: add a field for this to carState, car interface code shouldn't write params
+ # Update the device metric configuration to match the car at first startup,
# or if there's been a change.
- if self.CS.displayMetricUnits != self.displayMetricUnitsPrev:
- put_nonblocking("IsMetric", "1" if self.CS.displayMetricUnits else "0")
+ #if self.CS.displayMetricUnits != self.displayMetricUnitsPrev:
+ # put_nonblocking("IsMetric", "1" if self.CS.displayMetricUnits else "0")
# Check for and process state-change events (button press or release) from
# the turn stalk switch or ACC steering wheel/control stalk buttons.
@@ -101,7 +100,6 @@ class CarInterface(CarInterfaceBase):
ret.events = events.to_msg()
ret.buttonEvents = buttonEvents
- ret.canMonoTimes = canMonoTimes
# update previous car states
self.displayMetricUnitsPrev = self.CS.displayMetricUnits
diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py
index 3937a7c1..d99d7810 100644
--- a/selfdrive/car/volkswagen/values.py
+++ b/selfdrive/car/volkswagen/values.py
@@ -46,7 +46,7 @@ MQB_LDW_MESSAGES = {
}
class CAR:
- GOLF = "Volkswagen Golf"
+ GOLF = "VOLKSWAGEN GOLF"
FINGERPRINTS = {
CAR.GOLF: [
diff --git a/selfdrive/car/volkswagen/volkswagencan.py b/selfdrive/car/volkswagen/volkswagencan.py
index 694673ea..3cd47a09 100644
--- a/selfdrive/car/volkswagen/volkswagencan.py
+++ b/selfdrive/car/volkswagen/volkswagencan.py
@@ -48,5 +48,4 @@ def create_mqb_acc_buttons_control(packer, bus, buttonStatesToSend, CS, idx):
"GRA_Tip_Stufe_2": CS.graTipStufe2,
"GRA_ButtonTypeInfo": CS.graButtonTypeInfo
}
-
return packer.make_can_msg("GRA_ACC_01", bus, values, idx)
diff --git a/selfdrive/common/version.h b/selfdrive/common/version.h
index b66af920..d95231d5 100644
--- a/selfdrive/common/version.h
+++ b/selfdrive/common/version.h
@@ -1 +1 @@
-#define COMMA_VERSION "0.7.7-release"
+#define COMMA_VERSION "0.7.8-release"
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index 4c11c5e0..2546a598 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -10,7 +10,7 @@ from common.params import Params, put_nonblocking
import cereal.messaging as messaging
from selfdrive.config import Conversions as CV
from selfdrive.boardd.boardd import can_list_to_can_capnp
-from selfdrive.car.car_helpers import get_car, get_startup_event
+from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
from selfdrive.controls.lib.lane_planner import CAMERA_OFFSET
from selfdrive.controls.lib.drive_helpers import update_v_cruise, initialize_v_cruise
from selfdrive.controls.lib.longcontrol import LongControl, STARTING_TARGET_SPEED
@@ -64,7 +64,7 @@ class Controls:
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...")
- messaging.get_one_can(self.can_sock)
+ get_one_can(self.can_sock)
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], has_relay)
@@ -216,6 +216,8 @@ class Controls:
self.events.add(EventName.vehicleModelInvalid)
if not self.sm['liveLocationKalman'].posenetOK:
self.events.add(EventName.posenetInvalid)
+ if not self.sm['liveLocationKalman'].deviceStable:
+ self.events.add(EventName.deviceFalling)
if not self.sm['frame'].recoverState < 2:
# counter>=2 is active
self.events.add(EventName.focusRecoverActive)
diff --git a/selfdrive/controls/lib/alertmanager.py b/selfdrive/controls/lib/alertmanager.py
index 42daff42..870d8d4b 100644
--- a/selfdrive/controls/lib/alertmanager.py
+++ b/selfdrive/controls/lib/alertmanager.py
@@ -1,14 +1,34 @@
+import os
+import copy
+import json
+
from cereal import car, log
+from common.basedir import BASEDIR
+from common.params import Params
from common.realtime import DT_CTRL
from selfdrive.swaglog import cloudlog
-import copy
-
AlertSize = log.ControlsState.AlertSize
AlertStatus = log.ControlsState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
+
+with open(os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json")) as f:
+ OFFROAD_ALERTS = json.load(f)
+
+
+def set_offroad_alert(alert, show_alert, extra_text=None):
+ if show_alert:
+ a = OFFROAD_ALERTS[alert]
+ if extra_text is not None:
+ a = copy.copy(OFFROAD_ALERTS[alert])
+ a['text'] += extra_text
+ Params().put(alert, json.dumps(a))
+ else:
+ Params().delete(alert)
+
+
class AlertManager():
def __init__(self):
diff --git a/selfdrive/controls/lib/alerts_offroad.json b/selfdrive/controls/lib/alerts_offroad.json
index cebb1a2c..f343f4cd 100644
--- a/selfdrive/controls/lib/alerts_offroad.json
+++ b/selfdrive/controls/lib/alerts_offroad.json
@@ -16,6 +16,11 @@
"text": "Connect to internet to check for updates. openpilot won't engage until it connects to internet to check for updates.",
"severity": 1
},
+ "Offroad_UpdateFailed": {
+ "text": "Unable to download updates\n",
+ "severity": 1,
+ "_comment": "Append the command and error to the text."
+ },
"Offroad_PandaFirmwareMismatch": {
"text": "Unexpected panda firmware version. System won't start. Reboot your device to reflash panda.",
"severity": 1
@@ -27,5 +32,9 @@
"Offroad_IsTakingSnapshot": {
"text": "Taking camera snapshots. System won't start until finished.",
"severity": 0
+ },
+ "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
}
}
diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py
index f576cf4d..205c6a17 100644
--- a/selfdrive/controls/lib/events.py
+++ b/selfdrive/controls/lib/events.py
@@ -1,5 +1,6 @@
-from cereal import log, car
+from functools import total_ordering
+from cereal import log, car
from common.realtime import DT_CTRL
from selfdrive.config import Conversions as CV
from selfdrive.locationd.calibration_helpers import Filter
@@ -93,6 +94,7 @@ class Events:
ret.append(event)
return ret
+@total_ordering
class Alert:
def __init__(self,
alert_text_1,
@@ -136,6 +138,9 @@ class Alert:
def __gt__(self, alert2):
return self.alert_priority > alert2.alert_priority
+ def __eq__(self, alert2):
+ return self.alert_priority == alert2.alert_priority
+
class NoEntryAlert(Alert):
def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError,
visual_alert=VisualAlert.none, duration_hud_alert=2.):
@@ -525,15 +530,6 @@ EVENTS = {
duration_hud_alert=0.),
},
- EventName.posenetInvalid: {
- ET.WARNING: Alert(
- "TAKE CONTROL",
- "Vision Model Output Uncertain",
- AlertStatus.userPrompt, AlertSize.mid,
- Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.),
- ET.NO_ENTRY: NoEntryAlert("Vision Model Output Uncertain"),
- },
-
EventName.focusRecoverActive: {
ET.WARNING: Alert(
"TAKE CONTROL",
@@ -654,6 +650,16 @@ EVENTS = {
ET.NO_ENTRY : NoEntryAlert("Driving model lagging"),
},
+ EventName.posenetInvalid: {
+ ET.SOFT_DISABLE: SoftDisableAlert("Vision Model Output Uncertain"),
+ ET.NO_ENTRY: NoEntryAlert("Vision Model Output Uncertain"),
+ },
+
+ EventName.deviceFalling: {
+ ET.SOFT_DISABLE: SoftDisableAlert("Device Fell Off Mount"),
+ ET.NO_ENTRY: NoEntryAlert("Device Fell Off Mount"),
+ },
+
EventName.lowMemory: {
ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"),
ET.PERMANENT: Alert(
diff --git a/selfdrive/controls/lib/latcontrol_pid.py b/selfdrive/controls/lib/latcontrol_pid.py
index 5662942b..aa069e81 100644
--- a/selfdrive/controls/lib/latcontrol_pid.py
+++ b/selfdrive/controls/lib/latcontrol_pid.py
@@ -8,7 +8,8 @@ class LatControlPID():
def __init__(self, CP):
self.pid = PIController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
(CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
- k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, sat_limit=CP.steerLimitTimer)
+ k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, neg_limit=-1.0,
+ sat_limit=CP.steerLimitTimer)
self.angle_steers_des = 0.
def reset(self):
diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py
index d75f9db3..5262f480 100644
--- a/selfdrive/controls/lib/longcontrol.py
+++ b/selfdrive/controls/lib/longcontrol.py
@@ -85,7 +85,7 @@ class LongControl():
v_ego_pid = max(CS.vEgo, MIN_CAN_SPEED) # Without this we get jumps, CAN bus reports 0 when speed < 0.3
- if self.long_control_state == LongCtrlState.off:
+ if self.long_control_state == LongCtrlState.off or CS.gasPressed:
self.v_pid = v_ego_pid
self.pid.reset()
output_gb = 0.
diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py
index 88c4d694..553e5bb6 100755
--- a/selfdrive/controls/lib/planner.py
+++ b/selfdrive/controls/lib/planner.py
@@ -129,7 +129,7 @@ class Planner():
following = lead_1.status and lead_1.dRel < 45.0 and lead_1.vLeadK > v_ego and lead_1.aLeadK > 0.0
# Calculate speed for normal cruise control
- if enabled and not self.first_loop:
+ if enabled and not self.first_loop and not sm['carState'].gasPressed:
accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following)]
jerk_limits = [min(-0.1, accel_limits[0]), max(0.1, accel_limits[1])] # TODO: make a separate lookup for jerk tuning
accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngle, accel_limits, self.CP)
diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py
index a890af9e..28cabe6c 100755
--- a/selfdrive/debug/cpu_usage_stat.py
+++ b/selfdrive/debug/cpu_usage_stat.py
@@ -31,7 +31,7 @@ SLEEP_INTERVAL = 0.2
monitored_proc_names = [
'ubloxd', 'thermald', 'uploader', 'deleter', 'controlsd', 'plannerd', 'radard', 'mapd', 'loggerd', 'logmessaged', 'tombstoned',
- 'logcatd', 'proclogd', 'boardd', 'pandad', './ui', 'ui', 'calibrationd', 'params_learner', 'modeld', 'dmonitoringmodeld', 'camerad', 'sensord', 'updated', 'gpsd', 'athena']
+ 'logcatd', 'proclogd', 'boardd', 'pandad', './ui', 'ui', 'calibrationd', 'params_learner', 'modeld', 'dmonitoringd', 'dmonitoringmodeld', 'camerad', 'sensord', 'updated', 'gpsd', 'athena', 'locationd', 'paramsd']
cpu_time_names = ['user', 'system', 'children_user', 'children_system']
timer = getattr(time, 'monotonic', time.time)
diff --git a/selfdrive/debug/uiview.py b/selfdrive/debug/uiview.py
new file mode 100644
index 00000000..899f932a
--- /dev/null
+++ b/selfdrive/debug/uiview.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+import time
+import cereal.messaging as messaging
+from selfdrive.manager import start_managed_process, kill_managed_process
+
+services = ['controlsState', 'thermal'] # the services needed to be spoofed to start ui offroad
+procs = ['camerad', 'ui']
+[start_managed_process(p) for p in procs] # start needed processes
+pm = messaging.PubMaster(services)
+
+dat_cs, dat_thermal = [messaging.new_message(s) for s in services]
+dat_cs.controlsState.rearViewCam = False # ui checks for these two messages
+dat_thermal.thermal.started = True
+
+try:
+ while True:
+ pm.send('controlsState', dat_cs)
+ pm.send('thermal', dat_thermal)
+ time.sleep(1 / 100) # continually send, rate doesn't matter for thermal
+except KeyboardInterrupt:
+ [kill_managed_process(p) for p in procs]
diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript
index fbecaa1b..59516574 100644
--- a/selfdrive/locationd/SConscript
+++ b/selfdrive/locationd/SConscript
@@ -1,12 +1,6 @@
Import('env', 'common', 'cereal', 'messaging')
-loc_objs = [
- "locationd_yawrate.cc",
- "params_learner.cc",
- "paramsd.cc"]
-loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'json11', 'pthread']
-env.Program("paramsd", loc_objs, LIBS=loc_libs)
-env.SharedLibrary("locationd", loc_objs, LIBS=loc_libs)
+loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'pthread']
env.Program("ubloxd", [
"ubloxd.cc",
diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py
index e95f00c2..a27e284a 100755
--- a/selfdrive/locationd/calibrationd.py
+++ b/selfdrive/locationd/calibrationd.py
@@ -126,13 +126,21 @@ class Calibrator():
def send_data(self, pm):
calib = get_calib_from_vp(self.vp)
+ if self.valid_blocks > 0:
+ max_vp_calib = np.array(get_calib_from_vp(np.max(self.vps[:self.valid_blocks], axis=0)))
+ min_vp_calib = np.array(get_calib_from_vp(np.min(self.vps[:self.valid_blocks], axis=0)))
+ calib_spread = np.abs(max_vp_calib - min_vp_calib)
+ else:
+ calib_spread = np.zeros(3)
extrinsic_matrix = get_view_frame_from_road_frame(0, calib[1], calib[2], model_height)
cal_send = messaging.new_message('liveCalibration')
+ cal_send.liveCalibration.validBlocks = self.valid_blocks
cal_send.liveCalibration.calStatus = self.cal_status
cal_send.liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100)
cal_send.liveCalibration.extrinsicMatrix = [float(x) for x in extrinsic_matrix.flatten()]
cal_send.liveCalibration.rpyCalib = [float(x) for x in calib]
+ cal_send.liveCalibration.rpyCalibSpread = [float(x) for x in calib_spread]
pm.send('liveCalibration', cal_send)
@@ -170,8 +178,6 @@ def calibrationd_thread(sm=None, pm=None):
if DEBUG and new_vp is not None:
print('got new vp', new_vp)
- # decimate outputs for efficiency
-
def main(sm=None, pm=None):
calibrationd_thread(sm, pm)
diff --git a/selfdrive/locationd/locationd.py b/selfdrive/locationd/locationd.py
index 3a5d5155..be781768 100755
--- a/selfdrive/locationd/locationd.py
+++ b/selfdrive/locationd/locationd.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
import numpy as np
import sympy as sp
-
import cereal.messaging as messaging
import common.transformations.coordinates as coord
from common.transformations.orientation import ecef_euler_from_ned, \
@@ -23,6 +22,7 @@ from rednose.helpers.sympy_helpers import euler_rotate
VISION_DECIMATION = 2
SENSOR_DECIMATION = 10
+POSENET_STD_HIST = 40
def to_float(arr):
@@ -52,7 +52,7 @@ class Localizer():
self.kf = LiveKalman(GENERATED_DIR)
self.reset_kalman()
- self.max_age = .2 # seconds
+ self.max_age = .1 # seconds
self.disabled_logs = disabled_logs
self.calib = np.zeros(3)
self.device_from_calib = np.eye(3)
@@ -63,11 +63,13 @@ class Localizer():
self.posenet_invalid_count = 0
self.posenet_speed = 0
self.car_speed = 0
+ self.posenet_stds = 10*np.ones((POSENET_STD_HIST))
self.converter = coord.LocalCoord.from_ecef(self.kf.x[States.ECEF_POS])
self.unix_timestamp_millis = 0
self.last_gps_fix = 0
+ self.device_fell = False
@staticmethod
def msg_from_state(converter, calib_from_device, H, predicted_state, predicted_cov):
@@ -112,57 +114,42 @@ class Localizer():
#ned_vel_std = self.converter.ecef2ned(fix_ecef + vel_ecef + vel_ecef_std) - self.converter.ecef2ned(fix_ecef + vel_ecef)
fix = messaging.log.LiveLocationKalman.new_message()
- fix.positionGeodetic.value = to_float(fix_pos_geo)
- #fix.positionGeodetic.std = to_float(fix_pos_geo_std)
- #fix.positionGeodetic.valid = True
- fix.positionECEF.value = to_float(fix_ecef)
- fix.positionECEF.std = to_float(fix_ecef_std)
- fix.positionECEF.valid = True
- fix.velocityECEF.value = to_float(vel_ecef)
- fix.velocityECEF.std = to_float(vel_ecef_std)
- fix.velocityECEF.valid = True
- fix.velocityNED.value = to_float(ned_vel)
- #fix.velocityNED.std = to_float(ned_vel_std)
- #fix.velocityNED.valid = True
- fix.velocityDevice.value = to_float(vel_device)
- fix.velocityDevice.std = to_float(vel_device_std)
- fix.velocityDevice.valid = True
- fix.accelerationDevice.value = to_float(predicted_state[States.ACCELERATION])
- fix.accelerationDevice.std = to_float(predicted_std[States.ACCELERATION_ERR])
- fix.accelerationDevice.valid = True
- fix.orientationECEF.value = to_float(orientation_ecef)
- fix.orientationECEF.std = to_float(orientation_ecef_std)
- fix.orientationECEF.valid = True
- fix.calibratedOrientationECEF.value = to_float(calibrated_orientation_ecef)
- #fix.calibratedOrientationECEF.std = to_float(calibrated_orientation_ecef_std)
- #fix.calibratedOrientationECEF.valid = True
- fix.orientationNED.value = to_float(orientation_ned)
- #fix.orientationNED.std = to_float(orientation_ned_std)
- #fix.orientationNED.valid = True
- fix.angularVelocityDevice.value = to_float(predicted_state[States.ANGULAR_VELOCITY])
- fix.angularVelocityDevice.std = to_float(predicted_std[States.ANGULAR_VELOCITY_ERR])
- fix.angularVelocityDevice.valid = True
+ # write measurements to msg
+ measurements = [
+ # measurement field, value, std, valid
+ (fix.positionGeodetic, fix_pos_geo, np.nan*np.zeros(3), True),
+ (fix.positionECEF, fix_ecef, fix_ecef_std, True),
+ (fix.velocityECEF, vel_ecef, vel_ecef_std, True),
+ (fix.velocityNED, ned_vel, np.nan*np.zeros(3), True),
+ (fix.velocityDevice, vel_device, vel_device_std, True),
+ (fix.accelerationDevice, predicted_state[States.ACCELERATION], predicted_std[States.ACCELERATION_ERR], True),
+ (fix.orientationECEF, orientation_ecef, orientation_ecef_std, True),
+ (fix.calibratedOrientationECEF, calibrated_orientation_ecef, np.nan*np.zeros(3), True),
+ (fix.orientationNED, orientation_ned, np.nan*np.zeros(3), True),
+ (fix.angularVelocityDevice, predicted_state[States.ANGULAR_VELOCITY], predicted_std[States.ANGULAR_VELOCITY_ERR], True),
+ (fix.velocityCalibrated, vel_calib, vel_calib_std, True),
+ (fix.angularVelocityCalibrated, ang_vel_calib, ang_vel_calib_std, True),
+ (fix.accelerationCalibrated, acc_calib, acc_calib_std, True),
+ ]
+
+ for field, value, std, valid in measurements:
+ # TODO: can we write the lists faster?
+ field.value = to_float(value)
+ field.std = to_float(std)
+ field.valid = valid
- fix.velocityCalibrated.value = to_float(vel_calib)
- fix.velocityCalibrated.std = to_float(vel_calib_std)
- fix.velocityCalibrated.valid = True
- fix.angularVelocityCalibrated.value = to_float(ang_vel_calib)
- fix.angularVelocityCalibrated.std = to_float(ang_vel_calib_std)
- fix.angularVelocityCalibrated.valid = True
- fix.accelerationCalibrated.value = to_float(acc_calib)
- fix.accelerationCalibrated.std = to_float(acc_calib_std)
- fix.accelerationCalibrated.valid = True
return fix
- def liveLocationMsg(self, time):
+ def liveLocationMsg(self):
fix = self.msg_from_state(self.converter, self.calib_from_device, self.H, self.kf.x, self.kf.P)
+ # experimentally found these values, no false positives in 20k minutes of driving
+ old_mean, new_mean = np.mean(self.posenet_stds[:POSENET_STD_HIST//2]), np.mean(self.posenet_stds[POSENET_STD_HIST//2:])
+ std_spike = new_mean/old_mean > 4 and new_mean > 7
- if abs(self.posenet_speed - self.car_speed) > max(0.4 * self.car_speed, 5.0):
- self.posenet_invalid_count += 1
- else:
- self.posenet_invalid_count = 0
- fix.posenetOK = self.posenet_invalid_count < 4
+ fix.posenetOK = not (std_spike and self.car_speed > 5)
+ fix.deviceStable = not self.device_fell
+ self.device_fell = False
#fix.gpsWeek = self.time.week
#fix.gpsTimeOfWeek = self.time.tow
@@ -178,15 +165,10 @@ class Localizer():
def update_kalman(self, time, kind, meas, R=None):
try:
- self.kf.predict_and_observe(time, kind, meas, R=R)
+ self.kf.predict_and_observe(time, kind, meas, R)
except KalmanError:
cloudlog.error("Error in predict and observe, kalman reset")
self.reset_kalman()
- #idx = bisect_right([x[0] for x in self.observation_buffer], time)
- #self.observation_buffer.insert(idx, (time, kind, meas))
- #while len(self.observation_buffer) > 0 and self.observation_buffer[-1][0] - self.observation_buffer[0][0] > self.max_age:
- # else:
- # self.observation_buffer.pop(0)
def handle_gps(self, current_time, log):
# ignore the message if the fix is invalid
@@ -244,6 +226,8 @@ class Localizer():
trans_device = self.device_from_calib.dot(log.trans)
trans_device_std = self.device_from_calib.dot(log.transStd)
self.posenet_speed = np.linalg.norm(trans_device)
+ self.posenet_stds[:-1] = self.posenet_stds[1:]
+ self.posenet_stds[-1] = trans_device_std[0]
self.update_kalman(current_time,
ObservationKind.CAMERA_ODO_TRANSLATION,
np.concatenate([trans_device, 10*trans_device_std]))
@@ -260,6 +244,10 @@ class Localizer():
# Accelerometer
if sensor_reading.sensor == 1 and sensor_reading.type == 1:
+ # check if device fell, estimate 10 for g
+ # 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving
+ self.device_fell = self.device_fell or (np.linalg.norm(np.array(sensor_reading.acceleration.v) - np.array([10, 0, 0])) > 40)
+
self.acc_counter += 1
if self.acc_counter % SENSOR_DECIMATION == 0:
v = sensor_reading.acceleration.v
@@ -322,7 +310,7 @@ def locationd_thread(sm, pm, disabled_logs=None):
msg = messaging.new_message('liveLocationKalman')
msg.logMonoTime = t
- msg.liveLocationKalman = localizer.liveLocationMsg(t * 1e-9)
+ msg.liveLocationKalman = localizer.liveLocationMsg()
msg.liveLocationKalman.inputsOK = sm.all_alive_and_valid()
msg.liveLocationKalman.sensorsOK = sm.alive['sensorEvents'] and sm.valid['sensorEvents']
diff --git a/selfdrive/locationd/locationd_yawrate.cc b/selfdrive/locationd/locationd_yawrate.cc
deleted file mode 100644
index e682ec39..00000000
--- a/selfdrive/locationd/locationd_yawrate.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-#include
-#include
-
-#include
-#include
-#include
-
-#include "cereal/gen/cpp/log.capnp.h"
-
-#include "locationd_yawrate.h"
-
-
-void Localizer::update_state(const Eigen::Matrix &C, const double R, double current_time, double meas) {
- double dt = current_time - prev_update_time;
-
- if (dt < 0) {
- dt = 0;
- } else {
- prev_update_time = current_time;
- }
-
- x = A * x;
- P = A * P * A.transpose() + dt * Q;
-
- double y = meas - C * x;
- double S = R + C * P * C.transpose();
- Eigen::Vector2d K = P * C.transpose() * (1.0 / S);
- x = x + K * y;
- P = (I - K * C) * P;
-}
-
-void Localizer::handle_sensor_events(capnp::List::Reader sensor_events, double current_time) {
- for (cereal::SensorEventData::Reader sensor_event : sensor_events){
- if (sensor_event.getSensor() == 5 && sensor_event.getType() == 16) {
- double meas = -sensor_event.getGyroUncalibrated().getV()[0];
- update_state(C_gyro, R_gyro, current_time, meas);
- }
- }
-}
-
-void Localizer::handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time) {
- double R = pow(5 * camera_odometry.getRotStd()[2], 2);
- double meas = camera_odometry.getRot()[2];
- update_state(C_posenet, R, current_time, meas);
-}
-
-void Localizer::handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time) {
- steering_angle = controls_state.getAngleSteers() * DEGREES_TO_RADIANS;
- car_speed = controls_state.getVEgo();
-}
-
-
-Localizer::Localizer() {
- // States: [yaw rate, gyro bias]
- A <<
- 1, 0,
- 0, 1;
-
- Q <<
- pow(.1, 2.0), 0,
- 0, pow(0.05/ 100.0, 2.0),
- P <<
- pow(10000.0, 2.0), 0,
- 0, pow(10000.0, 2.0);
-
- I <<
- 1, 0,
- 0, 1;
-
- C_posenet << 1, 0;
- C_gyro << 1, 1;
- x << 0, 0;
-
- R_gyro = pow(0.025, 2.0);
-}
-
-void Localizer::handle_log(cereal::Event::Reader event) {
- double current_time = event.getLogMonoTime() / 1.0e9;
-
- // Initialize update_time on first update
- if (prev_update_time < 0) {
- prev_update_time = current_time;
- }
-
- auto type = event.which();
- switch(type) {
- case cereal::Event::CONTROLS_STATE:
- handle_controls_state(event.getControlsState(), current_time);
- break;
- case cereal::Event::CAMERA_ODOMETRY:
- handle_camera_odometry(event.getCameraOdometry(), current_time);
- break;
- case cereal::Event::SENSOR_EVENTS:
- handle_sensor_events(event.getSensorEvents(), current_time);
- break;
- default:
- break;
- }
-}
-
-
-extern "C" {
- void *localizer_init(void) {
- Localizer * localizer = new Localizer;
- return (void*)localizer;
- }
-
- void localizer_handle_log(void * localizer, const unsigned char * data, size_t len) {
- const kj::ArrayPtr view((const capnp::word*)data, len);
- capnp::FlatArrayMessageReader msg(view);
- cereal::Event::Reader event = msg.getRoot();
-
- Localizer * loc = (Localizer*) localizer;
- loc->handle_log(event);
- }
-
- double localizer_get_yaw(void * localizer) {
- Localizer * loc = (Localizer*) localizer;
- return loc->x[0];
- }
- double localizer_get_bias(void * localizer) {
- Localizer * loc = (Localizer*) localizer;
- return loc->x[1];
- }
-
- double * localizer_get_state(void * localizer) {
- Localizer * loc = (Localizer*) localizer;
- return loc->x.data();
- }
-
- void localizer_set_state(void * localizer, double * state) {
- Localizer * loc = (Localizer*) localizer;
- memcpy(loc->x.data(), state, 4 * sizeof(double));
- }
-
- double localizer_get_t(void * localizer) {
- Localizer * loc = (Localizer*) localizer;
- return loc->prev_update_time;
- }
-
- double * localizer_get_P(void * localizer) {
- Localizer * loc = (Localizer*) localizer;
- return loc->P.data();
- }
-
- void localizer_set_P(void * localizer, double * P) {
- Localizer * loc = (Localizer*) localizer;
- memcpy(loc->P.data(), P, 16 * sizeof(double));
- }
-}
diff --git a/selfdrive/locationd/locationd_yawrate.h b/selfdrive/locationd/locationd_yawrate.h
deleted file mode 100644
index 58999e5f..00000000
--- a/selfdrive/locationd/locationd_yawrate.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#pragma once
-
-#include
-#include "cereal/gen/cpp/log.capnp.h"
-
-#define DEGREES_TO_RADIANS 0.017453292519943295
-
-class Localizer
-{
- Eigen::Matrix2d A;
- Eigen::Matrix2d I;
- Eigen::Matrix2d Q;
- Eigen::Matrix C_posenet;
- Eigen::Matrix C_gyro;
-
- double R_gyro;
-
- void update_state(const Eigen::Matrix &C, const double R, double current_time, double meas);
- void handle_sensor_events(capnp::List::Reader sensor_events, double current_time);
- void handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time);
- void handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time);
-
-public:
- Eigen::Vector2d x;
- Eigen::Matrix2d P;
- double steering_angle = 0;
- double car_speed = 0;
- double prev_update_time = -1;
-
- Localizer();
- void handle_log(cereal::Event::Reader event);
-
-};
diff --git a/selfdrive/locationd/models/live_kf.py b/selfdrive/locationd/models/live_kf.py
index a6a6eaf0..d2153487 100755
--- a/selfdrive/locationd/models/live_kf.py
+++ b/selfdrive/locationd/models/live_kf.py
@@ -206,7 +206,7 @@ class LiveKalman():
ObservationKind.ECEF_ORIENTATION_FROM_GPS: np.diag([.2**2, .2**2, .2**2, .2**2])}
# init filter
- self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, np.diag(self.initial_P_diag), self.dim_state, self.dim_state_err)
+ self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, np.diag(self.initial_P_diag), self.dim_state, self.dim_state_err, max_rewind_age=0.2)
@property
def x(self):
diff --git a/selfdrive/locationd/params_learner.cc b/selfdrive/locationd/params_learner.cc
deleted file mode 100644
index 66f378a1..00000000
--- a/selfdrive/locationd/params_learner.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-#include
-#include
-#include
-
-#include
-#include
-#include "cereal/gen/cpp/log.capnp.h"
-#include "cereal/gen/cpp/car.capnp.h"
-#include "params_learner.h"
-
-// #define DEBUG
-
-template
-T clip(const T& n, const T& lower, const T& upper) {
- return std::max(lower, std::min(n, upper));
-}
-
-ParamsLearner::ParamsLearner(cereal::CarParams::Reader car_params,
- double angle_offset,
- double stiffness_factor,
- double steer_ratio,
- double learning_rate) :
- ao(angle_offset * DEGREES_TO_RADIANS),
- slow_ao(angle_offset * DEGREES_TO_RADIANS),
- x(stiffness_factor),
- sR(steer_ratio) {
-
- cF0 = car_params.getTireStiffnessFront();
- cR0 = car_params.getTireStiffnessRear();
-
- l = car_params.getWheelbase();
- m = car_params.getMass();
-
- aF = car_params.getCenterToFront();
- aR = l - aF;
-
- min_sr = MIN_SR * car_params.getSteerRatio();
- max_sr = MAX_SR * car_params.getSteerRatio();
- min_sr_th = MIN_SR_TH * car_params.getSteerRatio();
- max_sr_th = MAX_SR_TH * car_params.getSteerRatio();
- alpha1 = 0.01 * learning_rate;
- alpha2 = 0.0005 * learning_rate;
- alpha3 = 0.1 * learning_rate;
- alpha4 = 1.0 * learning_rate;
-}
-
-bool ParamsLearner::update(double psi, double u, double sa) {
- if (u > 10.0 && fabs(sa) < (DEGREES_TO_RADIANS * 90.)) {
- double ao_diff = 2.0*cF0*cR0*l*u*x*(1.0*cF0*cR0*l*u*x*(ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 2)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 2));
- double new_ao = ao - alpha1 * ao_diff;
-
- double slow_ao_diff = 2.0*cF0*cR0*l*u*x*(1.0*cF0*cR0*l*u*x*(slow_ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 2)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 2));
- double new_slow_ao = slow_ao - alpha2 * slow_ao_diff;
-
- double new_x = x - alpha3 * (-2.0*cF0*cR0*l*m*pow(u, 3)*(slow_ao - sa)*(aF*cF0 - aR*cR0)*(1.0*cF0*cR0*l*u*x*(slow_ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 2)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 3)));
- double new_sR = sR - alpha4 * (-2.0*cF0*cR0*l*u*x*(slow_ao - sa)*(1.0*cF0*cR0*l*u*x*(slow_ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 3)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 2)));
-
- ao = new_ao;
- slow_ao = new_slow_ao;
- x = new_x;
- sR = new_sR;
- }
-
-#ifdef DEBUG
- std::cout << "Instant AO: " << (RADIANS_TO_DEGREES * ao) << "\tAverage AO: " << (RADIANS_TO_DEGREES * slow_ao);
- std::cout << "\tStiffness: " << x << "\t sR: " << sR << std::endl;
-#endif
-
- ao = clip(ao, -MAX_ANGLE_OFFSET, MAX_ANGLE_OFFSET);
- slow_ao = clip(slow_ao, -MAX_ANGLE_OFFSET, MAX_ANGLE_OFFSET);
- x = clip(x, MIN_STIFFNESS, MAX_STIFFNESS);
- sR = clip(sR, min_sr, max_sr);
-
- bool valid = fabs(slow_ao) < MAX_ANGLE_OFFSET_TH;
- valid = valid && sR > min_sr_th;
- valid = valid && sR < max_sr_th;
- return valid;
-}
-
-
-extern "C" {
- void *params_learner_init(size_t len, char * params, double angle_offset, double stiffness_factor, double steer_ratio, double learning_rate) {
-
- auto amsg = kj::heapArray((len / sizeof(capnp::word)) + 1);
- memcpy(amsg.begin(), params, len);
-
- capnp::FlatArrayMessageReader cmsg(amsg);
- cereal::CarParams::Reader car_params = cmsg.getRoot();
-
- ParamsLearner * p = new ParamsLearner(car_params, angle_offset, stiffness_factor, steer_ratio, learning_rate);
- return (void*)p;
- }
-
- bool params_learner_update(void * params_learner, double psi, double u, double sa) {
- ParamsLearner * p = (ParamsLearner*) params_learner;
- return p->update(psi, u, sa);
- }
-
- double params_learner_get_ao(void * params_learner){
- ParamsLearner * p = (ParamsLearner*) params_learner;
- return p->ao;
- }
-
- double params_learner_get_x(void * params_learner){
- ParamsLearner * p = (ParamsLearner*) params_learner;
- return p->x;
- }
-
- double params_learner_get_slow_ao(void * params_learner){
- ParamsLearner * p = (ParamsLearner*) params_learner;
- return p->slow_ao;
- }
-
- double params_learner_get_sR(void * params_learner){
- ParamsLearner * p = (ParamsLearner*) params_learner;
- return p->sR;
- }
-}
diff --git a/selfdrive/locationd/params_learner.h b/selfdrive/locationd/params_learner.h
deleted file mode 100644
index 4d97551b..00000000
--- a/selfdrive/locationd/params_learner.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#define DEGREES_TO_RADIANS 0.017453292519943295
-#define RADIANS_TO_DEGREES (1.0 / DEGREES_TO_RADIANS)
-
-#define MAX_ANGLE_OFFSET (10.0 * DEGREES_TO_RADIANS)
-#define MAX_ANGLE_OFFSET_TH (9.0 * DEGREES_TO_RADIANS)
-#define MIN_STIFFNESS 0.5
-#define MAX_STIFFNESS 2.0
-#define MIN_SR 0.5
-#define MAX_SR 2.0
-#define MIN_SR_TH 0.55
-#define MAX_SR_TH 1.9
-
-class ParamsLearner {
- double cF0, cR0;
- double aR, aF;
- double l, m;
-
- double min_sr, max_sr, min_sr_th, max_sr_th;
- double alpha1, alpha2, alpha3, alpha4;
-
-public:
- double ao;
- double slow_ao;
- double x, sR;
-
- ParamsLearner(cereal::CarParams::Reader car_params,
- double angle_offset,
- double stiffness_factor,
- double steer_ratio,
- double learning_rate);
-
- bool update(double psi, double u, double sa);
-};
diff --git a/selfdrive/locationd/paramsd.cc b/selfdrive/locationd/paramsd.cc
deleted file mode 100644
index aee957bc..00000000
--- a/selfdrive/locationd/paramsd.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include "json11.hpp"
-
-#include "common/swaglog.h"
-#include "common/params.h"
-#include "common/timing.h"
-
-#include "messaging.hpp"
-#include "locationd_yawrate.h"
-#include "params_learner.h"
-
-#include "common/util.h"
-
-void sigpipe_handler(int sig) {
- LOGE("SIGPIPE received");
-}
-
-
-int main(int argc, char *argv[]) {
- signal(SIGPIPE, (sighandler_t)sigpipe_handler);
-
- SubMaster sm({"controlsState", "sensorEvents", "cameraOdometry"});
- PubMaster pm({"liveParameters"});
-
- Localizer localizer;
-
- // Read car params
- std::vector params;
- LOGW("waiting for params to set vehicle model");
- while (true) {
- params = read_db_bytes("CarParams");
- if (params.size() > 0) break;
- usleep(100*1000);
- }
- LOGW("got %d bytes CarParams", params.size());
-
- // make copy due to alignment issues
- auto amsg = kj::heapArray((params.size() / sizeof(capnp::word)) + 1);
- memcpy(amsg.begin(), params.data(), params.size());
-
- capnp::FlatArrayMessageReader cmsg(amsg);
- cereal::CarParams::Reader car_params = cmsg.getRoot();
-
- // Read params from previous run
- std::string fingerprint = car_params.getCarFingerprint();
- std::string vin = car_params.getCarVin();
- double sR = car_params.getSteerRatio();
- double x = 1.0;
- double ao = 0.0;
- std::vector live_params = read_db_bytes("LiveParameters");
- if (live_params.size() > 0){
- std::string err;
- std::string str(live_params.begin(), live_params.end());
- auto json = json11::Json::parse(str, err);
- if (json.is_null() || !err.empty()) {
- std::string log = "Error parsing json: " + err;
- LOGW(log.c_str());
- } else {
- std::string new_fingerprint = json["carFingerprint"].string_value();
- std::string new_vin = json["carVin"].string_value();
-
- if (fingerprint == new_fingerprint && vin == new_vin) {
- std::string log = "Parameter starting with: " + str;
- LOGW(log.c_str());
-
- sR = json["steerRatio"].number_value();
- x = json["stiffnessFactor"].number_value();
- ao = json["angleOffsetAverage"].number_value();
- }
- }
- }
-
- ParamsLearner learner(car_params, ao, x, sR, 1.0);
-
- // Main loop
- int save_counter = 0;
- while (true){
- if (sm.update(100) == 0) continue;
-
- if (sm.updated("controlsState")){
- localizer.handle_log(sm["controlsState"]);
- save_counter++;
-
- double yaw_rate = -localizer.x[0];
- bool valid = learner.update(yaw_rate, localizer.car_speed, localizer.steering_angle);
-
- double angle_offset_degrees = RADIANS_TO_DEGREES * learner.ao;
- double angle_offset_average_degrees = RADIANS_TO_DEGREES * learner.slow_ao;
-
- capnp::MallocMessageBuilder msg;
- cereal::Event::Builder event = msg.initRoot();
- event.setLogMonoTime(nanos_since_boot());
- auto live_params = event.initLiveParameters();
- live_params.setValid(valid);
- live_params.setYawRate(localizer.x[0]);
- live_params.setGyroBias(localizer.x[1]);
- live_params.setAngleOffset(angle_offset_degrees);
- live_params.setAngleOffsetAverage(angle_offset_average_degrees);
- live_params.setStiffnessFactor(learner.x);
- live_params.setSteerRatio(learner.sR);
-
- pm.send("liveParameters", msg);
-
- // Save parameters every minute
- if (save_counter % 6000 == 0) {
- json11::Json json = json11::Json::object {
- {"carVin", vin},
- {"carFingerprint", fingerprint},
- {"steerRatio", learner.sR},
- {"stiffnessFactor", learner.x},
- {"angleOffsetAverage", angle_offset_average_degrees},
- };
-
- std::string out = json.dump();
- std::async(std::launch::async,
- [out]{
- write_db_value("LiveParameters", out.c_str(), out.length());
- });
- }
- }
- if (sm.updated("sensorEvents")){
- localizer.handle_log(sm["sensorEvents"]);
- }
- if (sm.updated("cameraOdometry")){
- localizer.handle_log(sm["cameraOdometry"]);
- }
- }
- return 0;
-}
diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py
index 5b14bba8..34bfc789 100644
--- a/selfdrive/loggerd/uploader.py
+++ b/selfdrive/loggerd/uploader.py
@@ -247,7 +247,8 @@ def uploader_fn(exit_event):
backoff = 0.1
while True:
- allow_raw_upload = (params.get("IsUploadRawEnabled") != b"0")
+ offroad = params.get("IsOffroad") == b'1'
+ allow_raw_upload = (params.get("IsUploadRawEnabled") != b"0") and offroad
on_hotspot = is_on_hotspot()
on_wifi = is_on_wifi()
should_upload = on_wifi and not on_hotspot
@@ -257,7 +258,6 @@ def uploader_fn(exit_event):
d = uploader.next_file_to_upload(with_raw=allow_raw_upload and should_upload)
if d is None: # Nothing to upload
- offroad = params.get("IsOffroad") == b'1'
time.sleep(60 if offroad else 5)
continue
diff --git a/selfdrive/manager.py b/selfdrive/manager.py
index a81f80e9..e9ef36a2 100755
--- a/selfdrive/manager.py
+++ b/selfdrive/manager.py
@@ -19,7 +19,7 @@ WEBCAM = os.getenv("WEBCAM") is not None
sys.path.append(os.path.join(BASEDIR, "pyextra"))
os.environ['BASEDIR'] = BASEDIR
-TOTAL_SCONS_NODES = 1140
+TOTAL_SCONS_NODES = 1005
prebuilt = os.path.exists(os.path.join(BASEDIR, 'prebuilt'))
# Create folders needed for msgq
@@ -70,19 +70,15 @@ def unblock_stdout():
if __name__ == "__main__":
unblock_stdout()
-if __name__ == "__main__" and ANDROID:
- from common.spinner import Spinner
- from common.text_window import TextWindow
-else:
- from common.spinner import FakeSpinner as Spinner
- from common.text_window import FakeTextWindow as TextWindow
+from common.spinner import Spinner
+from common.text_window import TextWindow
import importlib
import traceback
from multiprocessing import Process
# Run scons
-spinner = Spinner()
+spinner = Spinner(noop=(__name__ != "__main__" or not ANDROID))
spinner.update("0")
if not prebuilt:
@@ -142,8 +138,9 @@ if not prebuilt:
cloudlog.error("scons build failed\n" + error_s)
# 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\n \n" + error_s) as t:
+ with TextWindow("openpilot failed to build\n \n" + error_s, noop=no_ui) as t:
t.wait_for_exit()
exit(1)
@@ -192,7 +189,6 @@ managed_processes = {
"updated": "selfdrive.updated",
"dmonitoringmodeld": ("selfdrive/modeld", ["./dmonitoringmodeld"]),
"modeld": ("selfdrive/modeld", ["./modeld"]),
- "driverview": "selfdrive.monitoring.driverview",
}
daemon_processes = {
@@ -245,6 +241,12 @@ car_started_processes = [
'locationd',
]
+driver_view_processes = [
+ 'camerad',
+ 'dmonitoringd',
+ 'dmonitoringmodeld'
+]
+
if WEBCAM:
car_started_processes += [
'dmonitoringmodeld',
@@ -387,6 +389,14 @@ def cleanup_all_processes(signal, frame):
kill_managed_process(name)
cloudlog.info("everything is dead")
+
+def send_managed_process_signal(name, sig):
+ if name not in running or name not in managed_processes:
+ return
+ cloudlog.info(f"sending signal {sig} to {name}")
+ os.kill(running[name].pid, sig)
+
+
# ****************** run loop ******************
def manager_init(should_register=True):
@@ -455,6 +465,7 @@ def manager_thread():
for k in os.getenv("BLOCK").split(","):
del managed_processes[k]
+ started_prev = False
logger_dead = False
while 1:
@@ -473,7 +484,7 @@ def manager_thread():
if msg.thermal.freeSpace < 0.05:
logger_dead = True
- if msg.thermal.started and "driverview" not in running:
+ if msg.thermal.started:
for p in car_started_processes:
if p == "loggerd" and logger_dead:
kill_managed_process(p)
@@ -481,13 +492,24 @@ def manager_thread():
start_managed_process(p)
else:
logger_dead = False
+ driver_view = params.get("IsDriverViewEnabled") == b"1"
+
+ # TODO: refactor how manager manages processes
for p in reversed(car_started_processes):
- kill_managed_process(p)
- # this is ugly
- if "driverview" not in running and params.get("IsDriverViewEnabled") == b"1":
- start_managed_process("driverview")
- elif "driverview" in running and params.get("IsDriverViewEnabled") == b"0":
- kill_managed_process("driverview")
+ if p not in driver_view_processes or not driver_view:
+ kill_managed_process(p)
+
+ for p in driver_view_processes:
+ if driver_view:
+ start_managed_process(p)
+ else:
+ kill_managed_process(p)
+
+ # trigger an update after going offroad
+ if started_prev:
+ send_managed_process_signal("updated", signal.SIGHUP)
+
+ started_prev = msg.thermal.started
# check the status of all processes, did any of them die?
running_list = ["%s%s\u001b[0m" % ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p) for p in running]
diff --git a/selfdrive/modeld/dmonitoringmodeld.cc b/selfdrive/modeld/dmonitoringmodeld.cc
index 140b567a..28776f94 100644
--- a/selfdrive/modeld/dmonitoringmodeld.cc
+++ b/selfdrive/modeld/dmonitoringmodeld.cc
@@ -56,7 +56,6 @@ int main(int argc, char **argv) {
buf = visionstream_get(&stream, &extra);
if (buf == NULL) {
printf("visionstream get failed\n");
- visionstream_destroy(&stream);
break;
}
//printf("frame_id: %d %dx%d\n", extra.frame_id, buf_info.width, buf_info.height);
@@ -84,11 +83,9 @@ int main(int argc, char **argv) {
LOGD("dmonitoring process: %.2fms, from last %.2fms", t2-t1, t1-last);
last = t1;
}
-
+ visionstream_destroy(&stream);
}
- visionstream_destroy(&stream);
-
dmonitoring_free(&dmonitoringmodel);
return 0;
diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc
index 68b37012..33dafc86 100644
--- a/selfdrive/modeld/modeld.cc
+++ b/selfdrive/modeld/modeld.cc
@@ -181,7 +181,7 @@ int main(int argc, char **argv) {
cl_mem yuv_cl;
VisionBuf yuv_ion = visionbuf_allocate_cl(buf_info.buf_len, device_id, context, &yuv_cl);
- uint32_t last_vipc_frame_id = 0;
+ uint32_t frame_id = 0, last_vipc_frame_id = 0;
double last = 0;
int desire = -1;
while (!do_exit) {
@@ -190,7 +190,6 @@ int main(int argc, char **argv) {
buf = visionstream_get(&stream, &extra);
if (buf == NULL) {
LOGW("visionstream get failed");
- visionstream_destroy(&stream);
break;
}
@@ -202,6 +201,7 @@ int main(int argc, char **argv) {
if (sm.update(0) > 0){
// TODO: path planner timeout?
desire = ((int)sm["pathPlan"].getPathPlan().getDesire()) - 1;
+ frame_id = sm["frame"].getFrame().getFrameId();
}
double mt1 = 0, mt2 = 0;
@@ -212,8 +212,7 @@ int main(int argc, char **argv) {
}
mat3 model_transform = matmul3(yuv_transform, transform);
- uint32_t frame_id = sm["frame"].getFrame().getFrameId();
-
+
mt1 = millis_since_boot();
// TODO: don't make copies!
@@ -232,17 +231,16 @@ int main(int argc, char **argv) {
model_publish(pm, extra.frame_id, frame_id, vipc_dropped_frames, frame_drop_perc, model_buf, extra.timestamp_eof);
posenet_publish(pm, extra.frame_id, frame_id, vipc_dropped_frames, frame_drop_perc, model_buf, extra.timestamp_eof);
- LOGD("model process: %.2fms, from last %.2fms, vipc_frame_id %zu, frame_id, %zu, frame_drop %.3f%", mt2-mt1, mt1-last, extra.frame_id, frame_id, frame_drop_perc);
+ LOGD("model process: %.2fms, from last %.2fms, vipc_frame_id %zu, frame_id, %zu, frame_drop %.3f", mt2-mt1, mt1-last, extra.frame_id, frame_id, frame_drop_perc);
last = mt1;
last_vipc_frame_id = extra.frame_id;
}
}
visionbuf_free(&yuv_ion);
+ visionstream_destroy(&stream);
}
- visionstream_destroy(&stream);
-
model_free(&model);
LOG("joining live_thread");
diff --git a/selfdrive/modeld/models/commonmodel.c b/selfdrive/modeld/models/commonmodel.c
index 93fceb3a..eebf4761 100644
--- a/selfdrive/modeld/models/commonmodel.c
+++ b/selfdrive/modeld/models/commonmodel.c
@@ -15,13 +15,13 @@ void frame_init(ModelFrame* frame, int width, int height,
frame->transformed_height = height;
frame->transformed_y_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE,
- frame->transformed_width*frame->transformed_height, NULL, &err);
+ (size_t)frame->transformed_width*frame->transformed_height, NULL, &err);
assert(err == 0);
frame->transformed_u_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE,
- (frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err);
+ (size_t)(frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err);
assert(err == 0);
frame->transformed_v_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE,
- (frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err);
+ (size_t)(frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err);
assert(err == 0);
frame->net_input_size = ((width*height*3)/2)*sizeof(float);
diff --git a/selfdrive/modeld/models/dmonitoring.cc b/selfdrive/modeld/models/dmonitoring.cc
index 15b28dd8..4f4203a3 100644
--- a/selfdrive/modeld/models/dmonitoring.cc
+++ b/selfdrive/modeld/models/dmonitoring.cc
@@ -5,9 +5,9 @@
#include
-#define MODEL_WIDTH 160
-#define MODEL_HEIGHT 320
-#define FULL_W 426
+#define MODEL_WIDTH 320
+#define MODEL_HEIGHT 640
+#define FULL_W 852
#if defined(QCOM) || defined(QCOM2)
#define input_lambda(x) (x - 128.f) * 0.0078125f
@@ -136,6 +136,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_
memcpy(&ret.right_eye_prob, &s->output[30], sizeof ret.right_eye_prob);
memcpy(&ret.left_blink_prob, &s->output[31], sizeof ret.right_eye_prob);
memcpy(&ret.right_blink_prob, &s->output[32], sizeof ret.right_eye_prob);
+ memcpy(&ret.sg_prob, &s->output[33], sizeof ret.sg_prob);
ret.face_orientation_meta[0] = softplus(ret.face_orientation_meta[0]);
ret.face_orientation_meta[1] = softplus(ret.face_orientation_meta[1]);
ret.face_orientation_meta[2] = softplus(ret.face_orientation_meta[2]);
@@ -166,6 +167,7 @@ void dmonitoring_publish(PubMaster &pm, uint32_t frame_id, const DMonitoringResu
framed.setRightEyeProb(res.right_eye_prob);
framed.setLeftBlinkProb(res.left_blink_prob);
framed.setRightBlinkProb(res.right_blink_prob);
+ framed.setSgProb(res.sg_prob);
pm.send("driverState", msg);
}
diff --git a/selfdrive/modeld/models/dmonitoring.h b/selfdrive/modeld/models/dmonitoring.h
index 83d014f8..439b9c00 100644
--- a/selfdrive/modeld/models/dmonitoring.h
+++ b/selfdrive/modeld/models/dmonitoring.h
@@ -9,7 +9,7 @@
extern "C" {
#endif
-#define OUTPUT_SIZE 33
+#define OUTPUT_SIZE 34
#define RHD_CHECK_INTERVAL 10
typedef struct DMonitoringResult {
@@ -22,6 +22,7 @@ typedef struct DMonitoringResult {
float right_eye_prob;
float left_blink_prob;
float right_blink_prob;
+ float sg_prob;
} DMonitoringResult;
typedef struct DMonitoringModelState {
diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc
index af481712..f58e7b19 100644
--- a/selfdrive/modeld/models/driving.cc
+++ b/selfdrive/modeld/models/driving.cc
@@ -9,9 +9,6 @@
#include "common/params.h"
#include "driving.h"
-
-
-
#define PATH_IDX 0
#define LL_IDX PATH_IDX + MODEL_PATH_DISTANCE*2 + 1
#define RL_IDX LL_IDX + MODEL_PATH_DISTANCE*2 + 2
@@ -48,17 +45,14 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context, int t
#endif
#ifdef DESIRE
- s->prev_desire = (float*)malloc(DESIRE_LEN * sizeof(float));
- for (int i = 0; i < DESIRE_LEN; i++) s->prev_desire[i] = 0.0;
- s->pulse_desire = (float*)malloc(DESIRE_LEN * sizeof(float));
- for (int i = 0; i < DESIRE_LEN; i++) s->pulse_desire[i] = 0.0;
- s->m->addDesire(s->pulse_desire, DESIRE_LEN);
+ s->prev_desire = std::make_unique(DESIRE_LEN);
+ s->pulse_desire = std::make_unique(DESIRE_LEN);
+ s->m->addDesire(s->pulse_desire.get(), DESIRE_LEN);
#endif
#ifdef TRAFFIC_CONVENTION
- s->traffic_convention = (float*)malloc(TRAFFIC_CONVENTION_LEN * sizeof(float));
- for (int i = 0; i < TRAFFIC_CONVENTION_LEN; i++) s->traffic_convention[i] = 0.0;
- s->m->addTrafficConvention(s->traffic_convention, TRAFFIC_CONVENTION_LEN);
+ s->traffic_convention = std::make_unique(TRAFFIC_CONVENTION_LEN);
+ s->m->addTrafficConvention(s->traffic_convention.get(), TRAFFIC_CONVENTION_LEN);
std::vector result = read_db_bytes("IsRHD");
if (result.size() > 0) {
@@ -79,8 +73,6 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context, int t
}
}
-
-
ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q,
cl_mem yuv_cl, int width, int height,
mat3 transform, void* sock,
@@ -100,7 +92,6 @@ ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q,
}
#endif
-
//for (int i = 0; i < OUTPUT_SIZE + TEMPORAL_SIZE; i++) { printf("%f ", s->output[i]); } printf("\n");
float *new_frame_buf = frame_prepare(&s->frame, q, yuv_cl, width, height, transform);
@@ -163,7 +154,6 @@ void poly_fit(float *in_pts, float *in_stds, float *out, int valid_len) {
out[3] = y0;
}
-
void fill_path(cereal::ModelData::PathData::Builder path, const float * data, bool has_prob, const float offset) {
float points_arr[MODEL_PATH_DISTANCE];
float stds_arr[MODEL_PATH_DISTANCE];
diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h
index 83d967d2..2bf4d615 100644
--- a/selfdrive/modeld/models/driving.h
+++ b/selfdrive/modeld/models/driving.h
@@ -14,6 +14,7 @@
#include "runners/run.h"
#include
+#include
#include "messaging.hpp"
#define MODEL_WIDTH 512
@@ -58,11 +59,11 @@ typedef struct ModelState {
float *input_frames;
RunModel *m;
#ifdef DESIRE
- float *prev_desire;
- float *pulse_desire;
+ std::unique_ptr prev_desire;
+ std::unique_ptr pulse_desire;
#endif
#ifdef TRAFFIC_CONVENTION
- float *traffic_convention;
+ std::unique_ptr traffic_convention;
#endif
} ModelState;
diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py
index 4939d604..66a1f2d8 100755
--- a/selfdrive/monitoring/dmonitoringd.py
+++ b/selfdrive/monitoring/dmonitoringd.py
@@ -8,14 +8,11 @@ from selfdrive.controls.lib.events import Events
from selfdrive.monitoring.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS, MAX_TERMINAL_DURATION
from selfdrive.locationd.calibration_helpers import Calibration
+
def dmonitoringd_thread(sm=None, pm=None):
gc.disable()
-
- # start the loop
set_realtime_priority(53)
- params = Params()
-
# Pub/Sub Sockets
if pm is None:
pm = messaging.PubMaster(['dMonitoringState'])
@@ -23,40 +20,38 @@ def dmonitoringd_thread(sm=None, pm=None):
if sm is None:
sm = messaging.SubMaster(['driverState', 'liveCalibration', 'carState', 'model'])
+ params = Params()
+
driver_status = DriverStatus()
is_rhd = params.get("IsRHD")
- if is_rhd is not None:
- driver_status.is_rhd_region = bool(int(is_rhd))
- driver_status.is_rhd_region_checked = True
+ driver_status.is_rhd_region = is_rhd == b"1"
+ driver_status.is_rhd_region_checked = is_rhd is not 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
+ sm['carState'].gasPressed = False
sm['carState'].standstill = True
- cal_rpy = [0, 0, 0]
v_cruise_last = 0
driver_engaged = False
+ offroad = params.get("IsOffroad") == b"1"
# 10Hz <- dmonitoringmodeld
while True:
sm.update()
- # Handle calibration
- if sm.updated['liveCalibration']:
- if sm['liveCalibration'].calStatus == Calibration.CALIBRATED:
- if len(sm['liveCalibration'].rpyCalib) == 3:
- cal_rpy = sm['liveCalibration'].rpyCalib
-
# Get interaction
if sm.updated['carState']:
v_cruise = sm['carState'].cruiseState.speed
driver_engaged = len(sm['carState'].buttonEvents) > 0 or \
v_cruise != v_cruise_last or \
- sm['carState'].steeringPressed
+ sm['carState'].steeringPressed or \
+ sm['carState'].gasPressed
if driver_engaged:
driver_status.update(Events(), True, sm['carState'].cruiseState.enabled, sm['carState'].standstill)
v_cruise_last = v_cruise
@@ -68,14 +63,16 @@ def dmonitoringd_thread(sm=None, pm=None):
# Get data from dmonitoringmodeld
if sm.updated['driverState']:
events = Events()
- driver_status.get_pose(sm['driverState'], cal_rpy, sm['carState'].vEgo, sm['carState'].cruiseState.enabled)
- # Block any engage after certain distrations
+ driver_status.get_pose(sm['driverState'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['carState'].cruiseState.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)
- # dMonitoringState packet
+ # build dMonitoringState packet
dat = messaging.new_message('dMonitoringState')
dat.dMonitoringState = {
"events": events.to_msg(),
@@ -93,7 +90,7 @@ def dmonitoringd_thread(sm=None, pm=None):
"awarenessPassive": driver_status.awareness_passive,
"isLowStd": driver_status.pose.low_std,
"hiStdCount": driver_status.hi_stds,
- "isPreview": False,
+ "isPreview": offroad,
}
pm.send('dMonitoringState', dat)
diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py
index 7cacd770..76487e24 100644
--- a/selfdrive/monitoring/driver_monitor.py
+++ b/selfdrive/monitoring/driver_monitor.py
@@ -21,8 +21,9 @@ _DISTRACTED_TIME = 11.
_DISTRACTED_PRE_TIME_TILL_TERMINAL = 8.
_DISTRACTED_PROMPT_TIME_TILL_TERMINAL = 6.
-_FACE_THRESHOLD = 0.4
+_FACE_THRESHOLD = 0.6
_EYE_THRESHOLD = 0.6
+_SG_THRESHOLD = 0.5
_BLINK_THRESHOLD = 0.5 # 0.225
_BLINK_THRESHOLD_SLACK = 0.65
_BLINK_THRESHOLD_STRICT = 0.5
@@ -189,8 +190,8 @@ class DriverStatus():
# self.pose.roll_std = driver_state.faceOrientationStd[2]
model_std_max = max(self.pose.pitch_std, self.pose.yaw_std)
self.pose.low_std = model_std_max < _POSESTD_THRESHOLD
- self.blink.left_blink = driver_state.leftBlinkProb * (driver_state.leftEyeProb > _EYE_THRESHOLD)
- self.blink.right_blink = driver_state.rightBlinkProb * (driver_state.rightEyeProb > _EYE_THRESHOLD)
+ self.blink.left_blink = driver_state.leftBlinkProb * (driver_state.leftEyeProb > _EYE_THRESHOLD) * (driver_state.sgProb < _SG_THRESHOLD)
+ self.blink.right_blink = driver_state.rightBlinkProb * (driver_state.rightEyeProb > _EYE_THRESHOLD) * (driver_state.sgProb < _SG_THRESHOLD)
self.face_detected = driver_state.faceProb > _FACE_THRESHOLD and \
abs(driver_state.facePosition[0]) <= 0.4 and abs(driver_state.facePosition[1]) <= 0.45
diff --git a/selfdrive/monitoring/driverview.py b/selfdrive/monitoring/driverview.py
deleted file mode 100755
index 4581a065..00000000
--- a/selfdrive/monitoring/driverview.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python3
-import os
-import subprocess
-import multiprocessing
-import signal
-import time
-
-import cereal.messaging as messaging
-from common.params import Params
-
-from common.basedir import BASEDIR
-
-KILL_TIMEOUT = 15
-
-
-def send_controls_packet(pm):
- while True:
- dat = messaging.new_message('controlsState')
- dat.controlsState = {
- "rearViewCam": True,
- }
- pm.send('controlsState', dat)
- time.sleep(0.01)
-
-
-def send_dmon_packet(pm, d):
- dat = messaging.new_message('dMonitoringState')
- dat.dMonitoringState = {
- "isRHD": d[0],
- "rhdChecked": d[1],
- "isPreview": d[2],
- }
- pm.send('dMonitoringState', dat)
-
-
-def main():
- pm = messaging.PubMaster(['controlsState', 'dMonitoringState'])
- controls_sender = multiprocessing.Process(target=send_controls_packet, args=[pm])
- controls_sender.start()
-
- # TODO: refactor with manager start/kill
- proc_cam = subprocess.Popen(os.path.join(BASEDIR, "selfdrive/camerad/camerad"), cwd=os.path.join(BASEDIR, "selfdrive/camerad"))
- proc_mon = subprocess.Popen(os.path.join(BASEDIR, "selfdrive/modeld/dmonitoringmodeld"), cwd=os.path.join(BASEDIR, "selfdrive/modeld"))
-
- params = Params()
- is_rhd = False
- is_rhd_checked = False
- should_exit = False
-
- def terminate(signalNumber, frame):
- print('got SIGTERM, exiting..')
- should_exit = True
- send_dmon_packet(pm, [is_rhd, is_rhd_checked, not should_exit])
- proc_cam.send_signal(signal.SIGINT)
- proc_mon.send_signal(signal.SIGINT)
- kill_start = time.time()
- while proc_cam.poll() is None:
- if time.time() - kill_start > KILL_TIMEOUT:
- from selfdrive.swaglog import cloudlog
- cloudlog.critical("FORCE REBOOTING PHONE!")
- os.system("date >> /sdcard/unkillable_reboot")
- os.system("reboot")
- raise RuntimeError
- continue
- controls_sender.terminate()
- exit()
-
- signal.signal(signal.SIGTERM, terminate)
-
- while True:
- send_dmon_packet(pm, [is_rhd, is_rhd_checked, not should_exit])
-
- if not is_rhd_checked:
- is_rhd = params.get("IsRHD") == b"1"
- is_rhd_checked = True
-
- time.sleep(0.01)
-
-
-if __name__ == '__main__':
- main()
diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py
index 2a6cf501..1e53ef42 100644
--- a/selfdrive/test/helpers.py
+++ b/selfdrive/test/helpers.py
@@ -4,8 +4,19 @@ from nose.tools import nottest
from common.android import ANDROID
from common.apk import update_apks, start_offroad, pm_apply_packages, android_packages
+from common.params import Params
+from selfdrive.version import training_version, terms_version
from selfdrive.manager import start_managed_process, kill_managed_process, get_running
+def set_params_enabled():
+ params = Params()
+ params.put("HasAcceptedTerms", terms_version)
+ params.put("HasCompletedSetup", "1")
+ params.put("OpenpilotEnabledToggle", "1")
+ params.put("CommunityFeaturesToggle", "1")
+ params.put("Passive", "0")
+ params.put("CompletedTrainingVersion", training_version)
+
def phone_only(x):
if ANDROID:
return x
diff --git a/selfdrive/test/id_rsa b/selfdrive/test/id_rsa
deleted file mode 100644
index 3f269afe..00000000
--- a/selfdrive/test/id_rsa
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+iXXq30Tq+J5N
-Kat3KWHCzcmwZ55nGh6WggAqECa5CasBlM9VeROpVu3beA+5h0MibRgbD4DMtVXB
-t6gEvZ8nd04E7eLA9LTZyFDZ7SkSOVj4oXOQsT0GnJmKrASW5KslTWqVzTfo2XCt
-Z+004ikLxmyFeBO8NOcErW1pa8gFdQDToH9FrA7kgysic/XVESTOoe7XlzRoe/eZ
-acEQ+jtnmFd21A4aEADkk00Ahjr0uKaJiLUAPatxs2icIXWpgYtfqqtaKF23wSt6
-1OTu6cAwXbOWr3m+IUSRUO0IRzEIQS3z1jfd1svgzSgSSwZ1Lhj4AoKxIEAIc8qJ
-rO4uymCJAgMBAAECggEBAISFevxHGdoL3Z5xkw6oO5SQKO2GxEeVhRzNgmu/HA+q
-x8OryqD6O1CWY4037kft6iWxlwiLOdwna2P25ueVM3LxqdQH2KS4DmlCx+kq6FwC
-gv063fQPMhC9LpWimvaQSPEC7VUPjQlo4tPY6sTTYBUOh0A1ihRm/x7juKuQCWix
-Cq8C/DVnB1X4mGj+W3nJc5TwVJtgJbbiBrq6PWrhvB/3qmkxHRL7dU2SBb2iNRF1
-LLY30dJx/cD73UDKNHrlrsjk3UJc29Mp4/MladKvUkRqNwlYxSuAtJV0nZ3+iFkL
-s3adSTHdJpClQer45R51rFDlVsDz2ZBpb/hRNRoGDuECgYEA6A1EixLq7QYOh3cb
-Xhyh3W4kpVvA/FPfKH1OMy3ONOD/Y9Oa+M/wthW1wSoRL2n+uuIW5OAhTIvIEivj
-6bAZsTT3twrvOrvYu9rx9aln4p8BhyvdjeW4kS7T8FP5ol6LoOt2sTP3T1LOuJPO
-uQvOjlKPKIMh3c3RFNWTnGzMPa0CgYEA0jNiPLxP3A2nrX0keKDI+VHuvOY88gdh
-0W5BuLMLovOIDk9aQFIbBbMuW1OTjHKv9NK+Lrw+YbCFqOGf1dU/UN5gSyE8lX/Q
-FsUGUqUZx574nJZnOIcy3ONOnQLcvHAQToLFAGUd7PWgP3CtHkt9hEv2koUwL4vo
-ikTP1u9Gkc0CgYEA2apoWxPZrY963XLKBxNQecYxNbLFaWq67t3rFnKm9E8BAICi
-4zUaE5J1tMVi7Vi9iks9Ml9SnNyZRQJKfQ+kaebHXbkyAaPmfv+26rqHKboA0uxA
-nDOZVwXX45zBkp6g1sdHxJx8JLoGEnkC9eyvSi0C//tRLx86OhLErXwYcNkCf1it
-VMRKrWYoXJTUNo6tRhvodM88UnnIo3u3CALjhgU4uC1RTMHV4ZCGBwiAOb8GozSl
-s5YD1E1iKwEULloHnK6BIh6P5v8q7J6uf/xdqoKMjlWBHgq6/roxKvkSPA1DOZ3l
-jTadcgKFnRUmc+JT9p/ZbCxkA/ALFg8++G+0ghECgYA8vG3M/utweLvq4RI7l7U7
-b+i2BajfK2OmzNi/xugfeLjY6k2tfQGRuv6ppTjehtji2uvgDWkgjJUgPfZpir3I
-RsVMUiFgloWGHETOy0Qvc5AwtqTJFLTD1Wza2uBilSVIEsg6Y83Gickh+ejOmEsY
-6co17RFaAZHwGfCFFjO76Q==
------END RSA PRIVATE KEY-----
diff --git a/selfdrive/test/phone_ci.py b/selfdrive/test/phone_ci.py
deleted file mode 100755
index a3a966ce..00000000
--- a/selfdrive/test/phone_ci.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python3
-import paramiko # pylint: disable=import-error
-import os
-import sys
-import re
-import time
-import socket
-
-
-SOURCE_DIR = "/data/openpilot_source/"
-TEST_DIR = "/data/openpilot/"
-
-def run_on_phone(test_cmd):
-
- eon_ip = os.environ.get('eon_ip', None)
- if eon_ip is None:
- raise Exception("'eon_ip' not set")
-
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-
- key_file = open(os.path.join(os.path.dirname(__file__), "id_rsa"))
- key = paramiko.RSAKey.from_private_key(key_file)
-
- print("SSH to phone at {}".format(eon_ip))
-
- # try connecting for one minute
- t_start = time.time()
- while True:
- try:
- ssh.connect(hostname=eon_ip, port=8022, pkey=key, timeout=10)
- except (paramiko.ssh_exception.SSHException, socket.timeout, paramiko.ssh_exception.NoValidConnectionsError):
- print("Connection failed")
- if time.time() - t_start > 60:
- raise
- else:
- break
- time.sleep(1)
-
- branch = os.environ['GIT_BRANCH']
- commit = os.environ.get('GIT_COMMIT', branch)
-
- conn = ssh.invoke_shell()
-
- # pass in all environment variables prefixed with 'CI_'
- for k, v in os.environ.items():
- if k.startswith("CI_") or k in ["GIT_BRANCH", "GIT_COMMIT"]:
- conn.send(f"export {k}='{v}'\n")
- conn.send("export CI=1\n")
-
- # clear scons cache dirs that haven't been written to in one day
- conn.send("cd /tmp && find -name 'scons_cache_*' -type d -maxdepth 1 -mtime 1 -exec rm -rf '{}' \\;\n")
-
- # set up environment
- conn.send(f"cd {SOURCE_DIR}\n")
- conn.send("git reset --hard\n")
- conn.send("git fetch origin\n")
- conn.send("find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \\;\n")
- conn.send(f"git reset --hard {commit}\n")
- conn.send(f"git checkout {commit}\n")
- conn.send("git clean -xdf\n")
- conn.send("git submodule update --init\n")
- conn.send("git submodule foreach --recursive git reset --hard\n")
- conn.send("git submodule foreach --recursive git clean -xdf\n")
- conn.send('echo "git took $SECONDS seconds"\n')
-
- conn.send(f"rsync -a --delete {SOURCE_DIR} {TEST_DIR}\n")
-
- # run the test
- conn.send(test_cmd + "\n")
-
- # get the result and print it back out
- conn.send('echo "RESULT:" $?\n')
- conn.send("exit\n")
-
- dat = b""
- conn.settimeout(240)
-
- while True:
- try:
- recvd = conn.recv(4096)
- except socket.timeout:
- print("connection to phone timed out")
- sys.exit(1)
-
- if len(recvd) == 0:
- break
-
- dat += recvd
- sys.stdout.buffer.write(recvd)
- sys.stdout.flush()
-
- return_code = int(re.findall(rb'^RESULT: (\d+)', dat[-1024:], flags=re.MULTILINE)[0])
- sys.exit(return_code)
-
-
-if __name__ == "__main__":
- run_on_phone(sys.argv[1])
diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh
new file mode 100755
index 00000000..e8228ce7
--- /dev/null
+++ b/selfdrive/test/setup_device_ci.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/bash -e
+
+export SOURCE_DIR="/data/openpilot_source/"
+
+if [ -z "$GIT_COMMIT" ]; then
+ echo "GIT_COMMIT must be set"
+ exit 1
+fi
+
+if [ -z "$TEST_DIR" ]; then
+
+ echo "TEST_DIR must be set"
+ exit 1
+fi
+
+# TODO: never clear qcom_replay cache
+# clear scons cache dirs that haven't been written to in one day
+cd /tmp && find -name 'scons_cache_*' -type d -maxdepth 1 -mtime 1 -exec rm -rf '{}' \;
+
+# set up environment
+cd $SOURCE_DIR
+git reset --hard
+git fetch origin
+find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \;
+git reset --hard $GIT_COMMIT
+git checkout $GIT_COMMIT
+git clean -xdf
+git submodule update --init
+git submodule foreach --recursive git reset --hard
+git submodule foreach --recursive git clean -xdf
+echo "git checkout took $SECONDS seconds"
+
+rsync -a --delete $SOURCE_DIR $TEST_DIR
+
+echo "$TEST_DIR synced with $GIT_COMMIT, took $SECONDS seconds"
diff --git a/selfdrive/test/test_cpu_usage.py b/selfdrive/test/test_cpu_usage.py
index eba08fd8..2f260ec8 100755
--- a/selfdrive/test/test_cpu_usage.py
+++ b/selfdrive/test/test_cpu_usage.py
@@ -1,13 +1,13 @@
#!/usr/bin/env python3
+import os
import time
-import threading
-import _thread
-import signal
import sys
+import subprocess
import cereal.messaging as messaging
-import selfdrive.manager as manager
-
+from common.basedir import BASEDIR
+from common.params import Params
+from selfdrive.test.helpers import set_params_enabled
def cputime_total(ct):
return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem
@@ -15,7 +15,7 @@ def cputime_total(ct):
def print_cpu_usage(first_proc, last_proc):
procs = [
- ("selfdrive.controls.controlsd", 59.46),
+ ("selfdrive.controls.controlsd", 66.15),
("selfdrive.locationd.locationd", 34.38),
("./loggerd", 33.90),
("selfdrive.controls.plannerd", 19.77),
@@ -39,7 +39,7 @@ def print_cpu_usage(first_proc, last_proc):
("./logcatd", 0),
]
- r = 0
+ r = True
dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9
result = "------------------------------------------------\n"
for proc_name, normal_cpu_usage in procs:
@@ -50,47 +50,54 @@ def print_cpu_usage(first_proc, last_proc):
cpu_usage = cpu_time / dt * 100.
if cpu_usage > max(normal_cpu_usage * 1.1, normal_cpu_usage + 5.0):
result += f"Warning {proc_name} using more CPU than normal\n"
- r = 1
+ r = False
elif cpu_usage < min(normal_cpu_usage * 0.3, max(normal_cpu_usage - 1.0, 0.0)):
result += f"Warning {proc_name} using less CPU than normal\n"
- r = 1
+ r = False
result += f"{proc_name.ljust(35)} {cpu_usage:.2f}%\n"
except IndexError:
result += f"{proc_name.ljust(35)} NO METRICS FOUND\n"
- r = 1
+ r = False
result += "------------------------------------------------\n"
print(result)
return r
-return_code = 1
-def test_thread():
- global return_code
- proc_sock = messaging.sub_sock('procLog', conflate=True)
+def test_cpu_usage():
+ cpu_ok = False
- # wait until everything's started and get first sample
- time.sleep(30)
- first_proc = messaging.recv_sock(proc_sock, wait=True)
+ # start manager
+ manager_path = os.path.join(BASEDIR, "selfdrive/manager.py")
+ manager_proc = subprocess.Popen(["python", manager_path])
+ try:
+ proc_sock = messaging.sub_sock('procLog', conflate=True, timeout=2000)
- # run for a minute and get last sample
- time.sleep(60)
- last_proc = messaging.recv_sock(proc_sock, wait=True)
+ # wait until everything's started and get first sample
+ start_time = time.monotonic()
+ while time.monotonic() - start_time < 120:
+ if Params().get("CarParams") is not None:
+ break
+ time.sleep(2)
+ first_proc = messaging.recv_sock(proc_sock, wait=True)
+ if first_proc is None:
+ raise Exception("\n\nTEST FAILED: progLog recv timed out\n\n")
- running = manager.get_running()
- all_running = all(p in running and running[p].is_alive() for p in manager.car_started_processes)
- return_code = print_cpu_usage(first_proc, last_proc)
- if not all_running:
- return_code = 1
- _thread.interrupt_main()
+ # run for a minute and get last sample
+ time.sleep(60)
+ last_proc = messaging.recv_sock(proc_sock, wait=True)
+ cpu_ok = print_cpu_usage(first_proc, last_proc)
+ finally:
+ manager_proc.terminate()
+ ret = manager_proc.wait(20)
+ if ret is None:
+ manager_proc.kill()
+ return cpu_ok
if __name__ == "__main__":
+ set_params_enabled()
+ Params().delete("CarParams")
- # setup signal handler to exit with test status
- def handle_exit(sig, frame):
- sys.exit(return_code)
- signal.signal(signal.SIGINT, handle_exit)
-
- # start manager and test thread
- t = threading.Thread(target=test_thread)
- t.daemon = True
- t.start()
- manager.main()
+ passed = False
+ try:
+ passed = test_cpu_usage()
+ finally:
+ sys.exit(int(not passed))
diff --git a/selfdrive/test/test_openpilot.py b/selfdrive/test/test_openpilot.py
index fc3b17dd..75e8192f 100644
--- a/selfdrive/test/test_openpilot.py
+++ b/selfdrive/test/test_openpilot.py
@@ -5,7 +5,7 @@ os.environ['FAKEUPLOAD'] = "1"
from common.params import Params
from common.realtime import sec_since_boot
from selfdrive.manager import manager_init, manager_prepare, start_daemon_process
-from selfdrive.test.helpers import phone_only, with_processes
+from selfdrive.test.helpers import phone_only, with_processes, set_params_enabled
import json
import requests
import signal
@@ -16,6 +16,7 @@ import time
# must run first
@phone_only
def test_manager_prepare():
+ set_params_enabled()
manager_init()
manager_prepare()
diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py
index 65587ca9..093b832d 100755
--- a/selfdrive/thermald/thermald.py
+++ b/selfdrive/thermald/thermald.py
@@ -1,20 +1,18 @@
#!/usr/bin/env python3
import os
-import json
-import copy
import datetime
import psutil
from smbus2 import SMBus
from cereal import log
from common.android import ANDROID, get_network_type, get_network_strength
-from common.basedir import BASEDIR
from common.params import Params, put_nonblocking
from common.realtime import sec_since_boot, DT_TRML
from common.numpy_fast import clip, interp
from common.filter_simple import FirstOrderFilter
-from selfdrive.version import terms_version, training_version
+from selfdrive.version import terms_version, training_version, get_git_branch
from selfdrive.swaglog import cloudlog
import cereal.messaging as messaging
+from selfdrive.controls.lib.alertmanager import set_offroad_alert
from selfdrive.loggerd.config import get_available_percent
from selfdrive.pandad import get_expected_signature
from selfdrive.thermald.power_monitoring import PowerMonitoring, get_battery_capacity, get_battery_status, \
@@ -35,10 +33,6 @@ LEON = False
last_eon_fan_val = None
-with open(BASEDIR + "/selfdrive/controls/lib/alerts_offroad.json") as json_file:
- OFFROAD_ALERTS = json.load(json_file)
-
-
def read_tz(x, clip=True):
if not ANDROID:
# we don't monitor thermal on PC
@@ -171,6 +165,7 @@ def thermald_thread():
thermal_status_prev = ThermalStatus.green
usb_power = True
usb_power_prev = True
+ current_branch = get_git_branch()
network_type = NetworkType.none
network_strength = NetworkStrength.unknown
@@ -179,7 +174,7 @@ def thermald_thread():
cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
health_prev = None
fw_version_match_prev = True
- current_connectivity_alert = None
+ current_update_alert = None
time_valid_prev = True
should_start_prev = False
handle_fan = None
@@ -253,6 +248,7 @@ def thermald_thread():
if is_uno:
msg.thermal.batteryPercent = 100
msg.thermal.batteryStatus = "Charging"
+ msg.thermal.bat = 0
current_filter.update(msg.thermal.batteryCurrent / 1e6)
@@ -300,9 +296,9 @@ def thermald_thread():
# show invalid date/time alert
time_valid = now.year >= 2019
if time_valid and not time_valid_prev:
- params.delete("Offroad_InvalidTime")
+ set_offroad_alert("Offroad_InvalidTime", False)
if not time_valid and time_valid_prev:
- put_nonblocking("Offroad_InvalidTime", json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"]))
+ set_offroad_alert("Offroad_InvalidTime", True)
time_valid_prev = time_valid
# Show update prompt
@@ -314,24 +310,37 @@ def thermald_thread():
update_failed_count = params.get("UpdateFailedCount")
update_failed_count = 0 if update_failed_count is None else int(update_failed_count)
+ last_update_exception = params.get("LastUpdateException", encoding='utf8')
- if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
- if current_connectivity_alert != "expired":
- current_connectivity_alert = "expired"
- params.delete("Offroad_ConnectivityNeededPrompt")
- put_nonblocking("Offroad_ConnectivityNeeded", json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"]))
+ if update_failed_count > 15 and last_update_exception is not None:
+ if current_branch in ["release2", "dashcam"]:
+ extra_text = "Ensure the software is correctly installed"
+ else:
+ extra_text = last_update_exception
+
+ if current_update_alert != "update" + extra_text:
+ current_update_alert = "update" + extra_text
+ set_offroad_alert("Offroad_ConnectivityNeeded", False)
+ set_offroad_alert("Offroad_ConnectivityNeededPrompt", False)
+ set_offroad_alert("Offroad_UpdateFailed", True, extra_text=extra_text)
+ elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
+ if current_update_alert != "expired":
+ current_update_alert = "expired"
+ set_offroad_alert("Offroad_UpdateFailed", False)
+ set_offroad_alert("Offroad_ConnectivityNeededPrompt", False)
+ set_offroad_alert("Offroad_ConnectivityNeeded", True)
elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
- if current_connectivity_alert != "prompt" + remaining_time:
- current_connectivity_alert = "prompt" + remaining_time
- alert_connectivity_prompt = copy.copy(OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"])
- alert_connectivity_prompt["text"] += remaining_time + " days."
- params.delete("Offroad_ConnectivityNeeded")
- put_nonblocking("Offroad_ConnectivityNeededPrompt", json.dumps(alert_connectivity_prompt))
- elif current_connectivity_alert is not None:
- current_connectivity_alert = None
- params.delete("Offroad_ConnectivityNeeded")
- params.delete("Offroad_ConnectivityNeededPrompt")
+ if current_update_alert != "prompt" + remaining_time:
+ current_update_alert = "prompt" + remaining_time
+ set_offroad_alert("Offroad_UpdateFailed", False)
+ set_offroad_alert("Offroad_ConnectivityNeeded", False)
+ set_offroad_alert("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining_time} days.")
+ elif current_update_alert is not None:
+ current_update_alert = None
+ set_offroad_alert("Offroad_UpdateFailed", False)
+ set_offroad_alert("Offroad_ConnectivityNeeded", False)
+ set_offroad_alert("Offroad_ConnectivityNeededPrompt", False)
do_uninstall = params.get("DoUninstall") == b"1"
accepted_terms = params.get("HasAcceptedTerms") == terms_version
@@ -361,19 +370,19 @@ def thermald_thread():
should_start = should_start and (not is_taking_snapshot) and (not is_viewing_driver)
if fw_version_match and not fw_version_match_prev:
- params.delete("Offroad_PandaFirmwareMismatch")
+ set_offroad_alert("Offroad_PandaFirmwareMismatch", False)
if not fw_version_match and fw_version_match_prev:
- put_nonblocking("Offroad_PandaFirmwareMismatch", json.dumps(OFFROAD_ALERTS["Offroad_PandaFirmwareMismatch"]))
+ set_offroad_alert("Offroad_PandaFirmwareMismatch", True)
# if any CPU gets above 107 or the battery gets above 63, kill all processes
# controls will warn with CPU above 95 or battery above 60
if thermal_status >= ThermalStatus.danger:
should_start = False
if thermal_status_prev < ThermalStatus.danger:
- put_nonblocking("Offroad_TemperatureTooHigh", json.dumps(OFFROAD_ALERTS["Offroad_TemperatureTooHigh"]))
+ set_offroad_alert("Offroad_TemperatureTooHigh", True)
else:
if thermal_status_prev >= ThermalStatus.danger:
- params.delete("Offroad_TemperatureTooHigh")
+ set_offroad_alert("Offroad_TemperatureTooHigh", False)
if should_start:
if not should_start_prev:
@@ -411,9 +420,9 @@ def thermald_thread():
thermal_sock.send(msg.to_bytes())
if usb_power_prev and not usb_power:
- put_nonblocking("Offroad_ChargeDisabled", json.dumps(OFFROAD_ALERTS["Offroad_ChargeDisabled"]))
+ set_offroad_alert("Offroad_ChargeDisabled", True)
elif usb_power and not usb_power_prev:
- params.delete("Offroad_ChargeDisabled")
+ set_offroad_alert("Offroad_ChargeDisabled", False)
thermal_status_prev = thermal_status
usb_power_prev = usb_power
diff --git a/selfdrive/ui/linux.cc b/selfdrive/ui/linux.cc
index 590a6de2..5b370cc2 100644
--- a/selfdrive/ui/linux.cc
+++ b/selfdrive/ui/linux.cc
@@ -83,7 +83,7 @@ int touch_read(TouchState *s, int* out_x, int* out_y) {
#include "sound.hpp"
bool Sound::init(int volume) { return true; }
-bool Sound::play(AudibleAlert alert) { return true; }
+bool Sound::play(AudibleAlert alert) { printf("play sound: %d\n", (int)alert); return true; }
void Sound::stop() {}
void Sound::setVolume(int volume) {}
Sound::~Sound() {}
diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc
index 8c17b4cf..8802526c 100644
--- a/selfdrive/ui/paint.cc
+++ b/selfdrive/ui/paint.cc
@@ -368,11 +368,14 @@ static void ui_draw_world(UIState *s) {
// Draw lane edges and vision/mpc tracks
ui_draw_vision_lanes(s);
- if (scene->lead_data[0].getStatus()) {
- draw_lead(s, scene->lead_data[0]);
- }
- if (scene->lead_data[1].getStatus() && (std::abs(scene->lead_data[0].getDRel() - scene->lead_data[1].getDRel()) > 3.0)) {
- draw_lead(s, scene->lead_data[1]);
+ // Draw lead indicators if openpilot is handling longitudinal
+ if (s->longitudinal_control) {
+ if (scene->lead_data[0].getStatus()) {
+ draw_lead(s, scene->lead_data[0]);
+ }
+ if (scene->lead_data[1].getStatus() && (std::abs(scene->lead_data[0].getDRel() - scene->lead_data[1].getDRel()) > 3.0)) {
+ draw_lead(s, scene->lead_data[1]);
+ }
}
nvgRestore(s->vg);
}
@@ -557,7 +560,7 @@ static void ui_draw_vision_face(UIState *s) {
const int face_size = 96;
const int face_x = (s->scene.ui_viz_rx + face_size + (bdr_s * 2));
const int face_y = (footer_y + ((footer_h - face_size) / 2));
- ui_draw_circle_image(s->vg, face_x, face_y, face_size, s->img_face, s->scene.controls_state.getDriverMonitoringOn());
+ ui_draw_circle_image(s->vg, face_x, face_y, face_size, s->img_face, s->scene.dmonitoring_state.getFaceDetected());
}
static void ui_draw_driver_view(UIState *s) {
@@ -569,19 +572,11 @@ static void ui_draw_driver_view(UIState *s) {
const int valid_frame_x = frame_x + (frame_w - valid_frame_w) / 2 + ff_xoffset;
// blackout
- if (!scene->is_rhd) {
- NVGpaint gradient = nvgLinearGradient(s->vg, valid_frame_x + valid_frame_w,
- box_y,
- valid_frame_x + box_h / 2, box_y,
- nvgRGBAf(0,0,0,1), nvgRGBAf(0,0,0,0));
- ui_draw_rect(s->vg, valid_frame_x + box_h / 2, box_y, valid_frame_w - box_h / 2, box_h, gradient);
- } else {
- NVGpaint gradient = nvgLinearGradient(s->vg, valid_frame_x,
- box_y,
- valid_frame_w - box_h / 2, box_y,
- nvgRGBAf(0,0,0,1), nvgRGBAf(0,0,0,0));
- ui_draw_rect(s->vg, valid_frame_x, box_y, valid_frame_w - box_h / 2, box_h, gradient);
- }
+ NVGpaint gradient = nvgLinearGradient(s->vg, scene->is_rhd ? valid_frame_x : (valid_frame_x + valid_frame_w),
+ box_y,
+ scene->is_rhd ? (valid_frame_w - box_h / 2) : (valid_frame_x + box_h / 2), box_y,
+ COLOR_BLACK, COLOR_BLACK_ALPHA(0));
+ ui_draw_rect(s->vg, scene->is_rhd ? valid_frame_x : (valid_frame_x + box_h / 2), box_y, valid_frame_w - box_h / 2, box_h, gradient);
ui_draw_rect(s->vg, scene->is_rhd ? valid_frame_x : valid_frame_x + box_h / 2, box_y, valid_frame_w - box_h / 2, box_h, COLOR_BLACK_ALPHA(144));
// borders
@@ -589,7 +584,7 @@ static void ui_draw_driver_view(UIState *s) {
ui_draw_rect(s->vg, valid_frame_x + valid_frame_w, box_y, frame_w - valid_frame_w - (valid_frame_x - frame_x), box_h, nvgRGBA(23, 51, 73, 255));
// draw face box
- if (scene->driver_state.getFaceProb() > 0.4) {
+ if (scene->dmonitoring_state.getFaceDetected()) {
auto fxy_list = scene->driver_state.getFacePosition();
const float face_x = fxy_list[0];
const float face_y = fxy_list[1];
@@ -600,6 +595,7 @@ static void ui_draw_driver_view(UIState *s) {
} else {
fbox_x = valid_frame_x + valid_frame_w - box_h / 2 + (face_x + 0.5) * (box_h / 2) - 0.5 * 0.6 * box_h / 2;
}
+
if (std::abs(face_x) <= 0.35 && std::abs(face_y) <= 0.4) {
ui_draw_rect(s->vg, fbox_x, fbox_y, 0.6 * box_h / 2, 0.6 * box_h / 2,
nvgRGBAf(1.0, 1.0, 1.0, 0.8 - ((std::abs(face_x) > std::abs(face_y) ? std::abs(face_x) : std::abs(face_y))) * 0.6 / 0.375),
@@ -613,7 +609,7 @@ static void ui_draw_driver_view(UIState *s) {
const int face_size = 85;
const int x = (valid_frame_x + face_size + (bdr_s * 2)) + (scene->is_rhd ? valid_frame_w - box_h / 2:0);
const int y = (box_y + box_h - face_size - bdr_s - (bdr_s * 1.5));
- ui_draw_circle_image(s->vg, x, y, face_size, s->img_face, scene->driver_state.getFaceProb() > 0.4);
+ ui_draw_circle_image(s->vg, x, y, face_size, s->img_face, scene->dmonitoring_state.getFaceDetected());
}
static void ui_draw_vision_header(UIState *s) {
@@ -853,8 +849,6 @@ void ui_nvg_init(UIState *s) {
assert(s->vg);
- s->font_courbd = nvgCreateFont(s->vg, "courbd", "../assets/fonts/courbd.ttf");
- assert(s->font_courbd >= 0);
s->font_sans_regular = nvgCreateFont(s->vg, "sans-regular", "../assets/fonts/opensans_regular.ttf");
assert(s->font_sans_regular >= 0);
s->font_sans_semibold = nvgCreateFont(s->vg, "sans-semibold", "../assets/fonts/opensans_semibold.ttf");
diff --git a/selfdrive/ui/sidebar.cc b/selfdrive/ui/sidebar.cc
index f4cb4f51..e8eb894c 100644
--- a/selfdrive/ui/sidebar.cc
+++ b/selfdrive/ui/sidebar.cc
@@ -10,17 +10,13 @@ static void ui_draw_sidebar_background(UIState *s) {
}
static void ui_draw_sidebar_settings_button(UIState *s) {
- bool settingsActive = s->active_app == cereal::UiLayoutState::App::SETTINGS;
- const int settings_btn_xr = !s->scene.uilayout_sidebarcollapsed ? settings_btn_x : -(sbr_w);
-
- ui_draw_image(s->vg, settings_btn_xr, settings_btn_y, settings_btn_w, settings_btn_h, s->img_button_settings, settingsActive ? 1.0f : 0.65f);
+ const float alpha = s->active_app == cereal::UiLayoutState::App::SETTINGS ? 1.0f : 0.65f;
+ ui_draw_image(s->vg, settings_btn_x, settings_btn_y, settings_btn_w, settings_btn_h, s->img_button_settings, alpha);
}
static void ui_draw_sidebar_home_button(UIState *s) {
- bool homeActive = s->active_app == cereal::UiLayoutState::App::HOME;
- const int home_btn_xr = !s->scene.uilayout_sidebarcollapsed ? home_btn_x : -(sbr_w);
-
- ui_draw_image(s->vg, home_btn_xr, home_btn_y, home_btn_w, home_btn_h, s->img_button_home, homeActive ? 1.0f : 0.65f);
+ const float alpha = s->active_app == cereal::UiLayoutState::App::HOME ? 1.0f : 0.65f;;
+ ui_draw_image(s->vg, home_btn_x, home_btn_y, home_btn_w, home_btn_h, s->img_button_home, alpha);
}
static void ui_draw_sidebar_network_strength(UIState *s) {
@@ -32,7 +28,7 @@ static void ui_draw_sidebar_network_strength(UIState *s) {
{cereal::ThermalData::NetworkStrength::GREAT, 5}};
const int network_img_h = 27;
const int network_img_w = 176;
- const int network_img_x = !s->scene.uilayout_sidebarcollapsed ? 58 : -(sbr_w);
+ const int network_img_x = 58;
const int network_img_y = 196;
const int img_idx = s->scene.thermal.getNetworkType() == cereal::ThermalData::NetworkType::NONE ? 0 : network_strength_map[s->scene.thermal.getNetworkStrength()];
ui_draw_image(s->vg, network_img_x, network_img_y, network_img_w, network_img_h, s->img_network[img_idx], 1.0f);
@@ -41,7 +37,7 @@ static void ui_draw_sidebar_network_strength(UIState *s) {
static void ui_draw_sidebar_battery_icon(UIState *s) {
const int battery_img_h = 36;
const int battery_img_w = 76;
- const int battery_img_x = !s->scene.uilayout_sidebarcollapsed ? 160 : -(sbr_w);
+ const int battery_img_x = 160;
const int battery_img_y = 255;
int battery_img = s->scene.thermal.getBatteryStatus() == "Charging" ? s->img_battery_charging : s->img_battery;
@@ -60,7 +56,7 @@ static void ui_draw_sidebar_network_type(UIState *s) {
{cereal::ThermalData::NetworkType::CELL3_G, "3G"},
{cereal::ThermalData::NetworkType::CELL4_G, "4G"},
{cereal::ThermalData::NetworkType::CELL5_G, "5G"}};
- const int network_x = !s->scene.uilayout_sidebarcollapsed ? 50 : -(sbr_w);
+ const int network_x = 50;
const int network_y = 273;
const int network_w = 100;
const char *network_type = network_type_map[s->scene.thermal.getNetworkType()];
@@ -72,7 +68,7 @@ static void ui_draw_sidebar_network_type(UIState *s) {
}
static void ui_draw_sidebar_metric(UIState *s, const char* label_str, const char* value_str, const int severity, const int y_offset, const char* message_str) {
- const int metric_x = !s->scene.uilayout_sidebarcollapsed ? 30 : -(sbr_w);
+ const int metric_x = 30;
const int metric_y = 338 + y_offset;
const int metric_w = 240;
const int metric_h = message_str ? strchr(message_str, '\n') ? 124 : 100 : 148;
diff --git a/selfdrive/ui/sound.hpp b/selfdrive/ui/sound.hpp
index c147f87b..d565f846 100644
--- a/selfdrive/ui/sound.hpp
+++ b/selfdrive/ui/sound.hpp
@@ -2,7 +2,7 @@
#include