mirror of
https://github.com/infiniteCable2/opendbc.git
synced 2026-06-08 10:54:51 +08:00
Tesla: MADS full support with VEHICLE bus harness (#239)
* Tesla: MADS full support with VEHICLE bus harness * fix msg size * enable safety * safety tests * 6 instead of 8 bytes * Revert "6 instead of 8 bytes" This reverts commit 240db92d37397b67196a5dbf52fcf4f7d63d3104.
This commit is contained in:
@@ -5,12 +5,15 @@ from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.interfaces import CarStateBase
|
||||
from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, CAR
|
||||
|
||||
from opendbc.sunnypilot.car.tesla.carstate_ext import CarStateExt
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarState(CarStateBase):
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
def __init__(self, CP, CP_SP):
|
||||
super().__init__(CP, CP_SP)
|
||||
CarStateBase.__init__(self, CP, CP_SP)
|
||||
CarStateExt.__init__(self, CP, CP_SP)
|
||||
self.can_define = CANDefine(DBC[CP.carFingerprint][Bus.party])
|
||||
self.shifter_values = self.can_define.dv["DI_systemStatus"]["DI_gear"]
|
||||
|
||||
@@ -118,11 +121,14 @@ class CarState(CarStateBase):
|
||||
# Messages needed by carcontroller
|
||||
self.das_control = copy.copy(cp_ap_party.vl["DAS_control"])
|
||||
|
||||
CarStateExt.update(self, ret, can_parsers)
|
||||
|
||||
return ret, ret_sp
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers(CP, CP_SP):
|
||||
return {
|
||||
Bus.party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.party),
|
||||
Bus.ap_party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.autopilot_party)
|
||||
Bus.ap_party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.autopilot_party),
|
||||
**CarStateExt.get_parser(CP, CP_SP),
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ from opendbc.car.tesla.carcontroller import CarController
|
||||
from opendbc.car.tesla.carstate import CarState
|
||||
from opendbc.car.tesla.values import TeslaSafetyFlags, CAR
|
||||
|
||||
from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP, TeslaSafetyFlagsSP
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
CarState = CarState
|
||||
@@ -41,4 +43,8 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
stock_cp.enableBsm = True
|
||||
|
||||
if 0x3DF in fingerprint[1]:
|
||||
ret.flags |= TeslaFlagsSP.HAS_VEHICLE_BUS.value
|
||||
ret.safetyParam |= TeslaSafetyFlagsSP.HAS_VEHICLE_BUS
|
||||
|
||||
return ret
|
||||
|
||||
@@ -37,7 +37,7 @@ class TeslaCarDocsHW4(CarDocs):
|
||||
|
||||
@dataclass
|
||||
class TeslaPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.party: 'tesla_model3_party'})
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.party: 'tesla_model3_party', Bus.adas: 'tesla_model3_vehicle'})
|
||||
|
||||
|
||||
class CAR(Platforms):
|
||||
|
||||
@@ -236,6 +236,48 @@ BO_ 1013 ID3F5VCFRONT_lighting: 8 VEH
|
||||
SG_ VCFRONT_indicatorRightRequest : 2|2@1+ (1,0) [0|2] "" Receiver
|
||||
SG_ VCFRONT_indicatorLeftRequest : 0|2@1+ (1,0) [0|2] "" Receiver
|
||||
|
||||
BO_ 851 UI_status: 8 VehicleBus
|
||||
SG_ UI_touchActive : 0|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_audioActive : 1|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_bluetoothActive : 2|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_cellActive : 3|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_displayReady : 4|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_displayOn : 5|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_wifiActive : 6|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_wifiConnected : 7|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_systemActive : 8|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_readyForDrive : 9|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_cellConnected : 10|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_vpnActive : 11|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_autopilotTrial : 12|2@1+ (1,0) [0|3] "" VehicleBus
|
||||
SG_ UI_factoryReset : 14|2@1+ (1,0) [0|3] "" VehicleBus
|
||||
SG_ UI_gpsActive : 16|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_screenshotActive : 17|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_radioActive : 18|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_cellNetworkTechnology : 19|4@1+ (1,0) [0|15] "" VehicleBus
|
||||
SG_ UI_cellReceiverPower : 24|8@1+ (1,-128) [-128|127] "dB" VehicleBus
|
||||
SG_ UI_falseTouchCounter : 32|8@1+ (1,0) [0|255] "1" VehicleBus
|
||||
SG_ UI_developmentCar : 40|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_cameraActive : 41|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_cellSignalBars : 42|3@1+ (1,0) [0|7] "" VehicleBus
|
||||
SG_ UI_trailerModeTelltale : 45|2@1+ (1,0) [0|3] "" VehicleBus
|
||||
SG_ UI_pcbTemperature : 48|8@1- (1,40) [-87|167] "degC" VehicleBus
|
||||
SG_ UI_cpuTemperature : 56|8@1- (1,40) [-87|167] "degC" VehicleBus
|
||||
|
||||
BO_ 991 UI_status2: 8 VehicleBus
|
||||
SG_ UI_mobileAppStepCount : 0|16@1+ (1,0) [0|65535] "" VehicleBus
|
||||
SG_ UI_userRequestSnapshot : 16|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_touchDetected : 17|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_validDeviceForEUSummon : 18|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_locatedAtHome : 19|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_locatedAtWork : 20|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_locatedAtFavorite : 21|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_displayInDarkMode : 22|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_userActivity : 23|1@1+ (1,0) [0|1] "" VehicleBus
|
||||
SG_ UI_activeTouchPoints : 24|8@1+ (1,0) [0|255] "" VehicleBus
|
||||
SG_ UI_linkState : 32|2@1+ (1,0) [0|3] "" VehicleBus
|
||||
SG_ UI_sentryModeState : 34|3@1+ (1,0) [0|7] "" VehicleBus
|
||||
|
||||
VAL_ 568 SpdCtrlLvr_Stat 32 "DN_1ST" 16 "UP_1ST" 8 "DN_2ND" 4 "UP_2ND" 2 "RWD" 1 "FWD" 0 "IDLE" ;
|
||||
VAL_ 568 DTR_Dist_Rq 255 "SNA" 200 "ACC_DIST_7" 166 "ACC_DIST_6" 133 "ACC_DIST_5" 100 "ACC_DIST_4" 66 "ACC_DIST_3" 33 "ACC_DIST_2" 0 "ACC_DIST_1" ;
|
||||
VAL_ 568 TurnIndLvr_Stat 3 "SNA" 2 "RIGHT" 1 "LEFT" 0 "IDLE" ;
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
#include "opendbc/safety/safety_declarations.h"
|
||||
|
||||
#define TESLA_COMMON_RX_CHECKS \
|
||||
{.msg = {{0x2b9, 2, 8, 25U, .max_counter = 7U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* DAS_control */ \
|
||||
{.msg = {{0x488, 2, 4, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* DAS_steeringControl */ \
|
||||
{.msg = {{0x257, 0, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* DI_speed (speed in kph) */ \
|
||||
{.msg = {{0x155, 0, 8, 50U, .max_counter = 15U}, { 0 }, { 0 }}}, /* ESP_B (2nd speed in kph) */ \
|
||||
{.msg = {{0x370, 0, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* EPAS3S_sysStatus (steering angle) */ \
|
||||
{.msg = {{0x118, 0, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* DI_systemStatus (gas pedal) */ \
|
||||
{.msg = {{0x39d, 0, 5, 25U, .max_counter = 15U}, { 0 }, { 0 }}}, /* IBST_status (brakes) */ \
|
||||
{.msg = {{0x286, 0, 8, 10U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* DI_state (acc state) */ \
|
||||
{.msg = {{0x311, 0, 7, 10U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* UI_warning (blinkers, buckle switch & doors) */ \
|
||||
|
||||
#define TESLA_VEHICLE_BUS_ADDR_CHECK \
|
||||
{.msg = {{0x3DF, 1, 8, 2U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* UI_status2 */ \
|
||||
|
||||
static bool tesla_longitudinal = false;
|
||||
static bool tesla_stock_aeb = false;
|
||||
|
||||
@@ -14,6 +28,10 @@ static bool tesla_stock_lkas_prev = false;
|
||||
static bool tesla_autopark = false;
|
||||
static bool tesla_autopark_prev = false;
|
||||
|
||||
// Detected VEHICLE bus
|
||||
extern bool tesla_has_vehicle_bus;
|
||||
bool tesla_has_vehicle_bus = false;
|
||||
|
||||
static uint8_t tesla_get_counter(const CANPacket_t *msg) {
|
||||
|
||||
uint8_t cnt = 0;
|
||||
@@ -166,6 +184,12 @@ static void tesla_rx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->bus == 1U) {
|
||||
if (msg->addr == 0x3DFU) {
|
||||
mads_button_press = (msg->data[3] == 3U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->bus == 2U) {
|
||||
// DAS_control
|
||||
if (msg->addr == 0x2b9U) {
|
||||
@@ -336,6 +360,10 @@ static safety_config tesla_init(uint16_t param) {
|
||||
tesla_longitudinal = GET_FLAG(param, TESLA_FLAG_LONGITUDINAL_CONTROL);
|
||||
#endif
|
||||
|
||||
const int TESLA_PARAM_SP_VEHICLE_BUS = 1;
|
||||
|
||||
tesla_has_vehicle_bus = GET_FLAG(current_safety_param_sp, TESLA_PARAM_SP_VEHICLE_BUS);
|
||||
|
||||
tesla_stock_aeb = false;
|
||||
tesla_stock_lkas = false;
|
||||
tesla_stock_lkas_prev = false;
|
||||
@@ -345,22 +373,25 @@ static safety_config tesla_init(uint16_t param) {
|
||||
tesla_autopark_prev = false;
|
||||
|
||||
static RxCheck tesla_model3_y_rx_checks[] = {
|
||||
{.msg = {{0x2b9, 2, 8, 25U, .max_counter = 7U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DAS_control
|
||||
{.msg = {{0x488, 2, 4, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DAS_steeringControl
|
||||
{.msg = {{0x257, 0, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DI_speed (speed in kph)
|
||||
{.msg = {{0x155, 0, 8, 50U, .max_counter = 15U}, { 0 }, { 0 }}}, // ESP_B (2nd speed in kph)
|
||||
{.msg = {{0x370, 0, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EPAS3S_sysStatus (steering angle)
|
||||
{.msg = {{0x118, 0, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DI_systemStatus (gas pedal)
|
||||
{.msg = {{0x39d, 0, 5, 25U, .max_counter = 15U}, { 0 }, { 0 }}}, // IBST_status (brakes)
|
||||
{.msg = {{0x286, 0, 8, 10U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DI_state (acc state)
|
||||
{.msg = {{0x311, 0, 7, 10U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // UI_warning (blinkers, buckle switch & doors)
|
||||
TESLA_COMMON_RX_CHECKS
|
||||
};
|
||||
|
||||
static RxCheck tesla_model3_y_vehicle_bus_rx_checks[] = {
|
||||
TESLA_COMMON_RX_CHECKS
|
||||
TESLA_VEHICLE_BUS_ADDR_CHECK
|
||||
};
|
||||
|
||||
safety_config ret;
|
||||
if (tesla_longitudinal) {
|
||||
ret = BUILD_SAFETY_CFG(tesla_model3_y_rx_checks, TESLA_M3_Y_LONG_TX_MSGS);
|
||||
SET_TX_MSGS(TESLA_M3_Y_LONG_TX_MSGS, ret);
|
||||
} else {
|
||||
ret = BUILD_SAFETY_CFG(tesla_model3_y_rx_checks, TESLA_M3_Y_TX_MSGS);
|
||||
SET_TX_MSGS(TESLA_M3_Y_TX_MSGS, ret);
|
||||
}
|
||||
|
||||
if (tesla_has_vehicle_bus) {
|
||||
SET_RX_CHECKS(tesla_model3_y_vehicle_bus_rx_checks, ret);
|
||||
} else {
|
||||
SET_RX_CHECKS(tesla_model3_y_rx_checks, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import unittest
|
||||
import numpy as np
|
||||
|
||||
from opendbc.car.lateral import get_max_angle_delta_vm, get_max_angle_vm
|
||||
from opendbc.car.tesla.values import CarControllerParams, TeslaSafetyFlags
|
||||
from opendbc.car.tesla.values import CarControllerParams, TeslaSafetyFlags, CANBUS
|
||||
from opendbc.car.tesla.carcontroller import get_safety_CP
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
@@ -13,6 +13,8 @@ from opendbc.safety.tests.libsafety import libsafety_py
|
||||
import opendbc.safety.tests.common as common
|
||||
from opendbc.safety.tests.common import CANPackerPanda, MAX_SPEED_DELTA, MAX_WRONG_COUNTERS, away_round, round_speed
|
||||
|
||||
from opendbc.sunnypilot.car.tesla.values import TeslaSafetyFlagsSP
|
||||
|
||||
MSG_DAS_steeringControl = 0x488
|
||||
MSG_APS_eacMonitor = 0x27d
|
||||
MSG_DAS_Control = 0x2b9
|
||||
@@ -448,5 +450,22 @@ class TestTeslaLongitudinalSafety(TestTeslaSafetyBase):
|
||||
self.assertFalse(self._tx(self._long_control_msg(set_speed=0, accel_limits=(-0.1, -0.1))))
|
||||
|
||||
|
||||
class TestTeslaVehicleBusSafety(TestTeslaSafetyBase):
|
||||
|
||||
LONGITUDINAL = False
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.safety = libsafety_py.libsafety
|
||||
self.packer_adas = CANPackerPanda("tesla_model3_vehicle")
|
||||
self.safety.set_current_safety_param_sp(TeslaSafetyFlagsSP.HAS_VEHICLE_BUS)
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.tesla, 0)
|
||||
self.safety.init_tests()
|
||||
|
||||
def _lkas_button_msg(self, enabled):
|
||||
values = {"UI_activeTouchPoints": 3 if enabled else 0}
|
||||
return self.packer_adas.make_can_msg_panda("UI_status2", CANBUS.vehicle, values)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
41
opendbc/sunnypilot/car/tesla/carstate_ext.py
Normal file
41
opendbc/sunnypilot/car/tesla/carstate_ext.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from enum import StrEnum
|
||||
|
||||
from opendbc.car import Bus, create_button_events, structs
|
||||
from opendbc.can.parser import CANParser
|
||||
from opendbc.car.tesla.values import DBC, CANBUS
|
||||
from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarStateExt:
|
||||
def __init__(self, CP: structs.CarParams, CP_SP: structs.CarParamsSP):
|
||||
self.CP = CP
|
||||
self.CP_SP = CP_SP
|
||||
|
||||
self.infotainment_3_finger_press = 0
|
||||
|
||||
def update(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
|
||||
if self.CP_SP.flags & TeslaFlagsSP.HAS_VEHICLE_BUS:
|
||||
cp_adas = can_parsers[Bus.adas]
|
||||
|
||||
prev_infotainment_3_finger_press = self.infotainment_3_finger_press
|
||||
self.infotainment_3_finger_press = int(cp_adas.vl["UI_status2"]["UI_activeTouchPoints"])
|
||||
|
||||
ret.buttonEvents = [*create_button_events(self.infotainment_3_finger_press, prev_infotainment_3_finger_press,
|
||||
{3: ButtonType.lkas})]
|
||||
|
||||
@staticmethod
|
||||
def get_parser(CP: structs.CarParams, CP_SP: structs.CarParamsSP) -> dict[StrEnum, CANParser]:
|
||||
messages = {}
|
||||
|
||||
if CP_SP.flags & TeslaFlagsSP.HAS_VEHICLE_BUS:
|
||||
messages[Bus.adas] = CANParser(DBC[CP.carFingerprint][Bus.adas], [], CANBUS.vehicle)
|
||||
|
||||
return messages
|
||||
15
opendbc/sunnypilot/car/tesla/values.py
Normal file
15
opendbc/sunnypilot/car/tesla/values.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from enum import IntFlag
|
||||
|
||||
|
||||
class TeslaFlagsSP(IntFlag):
|
||||
HAS_VEHICLE_BUS = 1 # 3-finger infotainment press signal is present on the VEHICLE bus with the deprecated Tesla harness installed
|
||||
|
||||
|
||||
class TeslaSafetyFlagsSP:
|
||||
HAS_VEHICLE_BUS = 1
|
||||
Reference in New Issue
Block a user