diff --git a/common/params.py b/common/params.py index 3c5a63786c..6065c8c1ad 100755 --- a/common/params.py +++ b/common/params.py @@ -80,6 +80,7 @@ keys = { "Passive": [TxType.PERSISTENT], "RecordFront": [TxType.PERSISTENT], "ReleaseNotes": [TxType.PERSISTENT], + "SafetyModelLock": [TxType.PERSISTENT], "ShouldDoUpdate": [TxType.CLEAR_ON_MANAGER_START], "SpeedLimitOffset": [TxType.PERSISTENT], "SubscriberInfo": [TxType.PERSISTENT], diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index bd60c34087..fde2b3ea21 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -49,6 +49,7 @@ const uint32_t NO_IGNITION_CNT_MAX = 2 * 60 * 60 * 24 * 3; // turn off charge a uint32_t no_ignition_cnt = 0; bool connected_once = false; uint8_t ignition_last = 0; +bool safety_model_locked = false; pthread_t safety_setter_thread_handle = -1; pthread_t pigeon_thread_handle = -1; @@ -74,12 +75,12 @@ void *safety_setter_thread(void *s) { } LOGW("got CarVin %s", value_vin); - pthread_mutex_lock(&usb_lock); - // VIN query done, stop listening to OBDII - libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT); - - pthread_mutex_unlock(&usb_lock); + if (!safety_model_locked) { + 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); + } char *value; size_t value_sz = 0; @@ -125,6 +126,11 @@ void *safety_setter_thread(void *s) { bool usb_connect() { int err; unsigned char hw_query[1] = {0}; + char *value_safety_model; + size_t value_safety_model_sz = 0; + int safety_model; + const int result = read_db_value(NULL, "SafetyModelLock", &value_safety_model, &value_safety_model_sz); + ignition_last = 0; dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc); @@ -140,6 +146,16 @@ bool usb_connect() { libusb_control_transfer(dev_handle, 0xc0, 0xe5, 1, 0, NULL, 0, TIMEOUT); } + // check if safety mode is forced (needed to support gm) + if (value_safety_model_sz > 0) { + sscanf(value_safety_model, "%d", &safety_model); + // sanity check that we are not setting all output + assert(safety_model != (int)(cereal::CarParams::SafetyModel::ALL_OUTPUT)); + safety_model_locked = true; + LOGW("Setting Locked Safety Model %s", value_safety_model); + libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel(safety_model)), 0, NULL, 0, TIMEOUT); + } + // power off ESP libusb_control_transfer(dev_handle, 0xc0, 0xd9, 0, 0, NULL, 0, TIMEOUT); @@ -297,10 +313,11 @@ void can_health(void *s) { assert((result == 0) || (result == ERR_NO_VALUE)); // 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); - + if (!safety_model_locked) { + 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); + } if (safety_setter_thread_handle == -1) { err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL); assert(err == 0); diff --git a/selfdrive/car/lock_safety_model.py b/selfdrive/car/lock_safety_model.py new file mode 100755 index 0000000000..055d8c0c2b --- /dev/null +++ b/selfdrive/car/lock_safety_model.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +import sys +from cereal import car +from common.params import Params + +# This script locks the safety model to a given value. +# When the safety model is locked, boardd will preset panda to the locked safety model + +# run example: +# ./lock_safety_model.py gm + +if __name__ == "__main__": + + params = Params() + + if len(sys.argv) < 2: + params.delete("SafetyModelLock") + print("Clear locked safety model") + + else: + safety_model = getattr(car.CarParams.SafetyModel, sys.argv[1]) + if type(safety_model) != int: + raise Exception("Invalid safety model: " + sys.argv[1]) + if safety_model == car.CarParams.SafetyModel.allOutput: + raise Exception("Locking the safety model to allOutput is not allowed") + params.put("SafetyModelLock", str(safety_model)) + print("Locked safety model: " + sys.argv[1]) diff --git a/selfdrive/thermald.py b/selfdrive/thermald.py index a0548beb60..22a59f027d 100755 --- a/selfdrive/thermald.py +++ b/selfdrive/thermald.py @@ -129,7 +129,6 @@ def thermald_thread(): off_ts = None started_ts = None - ignition_seen = False started_seen = False thermal_status = ThermalStatus.green thermal_status_prev = ThermalStatus.green @@ -151,7 +150,6 @@ def thermald_thread(): # clear car params when panda gets disconnected if health is None and health_prev is not None: params.panda_disconnect() - ignition_seen = False health_prev = health if health is not None: @@ -233,11 +231,6 @@ def thermald_thread(): # start constellation of processes when the car starts ignition = health is not None and health.health.started - ignition_seen = ignition_seen or ignition - - # add voltage check for ignition - if not ignition_seen and health is not None and health.health.voltage > 13500: - ignition = True do_uninstall = params.get("DoUninstall") == b"1" accepted_terms = params.get("HasAcceptedTerms") == terms_version