diff --git a/Jenkinsfile b/Jenkinsfile index c3625120386f04..dd0e2c12fa1b31 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 { - 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"' - } + /* + stage('PC tests') { + agent { + dockerfile { + filename 'Dockerfile.openpilot' + args '--privileged --shm-size=1G --user=root' + } + } + stages { + stage('Build') { + steps { + sh 'scons -j$(nproc)' } } } + post { + always { + // fix permissions since docker runs as another user + sh "chmod -R 777 ." + } + } } + */ - 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"' - } - } + stage('On-device Tests') { + agent { + docker { + image 'python:3.7.3' + args '--user=root' } } - } - 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"' + 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 7fff3e9062fe45..5b4e53003b119f 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,22 @@ git fetch --all git checkout xx979xx/HKG_community git checkout origin/release2 ``` +- To update a branch: +``` +git pull +``` +- To reset a branch: +``` +git reset xx979xx/HKG_community --hard +``` Changes: ------ +- UI Toggles for community features: you do not have to modify the code to enable/disable community features anymore, find the new toggels in Developer Settings. - HKG longitudinal control: warrings: it is beta, be carful!! Openpilot will control the speed of your car, you can engage with cruise button. if your car has SCC on bus0 (CAN1) you have to disable it, otherwise this won't works. -To enable long control, change line 255 in selfdrive/car/hyundai/interface.py to: -```python - ret.openpilotLongitudinalControl = True -``` -- Auto LCA: credit to @SiGmAX666: Auto Lane change assist, no need for steering nudge. To enable Auto LCA(disabled by default), change line 189 in selfdrive/car/hyundai/interface.py to: -```python - ret.autoLcaEnabled = True -``` +To enable long control, find the option under Developer Settings in your device. +- Auto LCA: credit to @SiGmAX666: Auto Lane change assist, no need for steering nudge. To enable Auto LCA(disabled by default), find the option under Developer Settings in your device. - Enable by Cruise button: Only for Car without long control, Openpilot will engage when turn cruise control on. - Turning disable: thank to Ku7: Openpilot will disable steering while turning signal on and speed below 60 kph, Enable again after 1 second. - Disabling by LKAS button: Openpilot will disable and enable steering by toggling LKAS button. @@ -147,7 +150,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 | @@ -157,7 +160,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 | @@ -217,6 +220,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 | @@ -225,11 +229,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 | @@ -237,9 +242,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 5559cd3c63c911..0c6dd3d4fb0783 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 7e5a412b56124d..322bdd5f9faeed 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 f411e636559926..72142ca96a510b 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 ec651dd839a7e6..0ab943db974b65 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 2bf4d20b4f4dc6..7351fdb6c81400 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -112,9 +112,10 @@ struct CarEvent @0x9b1657f34caf3ad3 { wrongCruiseMode @87; neosUpdateRequired @88; modeldLagging @89; - turningIndicatorOn @90; - lkasButtonOff @91; - autoLaneChange @92; + deviceFalling @90; + turningIndicatorOn @91; + lkasButtonOff @92; + autoLaneChange @93; } } @@ -411,8 +412,7 @@ struct CarParams { mdpsBus @51: Int8; sasBus @52: Int8; sccBus @53: Int8; - autoLcaEnabled @54: Bool; - spasEnabled @55: Bool; + spasEnabled @54: Bool; struct LateralParams { torqueBP @0 :List(Int32); @@ -482,6 +482,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 1ce307126adb98..cca6f1275be25a 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 { @@ -802,7 +806,8 @@ struct PathPlan { desire @17 :Desire; laneChangeState @18 :LaneChangeState; laneChangeDirection @19 :LaneChangeDirection; - autoLaneChangeTimer @20 :Int8; + autoLaneChangeEnabled @20 :Bool; + autoLaneChangeTimer @21 :Int8; enum Desire { none @0; @@ -865,6 +870,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 7aa16cad4c26b6..5e36bd8d8c17c0 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 20bb35213c02ae..fb0f96af4d0e12 100644 --- a/cereal/messaging/messaging.hpp +++ b/cereal/messaging/messaging.hpp @@ -59,34 +59,36 @@ class Poller { }; 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 3e1c41ce15f58b..992b39159975a8 100644 --- a/cereal/messaging/messaging_pyx_setup.py +++ b/cereal/messaging/messaging_pyx_setup.py @@ -39,7 +39,7 @@ def get_ext_filename(self, ext_name): 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 @@ def get_ext_filename(self, ext_name): 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 66b7696cf299dc..a0f6c1ef4e031f 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 fc362338f0b3f1..490e903f112759 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 103d416f535044..35abeb9ee43c3e 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 abd7e04375efff..3d7011fe295d6e 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 3f7d049cc55342..d11770faf6cc74 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 9b947a4320bf2d..630875998487dd 100644 --- a/common/kalman/tests/test_simple_kalman.py +++ b/common/kalman/tests/test_simple_kalman.py @@ -21,10 +21,10 @@ def setUp(self): 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 @@ def test_old_equal_new(self): 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 @@ def test_new_is_faster(self): 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 7b90913e7d6823..0b1e2a6d6ce752 100755 --- a/common/params.py +++ b/common/params.py @@ -80,12 +80,16 @@ class UnknownKeyName(Exception): "IsUploadRawEnabled": [TxType.PERSISTENT], "LastAthenaPingTime": [TxType.PERSISTENT], "LastUpdateTime": [TxType.PERSISTENT], + "LastUpdateException": [TxType.PERSISTENT], "LimitSetSpeed": [TxType.PERSISTENT], "LimitSetSpeedNeural": [TxType.PERSISTENT], "LiveParameters": [TxType.PERSISTENT], "LongitudinalControl": [TxType.PERSISTENT], "OpenpilotEnabledToggle": [TxType.PERSISTENT], "LaneChangeEnabled": [TxType.PERSISTENT], + "LongControlEnabled": [TxType.PERSISTENT], + "MadModeEnabled": [TxType.PERSISTENT], + "AutoLaneChangeEnabled": [TxType.PERSISTENT], "PandaFirmware": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "PandaFirmwareHex": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "PandaDongleId": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], @@ -108,6 +112,7 @@ class UnknownKeyName(Exception): "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 +324,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 c49b124c98dcd3..53e8ee5215829d 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -4,14 +4,17 @@ 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 @@ def __exit__(self, exc_type, exc_value, traceback): 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 88da8e53f53053..b815d8022a5b6a 100755 --- a/common/text_window.py +++ b/common/text_window.py @@ -6,20 +6,22 @@ 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 @@ def close(self): 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 @@ def __exit__(self, exc_type, exc_value, traceback): 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 7c051746a3c521..0f729522590649 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 e56a6f34bfb36e..b406c33fd7d551 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 313683b6f67cf6..8a1aa0ad723250 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 070d174711a318..a3b46858b1e4ec 100644 --- a/common/transformations/model.py +++ b/common/transformations/model.py @@ -2,6 +2,7 @@ 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 @@ 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 f0920942b67bda..415e247ab26323 100644 --- a/common/transformations/orientation.py +++ b/common/transformations/orientation.py @@ -46,7 +46,6 @@ def f(*inps): 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 15858eabb4d66e..66047420c12d34 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 a76be8b8fde2ef..ca0b9270b88e06 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,92 +350,78 @@ 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); - if (!check_battery()) { - set_battery_low(); - int battery_cap = battery_capacity(); - while(battery_cap < min_battery_cap) { - battery_cap = battery_capacity(); - battery_cap_text = std::to_string(battery_cap); - usleep(1000000); - } - set_running(); - } + // ** quick checks before download ** if (!check_space()) { set_error("2GB of free space required to update"); - return; + return false; } 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); - } - + 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; + 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(); - std::string recovery_hash = manifest["recovery_hash"].string_value(); - int recovery_len = manifest["recovery_len"].int_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; + return false; } - // std::string installer_fn = stage_download(installer_url, installer_hash, "installer"); + // std::string installer_fn = download(installer_url, installer_hash, "installer"); // if (installer_fn.empty()) { // //error'd // return; // } - std::string recovery_fn; + // ** handle recovery download ** if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) { set_progress("Skipping recovery flash..."); } else { @@ -414,20 +431,50 @@ struct Updater { 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"); + recovery_fn = download(recovery_url, recovery_hash, "recovery"); if (recovery_fn.empty()) { // error'd - return; + return false; } } } - std::string ota_fn = stage_download(ota_url, ota_hash, "update"); + // ** 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(); + while(battery_cap < min_battery_cap) { + battery_cap = battery_capacity(); + battery_cap_text = std::to_string(battery_cap); + usleep(1000000); + } + set_running(); + } + + bool sucess = download_stage(); + if (!sucess) { return; } + // ** install update ** + if (!check_battery()) { set_battery_low(); int battery_cap = battery_capacity(); @@ -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 00000000000000..eeebfc9eb0eb1b --- /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 ae1660411bf209..af5483562d652a 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 00000000000000..9a86d315ce2e0c --- /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 44ddc8f0983515..9935584bf4c00a 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 1d65c548e880ef..f259691944297c 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 8fb0fc8aa01663..c8d4f347490397 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 b071dc3623a1d8..72a0cde7c1eced 100644 --- a/opendbc/can/common_pyx_setup.py +++ b/opendbc/can/common_pyx_setup.py @@ -63,9 +63,9 @@ def get_ext_filename(self, ext_name): include_dirs=include_dirs, extra_link_args=extra_link_args, ), + nthreads=4, annotate=ANNOTATE ), - nthreads=4, ) if platform.system() == "Darwin": @@ -85,9 +85,9 @@ def get_ext_filename(self, ext_name): 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 f12b2e6c4edf5e..bd5adf6ffed131 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 00000000000000..9bf77b3f4b3ea0 --- /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 d1c7605a1f21e3..958b5c1f1b1375 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 00000000000000..96bc0064874809 --- /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 e1743ff0b57772..00000000000000 --- 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 00000000000000..39063a30d0ad4f --- /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 00000000000000..62e3e84873ff5f --- /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 00000000000000..0d5c14bc0d2c37 --- /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 28516299c85d73..84fca5469250cb 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 3a009a5a13173f..84964244ed02b3 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 24b93b540dba19..2daba2a141d7a7 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/main.c b/panda/board/main.c index e08756dce62d07..640d9b0848ac07 100644 --- a/panda/board/main.c +++ b/panda/board/main.c @@ -148,11 +148,7 @@ void set_safety_mode(uint16_t mode, int16_t param) { set_intercept_relay(true); heartbeat_counter = 0U; if (board_has_obd()) { - if (mode_copy == SAFETY_HYUNDAI_LEGACY || mode_copy == SAFETY_HYUNDAI) { - current_board->set_can_mode(CAN_MODE_OBD_CAN2); - } else { - current_board->set_can_mode(CAN_MODE_NORMAL); - } + current_board->set_can_mode(CAN_MODE_NORMAL); } can_silent = ALL_CAN_LIVE; break; diff --git a/panda/board/safety.h b/panda/board/safety.h index 7412a59dd2e5fa..0a1e64c2b34be2 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_defaults.h b/panda/board/safety/safety_defaults.h index b86de2e93cb77d..97ec160c32dcd0 100644 --- a/panda/board/safety/safety_defaults.h +++ b/panda/board/safety/safety_defaults.h @@ -159,6 +159,9 @@ static void alloutput_init(int16_t param) { UNUSED(param); controls_allowed = true; relay_malfunction_reset(); + if (board_has_obd()) { + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } } static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { diff --git a/panda/board/safety/safety_hyundai.h b/panda/board/safety/safety_hyundai.h index 16525c02258e63..770aaa06377c7f 100644 --- a/panda/board/safety/safety_hyundai.h +++ b/panda/board/safety/safety_hyundai.h @@ -13,7 +13,7 @@ int OP_CLU_live = 0; int OP_SCC_live = 0; int car_SCC_live = 0; int OP_EMS_live = 0; -int hyundai_mdps_bus = 0; +int hyundai_mdps_bus = -1; bool hyundai_LCAN_on_bus1 = false; bool hyundai_forward_bus1 = false; const CanMsg HYUNDAI_TX_MSGS[] = { @@ -127,12 +127,17 @@ static int hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { } if (bus == 1 && hyundai_LCAN_on_bus1) {valid = false;} - // check if we have a MDPS on Bus1 and LCAN not on the bus - if (bus == 1 && (addr == 593 || addr == 897) && !hyundai_LCAN_on_bus1) { - if (hyundai_mdps_bus != bus || !hyundai_forward_bus1) { + // check MDPS on Bus + if ((addr == 593 || addr == 897) && hyundai_mdps_bus != bus) { + if (bus == 0){ + hyundai_mdps_bus = bus; + if (!hyundai_forward_bus1 && board_has_obd()) { + current_board->set_can_mode(CAN_MODE_NORMAL); + } + } else if (bus == 1 && !hyundai_LCAN_on_bus1) { hyundai_mdps_bus = bus; hyundai_forward_bus1 = true; - } + } } // check if we have a SCC on Bus1 and LCAN not on the bus if (bus == 1 && addr == 1057 && !hyundai_LCAN_on_bus1) { @@ -290,7 +295,7 @@ static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // ensuring that only the cancel button press is sent (VAL 4) when controls are off. // This avoids unintended engagements while still allowing resume spam //allow clu11 to be sent to MDPS if MDPS is not on bus0 - if (addr == 1265 && !controls_allowed && (bus != hyundai_mdps_bus || !hyundai_mdps_bus)) { + if (addr == 1265 && !controls_allowed && (bus != hyundai_mdps_bus && hyundai_mdps_bus == 1)) { if ((GET_BYTES_04(to_send) & 0x7) != 4) { tx = 0; } @@ -315,7 +320,7 @@ static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { // forward cam to ccan and viceversa, except lkas cmd if (!relay_malfunction) { if (bus_num == 0) { - if (!OP_CLU_live || addr != 1265 || !hyundai_mdps_bus) { + if (!OP_CLU_live || addr != 1265 || hyundai_mdps_bus == 0) { if (!OP_MDPS_live || addr != 593) { if (!OP_EMS_live || addr != 790) { bus_fwd = hyundai_forward_bus1 ? 12 : 2; @@ -353,7 +358,7 @@ static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { bus_fwd = fwd_to_bus1; // EON create SCC12 for Car OP_SCC_live -= 1; } - } else if (!hyundai_mdps_bus) { + } else if (hyundai_mdps_bus == 0) { bus_fwd = fwd_to_bus1; // EON create LKAS and LFA for Car OP_LKAS_live -= 1; } else { @@ -377,6 +382,10 @@ static void hyundai_init(int16_t param) { relay_malfunction_reset(); hyundai_legacy = false; + + if (board_has_obd()) { + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } } static void hyundai_legacy_init(int16_t param) { @@ -385,6 +394,10 @@ static void hyundai_legacy_init(int16_t param) { relay_malfunction_reset(); hyundai_legacy = true; + + if (board_has_obd()) { + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } } const safety_hooks hyundai_hooks = { diff --git a/panda/board/safety/safety_nissan.h b/panda/board/safety/safety_nissan.h index 0dec23e8a0d8df..d1ca0c836c10f2 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 2f480bc6518ad1..6df607e5907203 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 @@ def __init__(self, folder, name, Q, x_initial, P_initial, dim_main, dim_main_err 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 @@ def predict_and_update_batch(self, t, kind, z, R, extra_args=[[]], augment=False # 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 d7e575d06472ad..0ccbe6bd24eeed 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 c44af47364eb32..a3bb2b0b4cf389 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)) +#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 + namespace { +Panda * panda = NULL; +std::atomic safety_setter_thread_running(false); 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__ -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; +struct tm get_time(){ + time_t rawtime; + time(&rawtime); -bool pigeon_thread_initialized = false; -pthread_t pigeon_thread_handle; + struct tm sys_time; + gmtime_r(&rawtime, &sys_time); -bool pigeon_needs_init; + return sys_time; +} -void pigeon_init(); -void *pigeon_thread(void *crap); +bool time_valid(struct tm sys_time){ + return 1900 + sys_time.tm_year >= 2019; +} -void *safety_setter_thread(void *s) { +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); - - pthread_mutex_lock(&usb_lock); + LOGW("setting safety model: %d with param %d", (int)safety_model, safety_param); - // set in the mutex to avoid race - safety_setter_thread_initialized = false; + panda->set_safety_model(safety_model, safety_param); - 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); - - 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); + if (panda->has_rtc){ + struct tm sys_time = get_time(); + struct tm rtc_time = panda->get_rtc(); - //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); - } - - 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++; - } + int recv = panda->can_receive(event); + if (recv){ + pm.send("can", msg); } - // 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; - } - - err = pthread_mutex_init(&usb_lock, NULL); - assert(err == 0); - - // init libusb - err = libusb_init(&ctx); - assert(err == 0); + while (!do_exit){ + std::vector threads; + threads.push_back(std::thread(can_health_thread)); -#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); + // connect to the board + usb_retry_connect(); - //while (!do_exit) usleep(1000); + 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)); - // destruct libusb + for (auto &t : threads) t.join(); - libusb_close(dev_handle); - libusb_exit(ctx); + delete panda; + panda = NULL; + } } diff --git a/selfdrive/boardd/boardd_setup.py b/selfdrive/boardd/boardd_setup.py index cf71901cb66a97..4b0859018323a3 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 00000000000000..5820fa40049a96 --- /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 00000000000000..3586cda74fed91 --- /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 45e50132067353..aecca564a265ab 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 79e6c8f0973558..dfed65238c2a6a 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 063b813c7bbe96..812f1a5968896f 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 4e1ce307c8bf30..658ab55bae22ea 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 4ba10bf4bea392..317618c0b26db3 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 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 315d3793d10b24..a84fcd732f9839 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 4308df5f37b667..1e051fe13c4850 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 f25cc69f7cde2b..b81526e9c002f8 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -11,7 +11,6 @@ def __init__(self, dbc_name, CP, VM): 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 d935e8eaa057f6..b6fdb11314c294 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -103,6 +103,13 @@ def get_can_parser(CP): ("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 @@ def get_cam_can_parser(CP): ("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 294b96c5eae1af..fbc469ebeb0656 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -14,8 +14,6 @@ def compute_gb(accel, speed): 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 @@ def update(self, c, can_strings): # 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 40a7c5a7422b0d..3139efad34ab4d 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 2070947cdcc2a0..b7fb53f530c61c 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -4,7 +4,6 @@ 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 @@ class CAR: 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 59e6191420b0f3..6d6c82f0b8fa67 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -14,7 +14,7 @@ def compute_gb(accel, speed): 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 b01814bca659ce..20a435b0821dff 100755 --- a/selfdrive/car/ford/radar_interface.py +++ b/selfdrive/car/ford/radar_interface.py @@ -8,14 +8,13 @@ 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 1328b11fe056f1..0fc3d278ce4161 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -16,13 +16,13 @@ def compute_gb(accel, speed): 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 f2f8c3cec9d78f..dc2c2f7b7cb055 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 @@ 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 @@ def __init__(self, CP): 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 4845e482f8a61d..4aaa98aa6680cb 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -172,7 +172,7 @@ def __init__(self, CP): 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 @@ def update(self, cp, cp_cam): 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 @@ def get_cam_can_parser(CP): 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 7e5c46c895b7a7..ac8bfe3b9f7ba6 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -83,7 +83,7 @@ def __init__(self, CP, CarController, CarState): 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 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, 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 @@ def update(self, c, can_strings): # ******************* 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 a921534c5aead8..6acec73d3cd61e 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 @@ def __init__(self, CP): 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 @@ def update(self, can_strings): # 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 32bc2d3783014e..713c38ae1bec74 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -885,10 +885,23 @@ class CAR: ], (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 @@ class CAR: 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 @@ class CAR: 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 4dc5fcb0b3a44c..14b183ae2b207a 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -69,7 +69,7 @@ def update(self, cp, cp2, cp_cam): ret.cruiseState.available = (cp_scc.vl["SCC11"]["MainMode_ACC"] != 0) if not self.no_radar else \ cp.vl['EMS16']['CRUISE_LAMP_M'] != 0 ret.cruiseState.standstill = cp_scc.vl["SCC11"]['SCCInfoDisplay'] == 4. if not self.no_radar else False - self.is_set_speed_in_mph = int(cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"]) + self.is_set_speed_in_mph = bool(cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"]) if ret.cruiseState.enabled: speed_conv = CV.MPH_TO_MS if self.is_set_speed_in_mph else CV.KPH_TO_MS ret.cruiseState.speed = cp_scc.vl["SCC11"]['VSetDis'] * speed_conv if not self.no_radar else \ @@ -502,7 +502,7 @@ def get_cam_can_parser(CP): 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), @@ -521,7 +521,9 @@ def get_cam_can_parser(CP): ("CF_Lkas_LdwsOpt_USM", "LKAS11", 0) ] - checks = [] + checks = [ + ("LKAS11", 100) + ] if CP.sccBus == 2: signals += [ ("MainMode_ACC", "SCC11", 1), @@ -576,5 +578,6 @@ def get_cam_can_parser(CP): ("SCC11", 50), ("SCC12", 50), ] + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index 58f5596cd4764f..a321cbf28ee746 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, CAR.SONATA_HEV, CAR.SANTA_FE, CAR.KONA_EV, CAR.NIRO_EV]: - 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 @@ -37,6 +37,13 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, # Note: the warning is hidden while the blinkers are on values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0 + elif car_fingerprint == CAR.GENESIS: + # This field is actually LdwsActivemode + # Genesis and Optima fault when forwarding while engaged + values["CF_Lkas_LdwsActivemode"] = 2 + elif car_fingerprint == CAR.OPTIMA: + values["CF_Lkas_LdwsActivemode"] = 0 + dat = packer.make_can_msg("LKAS11", 0, values)[2] if car_fingerprint in CHECKSUM["crc8"]: diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 71815b11bc9b3d..83b7bda91da679 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -5,6 +5,7 @@ from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.controls.lib.pathplanner import LANE_CHANGE_SPEED_MIN +from common.params import Params GearShifter = car.CarState.GearShifter EventName = car.CarEvent.EventName @@ -14,6 +15,7 @@ class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): super().__init__(CP, CarController, CarState) self.cp2 = self.CS.get_can2_parser(CP) + self.mad_mode_enabled = Params().get('MadModeEnabled') == b'1' self.lkas_button_alert = False @staticmethod @@ -105,10 +107,10 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, 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]] @@ -262,9 +264,8 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, ret.sccBus = 0 if 1056 in fingerprint[0] else 1 if 1056 in fingerprint[1] and 1296 not in fingerprint[1] \ else 2 if 1056 in fingerprint[2] else -1 ret.radarOffCan = ret.sccBus == -1 - ret.openpilotLongitudinalControl = False #TODO make ui toggle + ret.openpilotLongitudinalControl = Params().get('LongControlEnabled') == b'1' ret.enableCruise = not ret.radarOffCan - ret.autoLcaEnabled = False ret.spasEnabled = False return ret @@ -283,7 +284,7 @@ def update(self, c, can_strings): self.CP.enableCruise = True # most HKG cars has no long control, it is safer and easier to engage by main on - if not self.CP.openpilotLongitudinalControl: + if self.mad_mode_enabled and not self.CC.longcontrol: ret.cruiseState.enabled = ret.cruiseState.available # some Optima only has blinker flash signal if self.CP.carFingerprint == CAR.OPTIMA: @@ -342,7 +343,7 @@ def update(self, c, can_strings): events.add(EventName.turningIndicatorOn) if self.lkas_button_alert: events.add(EventName.lkasButtonOff) - if not self.CC.longcontrol and EventName.pedalPressed in events.events: + if self.mad_mode_enabled and not self.CC.longcontrol and EventName.pedalPressed in events.events: events.events.remove(EventName.pedalPressed) # handle button presses diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py index d77d0383a2a8ed..97bccc693713d8 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 @@ -31,10 +29,7 @@ def __init__(self, CP): 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 12b079c1b938fa..d79537969fedcc 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -48,7 +48,7 @@ class CAR: CEED = "KIA CEED 2019" CARDENZA = "KIA K7 2016-2019" CARDENZA_HEV = "KIA K7 HEV 2016-2019" - + class Buttons: NONE = 0 RES_ACCEL = 1 @@ -71,7 +71,7 @@ class Buttons: }], 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 },{ @@ -222,11 +222,18 @@ class Buttons: CAR.CARDENZA_HEV: [{ 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 576: 8, 593: 8, 688: 5, 832: 8, 865: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1096: 8, 1102: 8, 1108: 8, 1136: 6, 1138: 5, 1151: 8, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 7, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1210: 8, 1227: 8, 1265: 4, 1268: 8, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1343: 8, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1379: 8, 1407: 8, 1419: 8, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1476: 8, 1535: 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 = { # genesis CAR.GENESIS_G70: { @@ -377,19 +384,21 @@ class Buttons: FEATURES = { # Use Cluster for Gear Selection, rather than Transmission - "use_cluster_gears": [CAR.ELANTRA, CAR.KONA, CAR.ELANTRA_GT_I30, CAR.CARDENZA, CAR.NIRO_HEV, CAR.GRANDEUR], + "use_cluster_gears": set([CAR.ELANTRA, CAR.KONA, CAR.ELANTRA_GT_I30, CAR.CARDENZA, CAR.NIRO_HEV, CAR.GRANDEUR]), # Use TCU Message for Gear Selection - "use_tcu_gears": [CAR.OPTIMA, CAR.SONATA19, CAR.VELOSTER], + "use_tcu_gears": set([CAR.OPTIMA, CAR.SONATA19, CAR.VELOSTER]), # Use E_GEAR Message for Gear Selection - "use_elect_gears": [CAR.OPTIMA_HEV, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.SONATA_HEV, CAR.NIRO_EV, CAR.CARDENZA_HEV, CAR.GRANDEUR_HEV], + "use_elect_gears": set([CAR.OPTIMA_HEV, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.SONATA_HEV, CAR.NIRO_EV, CAR.CARDENZA_HEV, CAR.GRANDEUR_HEV]), # Use E_EMS11 Message for Gas and Brake for Hybrid/ELectric - "use_elect_ems": [CAR.OPTIMA_HEV, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.SONATA_HEV, CAR.NIRO_EV, CAR.CARDENZA_HEV, CAR.GRANDEUR_HEV], + "use_elect_ems": set([CAR.OPTIMA_HEV, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.SONATA_HEV, CAR.NIRO_EV, CAR.CARDENZA_HEV, CAR.GRANDEUR_HEV]), # send LFA MFA message for new HKG models - "send_lfa_mfa": [CAR.SONATA, CAR.PALISADE, CAR.SONATA_HEV, CAR.SANTA_FE, CAR.NIRO_EV], - "has_scc13": [], - "has_scc14": [], + "send_lfa_mfa": set([CAR.SONATA, CAR.PALISADE, CAR.SONATA_HEV, CAR.SANTA_FE, CAR.NIRO_EV]), + "has_scc13": set([]), + "has_scc14": set([]), # 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.STINGER, CAR.IONIQ, CAR.KONA, CAR.KONA_EV, CAR.FORTE, CAR.PALISADE, CAR.GENESIS_G70], + "use_fca": set([CAR.SONATA, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.STINGER, CAR.IONIQ, CAR.KONA, CAR.KONA_EV, CAR.FORTE, CAR.PALISADE, CAR.GENESIS_G70]), + + "use_bsm": set([CAR.SONATA, CAR.PALISADE, CAR.GENESIS, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.KONA]), } DBC = { diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index c73aa93847510a..bd5c8eb4b78954 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -27,6 +27,7 @@ def __init__(self, CP, CarController, CarState): 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 @@ def compute_gb(accel, speed): 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 @@ def __init__(self, CP): 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 @@ def parse_gear_shifter(gear): @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 18a26cc38a1b6a..03f3a026b5b432 100644 --- a/selfdrive/car/mazda/carstate.py +++ b/selfdrive/car/mazda/carstate.py @@ -162,8 +162,8 @@ def get_can_parser(CP): @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 059d734153b74e..dfa959da38de3d 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -15,7 +15,7 @@ def compute_gb(accel, speed): 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 @@ def update(self, c, can_strings): 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 617f7e23d2cc6f..d0298ec83829b1 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -33,7 +33,7 @@ def compute_gb(accel, speed): 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 5d988cb935183d..5838d67ae3241f 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -2,7 +2,7 @@ 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 @@ def update(self, enabled, CS, frame, actuators, cruise_cancel, hud_alert, 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 d43db51b6b9c19..f2076183d97857 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 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 @@ def update(self, cp, cp_adas, cp_cam): 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 cc9547aedddb89..9c419c5a8f41c0 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -14,7 +14,7 @@ def compute_gb(accel, speed): 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 4271b7f0e5489e..0630a8cb946b8d 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 06863b71cd975c..744fd0bcc9ddbb 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 @@ def __init__(self): 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 ### - - if (frame % P.STEER_STEP) == 0: + # *** steering *** + if (frame % self.params.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 c2406f2ffef5fc..5b5e23599c9735 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -4,7 +4,7 @@ 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 @@ def update(self, cp, cp_cam): 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 @@ def update(self, cp, cp_cam): 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 @@ def update(self, cp, cp_cam): 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 @@ def get_can_parser(CP): 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), - - ("Counter", "ES_Distance", 0), - ("Signal1", "ES_Distance", 0), - ("Signal2", "ES_Distance", 0), - ("Main", "ES_Distance", 0), - ("Signal3", "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), - ("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", 10), - ] + if CP.carFingerprint in PREGLOBAL_CARS: + signals = [ + ("Cruise_Set_Speed", "ES_DashStatus", 0), + ("Not_Ready_Startup", "ES_DashStatus", 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), + ] + + checks = [ + ("ES_DashStatus", 20), + ("ES_CruiseThrottle", 20), + ] + else: + signals = [ + ("Cruise_Set_Speed", "ES_DashStatus", 0), + ("Conventional_Cruise", "ES_DashStatus", 0), + + ("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 66a5d995132bd5..6d65f64f3d9688 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 @@ def compute_gb(accel, speed): 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 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, 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 d0850afc9e8f5d..8249d36ba93197 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -5,8 +5,7 @@ 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 d31c5cfb08f831..8cbb6fe72dacb1 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 @@ class CAR: { 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 @@ class CAR: } 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 1800a71d03f9ce..069d5af00b6f25 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -63,7 +63,7 @@ def test_car_interfaces(self): # 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 d4cc71640f7e5b..4cf84904e733c3 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -182,9 +182,14 @@ def get_can_parser(CP): @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 7720e627f78365..e31eaee4ffa973 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -313,7 +313,6 @@ def update(self, c, can_strings): 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 3a66beed0eb3ba..a7d2ec37bb26db 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 @@ def __init__(self, CP): 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 6755075d1e5ef0..da18bfba965ebf 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -341,6 +341,7 @@ class CAR: b'8646F0603400 ', b'8646F0605000 ', b'8646F0606000 ', + b'8646F0606100 ', ], }, CAR.CAMRYH: { @@ -614,6 +615,7 @@ class CAR: 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 @@ class CAR: (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 @@ class CAR: (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 @@ class CAR: 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 @@ class CAR: 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 @@ class CAR: 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 a157805c139a20..5bb5dcc1094e05 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -4,8 +4,6 @@ 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 @@ def update(self, enabled, CS, frame, actuators, visual_alert, audible_alert, lef 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 0ee8ce50e5016b..a994130929ad15 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -53,7 +53,7 @@ def update(self, pt_cp): 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 3ec4b070003801..c041c6c44cfa3f 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 @@ def compute_gb(accel, speed): 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 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, # 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 @@ def update(self, c, can_strings): 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 @@ def update(self, c, can_strings): 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 3937a7c154f511..d99d7810261247 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -46,7 +46,7 @@ class CANBUS: } 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 694673ea6bfd54..3cd47a0957ee12 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 b66af9200aca34..d95231d5c66484 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 7e61b5f77c1b47..bfe62e4013f6a4 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -10,7 +10,7 @@ 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 @@ def __init__(self, sm=None, pm=None, can_sock=None): 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) @@ -186,7 +186,7 @@ def update_events(self, CS): if (CS.leftBlindspot and direction == LaneChangeDirection.left) or \ (CS.rightBlindspot and direction == LaneChangeDirection.right): self.events.add(EventName.laneChangeBlocked) - elif self.CP.autoLcaEnabled and self.sm['pathPlan'].autoLaneChangeTimer > 0: + elif self.sm['pathPlan'].autoLaneChangeEnabled and self.sm['pathPlan'].autoLaneChangeTimer > 0: self.events.add(EventName.autoLaneChange) else: if direction == LaneChangeDirection.left: @@ -218,6 +218,8 @@ def update_events(self, CS): 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 42daff420f267d..870d8d4b7e5803 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 cebb1a2c26139f..f343f4cd5e7b04 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 d55df5f6c6caaf..36a6dbca55c39e 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 @@ def to_msg(self): ret.append(event) return ret +@total_ordering class Alert: def __init__(self, alert_text_1, @@ -136,6 +138,9 @@ def __str__(self): 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.): @@ -554,15 +559,6 @@ def auto_lane_change_alert(CP, sm, metric): 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", @@ -683,6 +679,16 @@ def auto_lane_change_alert(CP, sm, metric): 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 5662942b8f0a4f..aa069e81fc45d1 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 d75f9db3839611..5262f480a7ad37 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -85,7 +85,7 @@ def update(self, active, CS, v_target, v_target_future, a_target, CP): 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/pathplanner.py b/selfdrive/controls/lib/pathplanner.py index e42add5f497dd3..8f9e706bdfcc87 100644 --- a/selfdrive/controls/lib/pathplanner.py +++ b/selfdrive/controls/lib/pathplanner.py @@ -54,6 +54,7 @@ def __init__(self, CP): self.setup_mpc() self.solution_invalid_cnt = 0 self.lane_change_enabled = Params().get('LaneChangeEnabled') == b'1' + self.auto_lane_change_enabled = Params().get('AutoLaneChangeEnabled') == b'1' self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none self.lane_change_timer = 0.0 @@ -113,7 +114,7 @@ def update(self, sm, pm, CP, VM): torque_applied = sm['carState'].steeringPressed and \ ((sm['carState'].steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or (sm['carState'].steeringTorque < 0 and self.lane_change_direction == LaneChangeDirection.right)) or \ - CP.autoLcaEnabled and 3.25 > self.auto_lane_change_timer > 3. + self.auto_lane_change_enabled and 3.25 > self.auto_lane_change_timer > 3. blindspot_detected = ((sm['carState'].leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or (sm['carState'].rightBlindspot and self.lane_change_direction == LaneChangeDirection.right)) @@ -231,6 +232,7 @@ def update(self, sm, pm, CP, VM): plan_send.pathPlan.desire = desire plan_send.pathPlan.laneChangeState = self.lane_change_state plan_send.pathPlan.laneChangeDirection = self.lane_change_direction + plan_send.pathPlan.autoLaneChangeEnabled = self.auto_lane_change_enabled plan_send.pathPlan.autoLaneChangeTimer = 3 - int(self.auto_lane_change_timer) pm.send('pathPlan', plan_send) diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py index 88c4d694aafefc..553e5bb6facd5c 100755 --- a/selfdrive/controls/lib/planner.py +++ b/selfdrive/controls/lib/planner.py @@ -129,7 +129,7 @@ def update(self, sm, pm, CP, VM, PP): 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 a890af9e6793d2..28cabe6c8cbeef 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -31,7 +31,7 @@ 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 00000000000000..899f932ad6b500 --- /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 fbecaa1bae3ec0..59516574d8ffca 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 e95f00c2c954d8..a27e284a9ccdf9 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -126,13 +126,21 @@ def handle_cam_odom(self, trans, rot, trans_std, rot_std): 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 3a5d515538669c..be78176844ef35 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 @@ VISION_DECIMATION = 2 SENSOR_DECIMATION = 10 +POSENET_STD_HIST = 40 def to_float(arr): @@ -52,7 +52,7 @@ def __init__(self, disabled_logs=None, dog=None): 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 @@ def __init__(self, disabled_logs=None, dog=None): 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 @@ def msg_from_state(converter, calib_from_device, H, predicted_state, predicted_c #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 - - 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 + + # 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 + 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 @@ def liveLocationMsg(self, time): 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 @@ def handle_cam_odo(self, current_time, log): 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 @@ def handle_sensors(self, current_time, log): # 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 e682ec390980f5..00000000000000 --- 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 58999e5f37d9e2..00000000000000 --- 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 a6a6eaf0b178c6..d2153487b2fc79 100755 --- a/selfdrive/locationd/models/live_kf.py +++ b/selfdrive/locationd/models/live_kf.py @@ -206,7 +206,7 @@ def __init__(self, generated_dir): 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 66f378a1da281a..00000000000000 --- 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 4d97551b3b3a70..00000000000000 --- 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 aee957bc818ac0..00000000000000 --- 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 5b14bba8a8e681..34bfc7895902b9 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 a81f80e99f4800..22d944f01b9bb5 100755 --- a/selfdrive/manager.py +++ b/selfdrive/manager.py @@ -19,7 +19,7 @@ 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 @@ def unblock_stdout(): 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 @@ def unblock_stdout(): "updated": "selfdrive.updated", "dmonitoringmodeld": ("selfdrive/modeld", ["./dmonitoringmodeld"]), "modeld": ("selfdrive/modeld", ["./modeld"]), - "driverview": "selfdrive.monitoring.driverview", } daemon_processes = { @@ -245,6 +241,12 @@ def get_running(): '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] @@ -547,6 +569,9 @@ def main(): ("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')), ("OpenpilotEnabledToggle", "1"), ("LaneChangeEnabled", "1"), + ("LongControlEnabled", "0"), + ("MadModeEnabled", "0"), + ("AutoLaneChangeEnabled", "0"), ("IsDriverViewEnabled", "0"), ] diff --git a/selfdrive/modeld/dmonitoringmodeld.cc b/selfdrive/modeld/dmonitoringmodeld.cc index 140b567ad36ee6..28776f94ee95ad 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 68b370124c884b..33dafc86cf0304 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 93fceb3ad58a54..eebf4761afa33d 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 15b28dd8d64e50..4f4203a38a1811 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 83d014f8db1d34..439b9c0051f688 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 af481712b1ad5b..f58e7b1964de4d 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 83d967d23a23ec..2bf4d61500cbef 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 4939d604d74a52..66a1f2d879ddc9 100755 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -8,14 +8,11 @@ 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 7cacd770ce2a52..76487e24e3d165 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -21,8 +21,9 @@ _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 @@ def get_pose(self, driver_state, cal_rpy, car_speed, op_engaged): # 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 4581a065493c3a..00000000000000 --- 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 2a6cf501a22121..1e53ef4245037c 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -4,8 +4,19 @@ 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 3f269afe228357..00000000000000 --- 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 a3a966ce2fc0f6..00000000000000 --- 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 00000000000000..e8228ce7d47982 --- /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 eba08fd872bcd2..2f260ec8a34d86 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 fc3b17dded415b..75e8192f4cb7c0 100644 --- a/selfdrive/test/test_openpilot.py +++ b/selfdrive/test/test_openpilot.py @@ -5,7 +5,7 @@ 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 @@ # 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 65587ca9c91683..093b832da0827f 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 @@ 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 590a6de28fd854..5b370cc29f0612 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 9b12c128f2cad0..bda90053a811cf 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 f4cb4f515bbff5..e8eb894cc9f151 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 c147f87b68e8d9..d565f846ffcf46 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 4bd1fa20dcfd16..b8edfc4e2e4cd1 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(); + } + + // timeout on frontview + if ((sm.frame - sm.rcv_frame("dMonitoringState")) > 1*UI_FREQ) { + scene.frontview = false; } - s->started = scene.thermal.getStarted() || s->preview_started; + 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 830d227e39c8b5..bf64ef27aa2124 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 bb665180ed845f..205906806733a4 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -26,48 +26,59 @@ 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 @@ def update_now(self, signum, frame): 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 link(src, dest): - # Workaround for the EON/termux build of Python having os.link removed. - return libc.link(src.encode(), dest.encode()) + def sleep(self, t): + self.ready_event.wait(timeout=t) -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() - - finalize_from_ovfs_copy() - - # 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("update successful!") + # 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() + + updated_neos = run(["bash", "-c", r"unset REQUIRED_NEOS_VERSION && source launch_env.sh && \ + echo -n $REQUIRED_NEOS_VERSION"], OVERLAY_MERGED).strip() + + 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}") + + 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"]) - - # 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]) - - if len(new_files.splitlines()): - cloudlog.info(".git directory changed, recreating overlay") - overlay_init_done = False - - if not overlay_init_done: - init_ovfs() - overlay_init_done = True - - if params.get("IsOffroad") == b"1": - attempt_update() - update_failed_count = 0 - 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") + ping_failed = os.system(f"ping -W 4 -c 1 {TEST_IP}") != 0 + if ping_failed or time_wrong: + wait_helper.sleep(30) + continue + + # 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_initialized = False + + if not overlay_initialized: + init_ovfs() + overlay_initialized = True + + 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 + ) + 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 0999e7511d20c6..4fec0b4cc75bc0 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 @@ def get_git_remote(default=None): 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)