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 #include "cereal/gen/cpp/log.capnp.h" -#if defined(QCOM) || defined(QCOM2) +#if defined(QCOM) #include #include #endif @@ -18,7 +18,7 @@ class Sound { void setVolume(int volume); ~Sound(); -#if defined(QCOM) || defined(QCOM2) +#if defined(QCOM) private: SLObjectItf engine_ = nullptr; SLObjectItf outputMix_ = nullptr; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 4bd1fa20..b8edfc4e 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -193,8 +193,6 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, int num_back_fds, const int *back_fds, const VisionStreamBufs front_bufs, int num_front_fds, const int *front_fds) { - const VisionUIInfo ui_info = back_bufs.buf_info.ui_info; - assert(num_back_fds == UI_BUF_COUNT); assert(num_front_fds == UI_BUF_COUNT); @@ -206,14 +204,7 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, s->scene.frontview = getenv("FRONTVIEW") != NULL; s->scene.fullview = getenv("FULLVIEW") != NULL; - s->scene.transformed_width = ui_info.transformed_width; - s->scene.transformed_height = ui_info.transformed_height; - s->scene.front_box_x = ui_info.front_box_x; - s->scene.front_box_y = ui_info.front_box_y; - s->scene.front_box_width = ui_info.front_box_width; - s->scene.front_box_height = ui_info.front_box_height; s->scene.world_objects_visible = false; // Invisible until we receive a calibration message. - s->scene.gps_planner_active = false; s->rgb_width = back_bufs.width; s->rgb_height = back_bufs.height; @@ -225,13 +216,6 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, s->rgb_front_stride = front_bufs.stride; s->rgb_front_buf_len = front_bufs.buf_len; - s->rgb_transform = (mat4){{ - 2.0f/s->rgb_width, 0.0f, 0.0f, -1.0f, - 0.0f, 2.0f/s->rgb_height, 0.0f, -1.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }}; - read_param(&s->speed_lim_off, "SpeedLimitOffset"); read_param(&s->is_metric, "IsMetric"); read_param(&s->longitudinal_control, "LongitudinalControl"); @@ -285,8 +269,7 @@ void handle_message(UIState *s, SubMaster &sm) { auto event = sm["controlsState"]; scene.controls_state = event.getControlsState(); s->controls_timeout = 1 * UI_FREQ; - scene.frontview = scene.controls_state.getRearViewCam(); - if (!scene.frontview){ s->controls_seen = true; } + s->controls_seen = true; auto alert_sound = scene.controls_state.getAlertSound(); if (scene.alert_type.compare(scene.controls_state.getAlertType()) != 0) { @@ -379,12 +362,17 @@ void handle_message(UIState *s, SubMaster &sm) { scene.driver_state = sm["driverState"].getDriverState(); } if (sm.updated("dMonitoringState")) { - auto data = sm["dMonitoringState"].getDMonitoringState(); - scene.is_rhd = data.getIsRHD(); - s->preview_started = data.getIsPreview(); + scene.dmonitoring_state = sm["dMonitoringState"].getDMonitoringState(); + scene.is_rhd = scene.dmonitoring_state.getIsRHD(); + scene.frontview = scene.dmonitoring_state.getIsPreview(); } - s->started = scene.thermal.getStarted() || s->preview_started; + // timeout on frontview + if ((sm.frame - sm.rcv_frame("dMonitoringState")) > 1*UI_FREQ) { + scene.frontview = false; + } + + s->started = scene.thermal.getStarted() || scene.frontview; // Handle onroad/offroad transition if (!s->started) { if (s->status != STATUS_STOPPED) { @@ -831,7 +819,7 @@ int main(int argc, char* argv[]) { if (s->controls_timeout > 0) { s->controls_timeout--; - } else if (s->started) { + } else if (s->started && !s->scene.frontview) { if (!s->controls_seen) { // car is started, but controlsState hasn't been seen at all s->scene.alert_text1 = "openpilot Unavailable"; diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp index 830d227e..bf64ef27 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.hpp @@ -92,8 +92,6 @@ typedef struct UIScene { int frontview; int fullview; - int transformed_width, transformed_height; - ModelData model; float mpc_x[50]; @@ -114,16 +112,11 @@ typedef struct UIScene { int ui_viz_rw; int ui_viz_ro; - int front_box_x, front_box_y, front_box_width, front_box_height; - std::string alert_text1; std::string alert_text2; std::string alert_type; cereal::ControlsState::AlertSize alert_size; - // Used to show gps planner status - bool gps_planner_active; - cereal::HealthData::HwType hwType; int satelliteCount; uint8_t athenaStatus; @@ -132,6 +125,7 @@ typedef struct UIScene { cereal::RadarState::LeadData::Reader lead_data[2]; cereal::ControlsState::Reader controls_state; cereal::DriverState::Reader driver_state; + cereal::DMonitoringState::Reader dmonitoring_state; } UIScene; typedef struct { @@ -160,7 +154,6 @@ typedef struct UIState { NVGcontext *vg; // fonts and images - int font_courbd; int font_sans_regular; int font_sans_semibold; int font_sans_bold; @@ -203,7 +196,6 @@ typedef struct UIState { int rgb_width, rgb_height, rgb_stride; size_t rgb_buf_len; - mat4 rgb_transform; int rgb_front_width, rgb_front_height, rgb_front_stride; size_t rgb_front_buf_len; @@ -233,7 +225,6 @@ typedef struct UIState { float alert_blinking_alpha; bool alert_blinked; bool started; - bool preview_started; bool vision_seen; std::atomic light_sensor; diff --git a/selfdrive/updated.py b/selfdrive/updated.py index bb665180..20590680 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -26,48 +26,59 @@ import os import datetime import subprocess import psutil -from stat import S_ISREG, S_ISDIR, S_ISLNK, S_IMODE, ST_MODE, ST_INO, ST_UID, ST_GID, ST_ATIME, ST_MTIME import shutil import signal -from pathlib import Path import fcntl -import threading import time +import threading from cffi import FFI +from pathlib import Path from common.basedir import BASEDIR from common.params import Params from selfdrive.swaglog import cloudlog +from selfdrive.controls.lib.alertmanager import set_offroad_alert -STAGING_ROOT = "/data/safe_staging" +TEST_IP = os.getenv("UPDATER_TEST_IP", "8.8.8.8") +LOCK_FILE = os.getenv("UPDATER_LOCK_FILE", "/tmp/safe_staging_overlay.lock") +STAGING_ROOT = os.getenv("UPDATER_STAGING_ROOT", "/data/safe_staging") + +NEOS_VERSION = os.getenv("UPDATER_NEOS_VERSION", "/VERSION") +NEOSUPDATE_DIR = os.getenv("UPDATER_NEOSUPDATE_DIR", "/data/neoupdate") OVERLAY_UPPER = os.path.join(STAGING_ROOT, "upper") OVERLAY_METADATA = os.path.join(STAGING_ROOT, "metadata") OVERLAY_MERGED = os.path.join(STAGING_ROOT, "merged") FINALIZED = os.path.join(STAGING_ROOT, "finalized") -NICE_LOW_PRIORITY = ["nice", "-n", "19"] -SHORT = os.getenv("SHORT") is not None -# Workaround for the EON/termux build of Python having os.link removed. +# Workaround for lack of os.link in the NEOS/termux python ffi = FFI() ffi.cdef("int link(const char *oldpath, const char *newpath);") libc = ffi.dlopen(None) +def link(src, dest): + return libc.link(src.encode(), dest.encode()) class WaitTimeHelper: - ready_event = threading.Event() - shutdown = False - - def __init__(self): + def __init__(self, proc): + self.proc = proc + self.ready_event = threading.Event() + self.shutdown = False signal.signal(signal.SIGTERM, self.graceful_shutdown) signal.signal(signal.SIGINT, self.graceful_shutdown) signal.signal(signal.SIGHUP, self.update_now) def graceful_shutdown(self, signum, frame): - # umount -f doesn't appear effective in avoiding "device busy" on EON, + # umount -f doesn't appear effective in avoiding "device busy" on NEOS, # so don't actually die until the next convenient opportunity in main(). cloudlog.info("caught SIGINT/SIGTERM, dismounting overlay at next opportunity") + + # forward the signal to all our child processes + child_procs = self.proc.children(recursive=True) + for p in child_procs: + p.send_signal(signum) + self.shutdown = True self.ready_event.set() @@ -75,42 +86,27 @@ class WaitTimeHelper: cloudlog.info("caught SIGHUP, running update check immediately") self.ready_event.set() - -def wait_between_updates(ready_event): - ready_event.clear() - if SHORT: - ready_event.wait(timeout=10) - else: - ready_event.wait(timeout=60 * 10) + def sleep(self, t): + self.ready_event.wait(timeout=t) -def link(src, dest): - # Workaround for the EON/termux build of Python having os.link removed. - return libc.link(src.encode(), dest.encode()) - - -def run(cmd, cwd=None): +def run(cmd, cwd=None, low_priority=False): + if low_priority: + cmd = ["nice", "-n", "19"] + cmd return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8') -def remove_consistent_flag(): +def set_consistent_flag(consistent): os.system("sync") consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent")) - try: + if consistent: + consistent_file.touch() + elif not consistent and consistent_file.exists(): consistent_file.unlink() - except FileNotFoundError: - pass os.system("sync") -def set_consistent_flag(): - consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent")) - os.system("sync") - consistent_file.touch() - os.system("sync") - - -def set_update_available_params(new_version=False): +def set_update_available_params(new_version): params = Params() t = datetime.datetime.utcnow().isoformat() @@ -134,39 +130,35 @@ def dismount_ovfs(): def setup_git_options(cwd): - # We sync FS object atimes (which EON doesn't use) and mtimes, but ctimes + # We sync FS object atimes (which NEOS doesn't use) and mtimes, but ctimes # are outside user control. Make sure Git is set up to ignore system ctimes, # because they change when we make hard links during finalize. Otherwise, # there is a lot of unnecessary churn. This appears to be a common need on # OSX as well: https://www.git-tower.com/blog/make-git-rebase-safe-on-osx/ - try: - trustctime = run(["git", "config", "--get", "core.trustctime"], cwd) - trustctime_set = (trustctime.strip() == "false") - except subprocess.CalledProcessError: - trustctime_set = False - if not trustctime_set: - cloudlog.info("Setting core.trustctime false") - run(["git", "config", "core.trustctime", "false"], cwd) - - # We are temporarily using copytree to copy the directory, which also changes + # We are using copytree to copy the directory, which also changes # inode numbers. Ignore those changes too. - try: - checkstat = run(["git", "config", "--get", "core.checkStat"], cwd) - checkstat_set = (checkstat.strip() == "minimal") - except subprocess.CalledProcessError: - checkstat_set = False + git_cfg = [ + ("core.trustctime", "false"), + ("core.checkStat", "minimal"), + ] + for option, value in git_cfg: + try: + ret = run(["git", "config", "--get", option], cwd) + config_ok = ret.strip() == value + except subprocess.CalledProcessError: + config_ok = False - if not checkstat_set: - cloudlog.info("Setting core.checkState minimal") - run(["git", "config", "core.checkStat", "minimal"], cwd) + if not config_ok: + cloudlog.info(f"Setting git '{option}' to '{value}'") + run(["git", "config", option, value], cwd) def init_ovfs(): cloudlog.info("preparing new safe staging area") Params().put("UpdateAvailable", "0") - remove_consistent_flag() + set_consistent_flag(False) dismount_ovfs() if os.path.isdir(STAGING_ROOT): @@ -174,6 +166,7 @@ def init_ovfs(): for dirname in [STAGING_ROOT, OVERLAY_UPPER, OVERLAY_METADATA, OVERLAY_MERGED, FINALIZED]: os.mkdir(dirname, 0o755) + if not os.lstat(BASEDIR).st_dev == os.lstat(OVERLAY_MERGED).st_dev: raise RuntimeError("base and overlay merge directories are on different filesystems; not valid for overlay FS!") @@ -181,100 +174,39 @@ def init_ovfs(): if os.path.isfile(os.path.join(BASEDIR, ".overlay_consistent")): os.remove(os.path.join(BASEDIR, ".overlay_consistent")) - # Leave a timestamped canary in BASEDIR to check at startup. The EON clock + # Leave a timestamped canary in BASEDIR to check at startup. The device clock # should be correct by the time we get here. If the init file disappears, or # critical mtimes in BASEDIR are newer than .overlay_init, continue.sh can # assume that BASEDIR has used for local development or otherwise modified, # and skips the update activation attempt. Path(os.path.join(BASEDIR, ".overlay_init")).touch() + os.system("sync") overlay_opts = f"lowerdir={BASEDIR},upperdir={OVERLAY_UPPER},workdir={OVERLAY_METADATA}" run(["mount", "-t", "overlay", "-o", overlay_opts, "none", OVERLAY_MERGED]) -def inodes_in_tree(search_dir): - """Given a search root, produce a dictionary mapping of inodes to relative - pathnames of regular files (no directories, symlinks, or special files).""" - inode_map = {} - for root, _, files in os.walk(search_dir, topdown=True): - for file_name in files: - full_path_name = os.path.join(root, file_name) - st = os.lstat(full_path_name) - if S_ISREG(st[ST_MODE]): - inode_map[st[ST_INO]] = full_path_name - return inode_map - - -def dup_ovfs_object(inode_map, source_obj, target_dir): - """Given a relative pathname to copy, and a new target root, duplicate the - source object in the target root, using hardlinks for regular files.""" - - source_full_path = os.path.join(OVERLAY_MERGED, source_obj) - st = os.lstat(source_full_path) - target_full_path = os.path.join(target_dir, source_obj) - - if S_ISREG(st[ST_MODE]): - # Hardlink all regular files; ownership and permissions are shared. - link(inode_map[st[ST_INO]], target_full_path) - else: - # Recreate all directories and symlinks; copy ownership and permissions. - if S_ISDIR(st[ST_MODE]): - os.mkdir(os.path.join(FINALIZED, source_obj), S_IMODE(st[ST_MODE])) - elif S_ISLNK(st[ST_MODE]): - os.symlink(os.readlink(source_full_path), target_full_path) - os.chmod(target_full_path, S_IMODE(st[ST_MODE]), follow_symlinks=False) - else: - # Ran into a FIFO, socket, etc. Should not happen in OP install dir. - # Ignore without copying for the time being; revisit later if needed. - cloudlog.error("can't copy this file type: %s" % source_full_path) - os.chown(target_full_path, st[ST_UID], st[ST_GID], follow_symlinks=False) - - # Sync target mtimes to the cached lstat() value from each source object. - # Restores shared inode mtimes after linking, fixes symlinks and dirs. - os.utime(target_full_path, (st[ST_ATIME], st[ST_MTIME]), follow_symlinks=False) - - -def finalize_from_ovfs_hardlink(): - """Take the current OverlayFS merged view and finalize a copy outside of - OverlayFS, ready to be swapped-in at BASEDIR. Copy using hardlinks""" - - cloudlog.info("creating finalized version of the overlay") - - # The "copy" is done with hardlinks, but since the OverlayFS merge looks - # like a different filesystem, and hardlinks can't cross filesystems, we - # have to borrow a source pathname from the upper or lower layer. - inode_map = inodes_in_tree(BASEDIR) - inode_map.update(inodes_in_tree(OVERLAY_UPPER)) - - shutil.rmtree(FINALIZED) - os.umask(0o077) - os.mkdir(FINALIZED) - for root, dirs, files in os.walk(OVERLAY_MERGED, topdown=True): - for obj_name in dirs: - relative_path_name = os.path.relpath(os.path.join(root, obj_name), OVERLAY_MERGED) - dup_ovfs_object(inode_map, relative_path_name, FINALIZED) - for obj_name in files: - relative_path_name = os.path.relpath(os.path.join(root, obj_name), OVERLAY_MERGED) - dup_ovfs_object(inode_map, relative_path_name, FINALIZED) - cloudlog.info("done finalizing overlay") - - -def finalize_from_ovfs_copy(): +def finalize_from_ovfs(): """Take the current OverlayFS merged view and finalize a copy outside of OverlayFS, ready to be swapped-in at BASEDIR. Copy using shutil.copytree""" + # Remove the update ready flag and any old updates cloudlog.info("creating finalized version of the overlay") + set_consistent_flag(False) shutil.rmtree(FINALIZED) + + # Copy the merged overlay view and set the update ready flag shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True) + set_consistent_flag(True) cloudlog.info("done finalizing overlay") -def attempt_update(): +def attempt_update(wait_helper): cloudlog.info("attempting git update inside staging overlay") setup_git_options(OVERLAY_MERGED) - git_fetch_output = run(NICE_LOW_PRIORITY + ["git", "fetch"], OVERLAY_MERGED) + git_fetch_output = run(["git", "fetch"], OVERLAY_MERGED, low_priority=True) cloudlog.info("git fetch success: %s", git_fetch_output) cur_hash = run(["git", "rev-parse", "HEAD"], OVERLAY_MERGED).rstrip() @@ -287,106 +219,146 @@ def attempt_update(): cloudlog.info("comparing %s to %s" % (cur_hash, upstream_hash)) if new_version or git_fetch_result: cloudlog.info("Running update") + if new_version: cloudlog.info("git reset in progress") r = [ - run(NICE_LOW_PRIORITY + ["git", "reset", "--hard", "@{u}"], OVERLAY_MERGED), - run(NICE_LOW_PRIORITY + ["git", "clean", "-xdf"], OVERLAY_MERGED), - run(NICE_LOW_PRIORITY + ["git", "submodule", "init"], OVERLAY_MERGED), - run(NICE_LOW_PRIORITY + ["git", "submodule", "update"], OVERLAY_MERGED), + run(["git", "reset", "--hard", "@{u}"], OVERLAY_MERGED, low_priority=True), + run(["git", "clean", "-xdf"], OVERLAY_MERGED, low_priority=True ), + run(["git", "submodule", "init"], OVERLAY_MERGED, low_priority=True), + run(["git", "submodule", "update"], OVERLAY_MERGED, low_priority=True), ] cloudlog.info("git reset success: %s", '\n'.join(r)) - # Un-set the validity flag to prevent the finalized tree from being - # activated later if the finalize step is interrupted - remove_consistent_flag() + # Download the accompanying NEOS version if it doesn't match the current version + with open(NEOS_VERSION, "r") as f: + cur_neos = f.read().strip() - finalize_from_ovfs_copy() + updated_neos = run(["bash", "-c", r"unset REQUIRED_NEOS_VERSION && source launch_env.sh && \ + echo -n $REQUIRED_NEOS_VERSION"], OVERLAY_MERGED).strip() - # Make sure the validity flag lands on disk LAST, only when the local git - # repo and OP install are in a consistent state. - set_consistent_flag() + cloudlog.info(f"NEOS version check: {cur_neos} vs {updated_neos}") + if cur_neos != updated_neos: + cloudlog.info(f"Beginning background download for NEOS {updated_neos}") - cloudlog.info("update successful!") + set_offroad_alert("Offroad_NeosUpdate", True) + updater_path = os.path.join(OVERLAY_MERGED, "installer/updater/updater") + update_manifest = f"file://{OVERLAY_MERGED}/installer/updater/update.json" + + neos_downloaded = False + start_time = time.monotonic() + # Try to download for one day + while (time.monotonic() - start_time < 60*60*24) and not wait_helper.shutdown: + wait_helper.ready_event.clear() + try: + run([updater_path, "bgcache", update_manifest], OVERLAY_MERGED, low_priority=True) + neos_downloaded = True + break + except subprocess.CalledProcessError: + cloudlog.info("NEOS background download failed, retrying") + wait_helper.sleep(120) + + # If the download failed, we'll show the alert again when we retry + set_offroad_alert("Offroad_NeosUpdate", False) + if not neos_downloaded: + raise Exception("Failed to download NEOS update") + + cloudlog.info(f"NEOS background download successful, took {time.monotonic() - start_time} seconds") + + # Create the finalized, ready-to-swap update + finalize_from_ovfs() + cloudlog.info("openpilot update successful!") else: cloudlog.info("nothing new from git at this time") - set_update_available_params(new_version=new_version) + set_update_available_params(new_version) + return new_version def main(): - update_failed_count = 0 - overlay_init_done = False params = Params() if params.get("DisableUpdates") == b"1": - raise RuntimeError("updates are disabled by param") + raise RuntimeError("updates are disabled by the DisableUpdates param") - if not os.geteuid() == 0: + if os.geteuid() != 0: raise RuntimeError("updated must be launched as root!") # Set low io priority - p = psutil.Process() + proc = psutil.Process() if psutil.LINUX: - p.ionice(psutil.IOPRIO_CLASS_BE, value=7) + proc.ionice(psutil.IOPRIO_CLASS_BE, value=7) - ov_lock_fd = open('/tmp/safe_staging_overlay.lock', 'w') + ov_lock_fd = open(LOCK_FILE, 'w') try: fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: raise RuntimeError("couldn't get overlay lock; is another updated running?") - # Wait a short time before our first update attempt - # Avoids race with IsOffroad not being set, reduces manager startup load - time.sleep(30) - wait_helper = WaitTimeHelper() + # Wait for IsOffroad to be set before our first update attempt + wait_helper = WaitTimeHelper(proc) + wait_helper.sleep(30) - while True: - update_failed_count += 1 + update_failed_count = 0 + update_available = False + overlay_initialized = False + while not wait_helper.shutdown: + wait_helper.ready_event.clear() + + # Check for internet every 30s time_wrong = datetime.datetime.utcnow().year < 2019 - ping_failed = subprocess.call(["ping", "-W", "4", "-c", "1", "8.8.8.8"]) + ping_failed = os.system(f"ping -W 4 -c 1 {TEST_IP}") != 0 + if ping_failed or time_wrong: + wait_helper.sleep(30) + continue - # Wait until we have a valid datetime to initialize the overlay - if not (ping_failed or time_wrong): - try: - # If the git directory has modifcations after we created the overlay - # we need to recreate the overlay - if overlay_init_done: - overlay_init_fn = os.path.join(BASEDIR, ".overlay_init") - git_dir_path = os.path.join(BASEDIR, ".git") - new_files = run(["find", git_dir_path, "-newer", overlay_init_fn]) + # Attempt an update + exception = None + update_failed_count += 1 + try: + # Re-create the overlay if BASEDIR/.git has changed since we created the overlay + if overlay_initialized: + overlay_init_fn = os.path.join(BASEDIR, ".overlay_init") + git_dir_path = os.path.join(BASEDIR, ".git") + new_files = run(["find", git_dir_path, "-newer", overlay_init_fn]) - if len(new_files.splitlines()): - cloudlog.info(".git directory changed, recreating overlay") - overlay_init_done = False + if len(new_files.splitlines()): + cloudlog.info(".git directory changed, recreating overlay") + overlay_initialized = False - if not overlay_init_done: - init_ovfs() - overlay_init_done = True + if not overlay_initialized: + init_ovfs() + overlay_initialized = True - if params.get("IsOffroad") == b"1": - attempt_update() - update_failed_count = 0 - else: - cloudlog.info("not running updater, openpilot running") + if params.get("IsOffroad") == b"1": + update_available = attempt_update(wait_helper) or update_available + update_failed_count = 0 + if not update_available and os.path.isdir(NEOSUPDATE_DIR): + shutil.rmtree(NEOSUPDATE_DIR) + else: + cloudlog.info("not running updater, openpilot running") - except subprocess.CalledProcessError as e: - cloudlog.event( - "update process failed", - cmd=e.cmd, - output=e.output, - returncode=e.returncode - ) - overlay_init_done = False - except Exception: - cloudlog.exception("uncaught updated exception, shouldn't happen") + except subprocess.CalledProcessError as e: + cloudlog.event( + "update process failed", + cmd=e.cmd, + output=e.output, + returncode=e.returncode + ) + exception = e + overlay_initialized = False + except Exception: + cloudlog.exception("uncaught updated exception, shouldn't happen") params.put("UpdateFailedCount", str(update_failed_count)) - wait_between_updates(wait_helper.ready_event) - if wait_helper.shutdown: - break + if exception is None: + params.delete("LastUpdateException") + else: + params.put("LastUpdateException", f"command failed: {exception.cmd}\n{exception.output}") + + # Wait 10 minutes between update attempts + wait_helper.sleep(60*10) - # We've been signaled to shut down dismount_ovfs() if __name__ == "__main__": diff --git a/selfdrive/version.py b/selfdrive/version.py index 0999e751..4fec0b4c 100644 --- a/selfdrive/version.py +++ b/selfdrive/version.py @@ -1,47 +1,47 @@ #!/usr/bin/env python3 import os import subprocess +from common.basedir import BASEDIR from selfdrive.swaglog import cloudlog -def get_git_commit(default=None): +def run_cmd(cmd): + return subprocess.check_output(cmd, encoding='utf8').strip() + + +def run_cmd_default(cmd, default=None): try: - return subprocess.check_output(["git", "rev-parse", "HEAD"], encoding='utf8').strip() + return run_cmd(cmd) except subprocess.CalledProcessError: return default +def get_git_commit(branch="HEAD", default=None): + return run_cmd_default(["git", "rev-parse", branch], default=default) + + def get_git_branch(default=None): - try: - return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], encoding='utf8').strip() - except subprocess.CalledProcessError: - return default + return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"], default=default) def get_git_full_branchname(default=None): - try: - return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], encoding='utf8').strip() - except subprocess.CalledProcessError: - return default + return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], default=default) def get_git_remote(default=None): try: - local_branch = subprocess.check_output(["git", "name-rev", "--name-only", "HEAD"], encoding='utf8').strip() - tracking_remote = subprocess.check_output(["git", "config", "branch." + local_branch + ".remote"], encoding='utf8').strip() - return subprocess.check_output(["git", "config", "remote." + tracking_remote + ".url"], encoding='utf8').strip() - - except subprocess.CalledProcessError: - try: - # Not on a branch, fallback - return subprocess.check_output(["git", "config", "--get", "remote.origin.url"], encoding='utf8').strip() - except subprocess.CalledProcessError: - return default + local_branch = run_cmd(["git", "name-rev", "--name-only", "HEAD"]) + tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"]) + return run_cmd(["git", "config", "remote." + tracking_remote + ".url"]) + except subprocess.CalledProcessError: # Not on a branch, fallback + return run_cmd_default(["git", "config", "--get", "remote.origin.url"], default=default) with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "common", "version.h")) as _versionf: version = _versionf.read().split('"')[1] +prebuilt = os.path.exists(os.path.join(BASEDIR, 'prebuilt')) + training_version = b"0.2.0" terms_version = b"2" @@ -51,35 +51,42 @@ tested_branch = False origin = get_git_remote() branch = get_git_full_branchname() -try: - # This is needed otherwise touched files might show up as modified +if (origin is not None) and (branch is not None): try: - subprocess.check_call(["git", "update-index", "--refresh"]) - except subprocess.CalledProcessError: - pass - - if (origin is not None) and (branch is not None): comma_remote = origin.startswith('git@github.com:commaai') or origin.startswith('https://github.com/commaai') tested_branch = get_git_branch() in ['devel', 'release2-staging', 'dashcam-staging', 'release2', 'dashcam'] - dirty = not comma_remote + dirty = False + + # Actually check dirty files + if not prebuilt: + # This is needed otherwise touched files might show up as modified + try: + subprocess.check_call(["git", "update-index", "--refresh"]) + except subprocess.CalledProcessError: + pass + dirty = (subprocess.call(["git", "diff-index", "--quiet", branch, "--"]) != 0) + + # Log dirty files + if dirty and comma_remote: + try: + dirty_files = run_cmd(["git", "diff-index", branch, "--"]) + cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, + dirty_files=dirty_files, commit=get_git_commit(), origin_commit=get_git_commit(branch)) + except subprocess.CalledProcessError: + pass + + dirty = dirty or (not comma_remote) dirty = dirty or ('master' in branch) - dirty = dirty or (subprocess.call(["git", "diff-index", "--quiet", branch, "--"]) != 0) - if dirty: - dirty_files = subprocess.check_output(["git", "diff-index", branch, "--"], encoding='utf8') - commit = subprocess.check_output(["git", "rev-parse", "--verify", "HEAD"], encoding='utf8').rstrip() - origin_commit = subprocess.check_output(["git", "rev-parse", "--verify", branch], encoding='utf8').rstrip() - cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, - dirty_files=dirty_files, commit=commit, origin_commit=origin_commit) - -except subprocess.CalledProcessError: - dirty = True - cloudlog.exception("git subprocess failed while checking dirty") + except subprocess.CalledProcessError: + dirty = True + cloudlog.exception("git subprocess failed while checking dirty") if __name__ == "__main__": print("Dirty: %s" % dirty) print("Version: %s" % version) print("Remote: %s" % origin) - print("Branch %s" % branch) + print("Branch: %s" % branch) + print("Prebuilt: %s" % prebuilt)