test: sync opendbc safety models (stage 2b)

This commit is contained in:
1okko
2026-10-20 21:36:04 +08:00
parent da7fde3900
commit 1cdef84df8
64 changed files with 2228 additions and 2532 deletions
+13 -10
View File
@@ -469,7 +469,6 @@ struct CarParams {
notCar @66 :Bool; # flag for non-car robotics platforms
pcmCruise @3 :Bool; # is openpilot's state tied to the PCM's cruise state?
enableBsm @56 :Bool; # blind spot monitoring
flags @64 :UInt32; # flags for car specific quirks
alphaLongitudinalAvailable @71 :Bool;
@@ -484,20 +483,17 @@ struct CarParams {
autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically
# things about the car in the manual
mass @17 :Float32; # [kg] curb weight: all fluids no cargo
wheelbase @18 :Float32; # [m] distance from rear axle to front axle
centerToFront @19 :Float32; # [m] distance from center of mass to front axle
steerRatio @20 :Float32; # [] ratio of steering wheel angle to front wheel angle
steerRatioRear @21 :Float32; # [] ratio of steering wheel angle to rear wheel angle (usually 0)
# things we can derive
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
# mass-normalized vehicle dynamics parameters
rotationalInertiaPerMass @22 :Float32; # [m^2] rotational inertia per unit mass
tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear]
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
tireStiffnessFrontPerMass @23 :Float32; # [N/(rad*kg)] front tire stiffness per unit mass
tireStiffnessRearPerMass @24 :Float32; # [N/(rad*kg)] rear tire stiffness per unit mass
longitudinalTuning @25 :LongitudinalPIDTuning;
lateralParams @48 :LateralParams;
lateralTuning :union {
pid @26 :LateralPIDTuning;
indiDEPRECATED @27 :LateralINDITuningDEPRECATED;
@@ -648,8 +644,11 @@ struct CarParams {
fcaGiorgio @32;
rivian @33;
volkswagenMeb @34;
mg @35;
gwm @36;
byd @35;
volvo @36;
bmw @37;
mg @38;
gwm @39;
}
enum SteerControlType {
@@ -724,6 +723,9 @@ struct CarParams {
}
deprecated :group {
mass @17 :Float32;
steerRatioRear @21 :Float32;
lateralParams @48 :LateralParams;
enableGasInterceptor @2 :Bool;
enableCamera @4 :Bool;
enableApgs @6 :Bool;
@@ -749,6 +751,7 @@ struct CarParams {
stoppingControl @31 :Bool; # Does the car allow full control even at lows speeds when stopping
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
enableDsu @5 :Bool; # driving support unit
enableBsm @56 :Bool; # blind spot monitoring
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
startAccel @32 :Float32; # Required acceleration to get car moving
startingState @70 :Bool; # Does this car make use of special starting state
+10 -4
View File
@@ -34,8 +34,11 @@
#define SAFETY_PSA 31U
#define SAFETY_RIVIAN 33U
#define SAFETY_VOLKSWAGEN_MEB 34U
#define SAFETY_MG 35U
#define SAFETY_GWM 36U
#define SAFETY_BYD 35U
#define SAFETY_VOLVO 36U
#define SAFETY_BMW 37U
#define SAFETY_MG 38U
#define SAFETY_GWM 39U
#define GET_BIT(msg, b) ((bool)!!(((msg)->data[((b) / 8U)] >> ((b) % 8U)) & 0x1U))
#define GET_FLAG(value, mask) (((value) & (mask)) == (mask))
@@ -60,7 +63,8 @@
#define UPDATE_VEHICLE_SPEED(val_ms) (update_sample(&vehicle_speed, ROUND((val_ms) * VEHICLE_SPEED_FACTOR)))
#define UPDATE_VEHICLE_SPEED_2(val_ms) (update_sample(&vehicle_speed_2, ROUND((val_ms) * VEHICLE_SPEED_FACTOR)))
uint32_t GET_BYTES(const CANPacket_t *msg, int start, int len);
uint32_t GET_BYTES_LE(const CANPacket_t *msg, int start, int len);
uint64_t GET_BYTES_64_LE(const CANPacket_t *msg, int start, int len);
extern const int MAX_WRONG_COUNTERS;
#define MAX_ADDR_CHECK_MSGS 3U
@@ -256,7 +260,7 @@ bool longitudinal_interceptor_checks(const CANPacket_t *msg); // gas intercepto
void pcm_cruise_check(bool cruise_engaged);
void speed_mismatch_check(const float speed_2);
void safety_tick(const safety_config *safety_config);
void safety_tick(void);
// This can be set by the safety hooks
extern bool controls_allowed;
@@ -371,5 +375,7 @@ extern const safety_hooks volkswagen_meb_hooks;
extern const safety_hooks volkswagen_pq_hooks;
extern const safety_hooks rivian_hooks;
extern const safety_hooks psa_hooks;
extern const safety_hooks byd_hooks;
extern const safety_hooks mg_hooks;
extern const safety_hooks gwm_hooks;
#define GET_BYTES(msg, start, len) GET_BYTES_LE(msg, start, len)
+32
View File
@@ -1,3 +1,5 @@
#pragma once
#include "opendbc/safety/declarations.h"
// cppcheck-suppress-macro misra-c2012-1.2; allow __typeof__ extension
@@ -34,6 +36,36 @@
#define SAFETY_UNUSED(x) ((void)(x))
// Update an MSB-first CRC8 with one byte; callers choose the initial value and final XOR.
static uint8_t crc8_update(uint8_t initial_crc, uint8_t data, uint8_t poly) {
uint8_t crc = initial_crc ^ data;
for (int i = 0; i < 8; i++) {
if ((crc & 0x80U) != 0U) {
crc = (crc << 1) ^ poly;
} else {
crc <<= 1;
}
}
return crc;
}
// Compare address and bus as one key: CANPacket_t has a 29-bit address and 3-bit bus.
static bool msg_matches_addr_bus(const CANPacket_t *msg, uint32_t addr, uint32_t bus) {
uint32_t actual = ((uint32_t)msg->addr << 3) | (uint32_t)msg->bus;
uint32_t expected = (addr << 3) | bus;
return actual == expected;
}
// Compare address, bus, and decoded byte length as one key.
static bool msg_matches_addr_bus_len(const CANPacket_t *msg, uint32_t addr, uint32_t bus, uint32_t len) {
uint64_t actual = ((uint64_t)msg->addr << 10) | ((uint64_t)msg->bus << 7) | (uint64_t)dlc_to_len[msg->data_len_code];
uint64_t expected = ((uint64_t)addr << 10) | ((uint64_t)bus << 7) | (uint64_t)len;
return actual == expected;
}
#define MSG_MATCHES_SELECT(_msg, _addr, _bus, _len, NAME, ...) NAME
#define msg_matches(...) MSG_MATCHES_SELECT(__VA_ARGS__, msg_matches_addr_bus_len, msg_matches_addr_bus)(__VA_ARGS__)
// compute the time elapsed (in microseconds) from 2 counter samples
// case where ts < ts_last is ok: overflow is properly re-casted into uint32_t
static inline uint32_t safety_get_ts_elapsed(uint32_t ts, uint32_t ts_last) {
+48 -6
View File
@@ -4,6 +4,7 @@
#include <stdint.h>
#include "opendbc/safety/can.h"
#include "opendbc/safety/helpers.h"
bool ignition_can = false;
uint32_t ignition_can_cnt = 0U;
@@ -77,10 +78,51 @@ void ignition_can_hook(const CANPacket_t *msg) {
}
}
// TODO: this is too loose, Teslas have 0x222
// body v2 exception
// if (((msg->bus == 0U) || (msg->bus == 2U)) && (msg->addr == 0x222U)) {
// ignition_can = true;
// ignition_can_cnt = 0U;
// }
// Rivian R1S/T GEN1 exception
if (msg_matches(msg, 0x152U, 0U, 8U)) {
// 0x152 overlaps with Subaru pre-global which has this bit as the high beam
int counter = msg->data[1] & 0xFU; // max is only 14
static int prev_counter_rivian = -1;
if ((counter == ((prev_counter_rivian + 1) % 15)) && (prev_counter_rivian != -1)) {
// VDM_OutputSignals->VDM_EpasPowerMode
ignition_can = ((msg->data[7] >> 4U) & 0x3U) == 1U; // VDM_EpasPowerMode_Drive_On=1
ignition_can_cnt = 0U;
}
prev_counter_rivian = counter;
}
// Tesla Model 3/Y exception
if (msg_matches(msg, 0x221U, 0U, 8U)) {
// 0x221 overlaps with Rivian which has random data on byte 0
int counter = msg->data[6] >> 4;
static int prev_counter_tesla = -1;
if ((counter == ((prev_counter_tesla + 1) % 16)) && (prev_counter_tesla != -1)) {
// VCFRONT_LVPowerState->VCFRONT_vehiclePowerState
int power_state = (msg->data[0] >> 5U) & 0x3U;
ignition_can = power_state == 0x3; // VEHICLE_POWER_STATE_DRIVE=3
ignition_can_cnt = 0U;
}
prev_counter_tesla = counter;
}
// Mazda exception
if (msg_matches(msg, 0x9EU, 0U, 8U)) {
ignition_can = (msg->data[0] >> 5) == 0x6U;
ignition_can_cnt = 0U;
}
// Volkswagen MEB exception
if (msg_matches(msg, 0x3C0U, 0U, 4U)) {
int counter = msg->data[1] & 0xFU;
static int prev_counter_vw_meb = -1;
if ((counter == ((prev_counter_vw_meb + 1) % 16)) && (prev_counter_vw_meb != -1)) {
// Klemmen_Status_01->ZAS_Kl_15
ignition_can = ((msg->data[2] >> 1) & 1U) != 0U;
ignition_can_cnt = 0U;
}
prev_counter_vw_meb = counter;
}
}
+32 -7
View File
@@ -2,10 +2,28 @@
#include "opendbc/safety/declarations.h"
static void body_rx_hook(const CANPacket_t *msg) {
if (msg->addr == 0x201U) {
controls_allowed = true;
static uint8_t body_get_counter(const CANPacket_t *msg) {
return msg->data[6] & 0xFU;
}
static uint32_t body_get_checksum(const CANPacket_t *msg) {
return msg->data[7];
}
static uint32_t body_compute_checksum(const CANPacket_t *msg) {
uint8_t checksum = 0xFFU;
int len = GET_LEN(msg);
for (int i = len - 2; i >= 0; i--) {
checksum = crc8_update(checksum, msg->data[i], 0xD5U);
}
return checksum;
}
static void body_rx_hook(const CANPacket_t *msg) {
SAFETY_UNUSED(msg);
// controls allowed as soon as RX is valid
controls_allowed = true;
}
static bool body_tx_hook(const CANPacket_t *msg) {
@@ -17,7 +35,7 @@ static bool body_tx_hook(const CANPacket_t *msg) {
// Allow going into CAN flashing mode even if controls are not allowed
bool flash_msg = (msg->addr == 0x250U) && (GET_LEN(msg) == 8U);
if (!controls_allowed && (GET_BYTES(msg, 0, 4) == 0xdeadfaceU) && (GET_BYTES(msg, 4, 4) == 0x0ab00b1eU) && flash_msg) {
if (!controls_allowed && flash_msg && (GET_BYTES_64_LE(msg, 0, 8) == 0x0AB00B1EDEADFACEULL)) {
tx = true;
}
@@ -26,11 +44,15 @@ static bool body_tx_hook(const CANPacket_t *msg) {
static safety_config body_init(uint16_t param) {
static RxCheck body_rx_checks[] = {
{.msg = {{0x201, 0, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{0x201, 0, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
};
static const CanMsg BODY_TX_MSGS[] = {{0x250, 0, 8, .check_relay = false}, {0x250, 0, 6, .check_relay = false}, {0x251, 0, 5, .check_relay = false}, // body
{0x1, 0, 8, .check_relay = false}}; // CAN flasher
static const CanMsg BODY_TX_MSGS[] = {
{0x250, 0, 8, .check_relay = false},
{0x250, 0, 6, .check_relay = false},
{0x251, 0, 5, .check_relay = false},
{0x1, 0, 8, .check_relay = false}, // CAN flasher
};
SAFETY_UNUSED(param);
safety_config ret = BUILD_SAFETY_CFG(body_rx_checks, BODY_TX_MSGS);
@@ -42,4 +64,7 @@ const safety_hooks body_hooks = {
.init = body_init,
.rx = body_rx_hook,
.tx = body_tx_hook,
.get_counter = body_get_counter,
.get_checksum = body_get_checksum,
.compute_checksum = body_compute_checksum,
};
+119
View File
@@ -0,0 +1,119 @@
#pragma once
#include "opendbc/safety/declarations.h"
static uint8_t byd_get_counter(const CANPacket_t *msg) {
// Speed uses the high nibble; cruise status uses the low nibble.
return (msg->addr == 0x1F0U) ? (msg->data[6] >> 4) : (msg->data[6] & 0xFU);
}
static uint32_t byd_get_checksum(const CANPacket_t *msg) {
return msg->data[7];
}
static uint32_t byd_compute_checksum(const CANPacket_t *msg) {
uint8_t sum = 0;
for (int i = 0; i < 7; i++) {
sum += msg->data[i];
}
return 0xFFU - sum;
}
static void byd_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Steering angle: 0.1 deg/LSB, signed
if (msg->addr == 0x11FU) {
int angle_meas_new = to_signed((msg->data[1] << 8) | msg->data[0], 16); // STEER_ANGLE_2
update_sample(&angle_meas, angle_meas_new);
}
// Vehicle speed: 0.1 kph/LSB
if (msg->addr == 0x1F0U) {
int speed = (msg->data[1] << 8) | msg->data[0]; // WHEELSPEED_CLEAN
vehicle_moving = speed > 0;
UPDATE_VEHICLE_SPEED(speed * 0.1 * KPH_TO_MS);
}
// Gas and brake pressed
if (msg->addr == 0x242U) {
brake_pressed = (msg->data[4] >> 5) & 0x1U; // BRAKE_PRESSED
gas_pressed = (msg->data[3] & 0x7FU) > 0U; // RAW_THROTTLE
}
}
if (msg->bus == 2U) {
// Cruise state
if (msg->addr == 0x32DU) {
// ACC_STATE: 0=OFF, 2=ACC_ON, 3=ACC_ACTIVE, 5=FORCE_ACCEL, 7=ERROR
uint8_t acc_state = (msg->data[2] >> 3) & 0x7U;
bool acc_on = (acc_state == 3U) || (acc_state == 5U);
pcm_cruise_check(acc_on);
}
}
}
static bool byd_tx_hook(const CANPacket_t *msg) {
const AngleSteeringLimits BYD_STEERING_LIMITS = {
.max_angle = 3900, // 390 deg
.angle_deg_to_can = 10,
.frequency = 50U,
};
// NOTE: based off BYD_ATTO_3 to match openpilot
const AngleSteeringParams BYD_STEERING_PARAMS = {
.slip_factor = -0.0006166479109059387, // calc_slip_factor(VM)
.steer_ratio = 14.8,
.wheelbase = 2.72,
};
bool tx = true;
// Steering control: 0.1 deg/LSB, signed
if (msg->addr == 0x1E2U) {
int desired_angle = to_signed((msg->data[4] << 8) | msg->data[3], 16); // STEER_ANGLE
bool steer_req = ((msg->data[2] >> 5) & 0x1U) != 0U; // STEER_REQ
if (steer_angle_cmd_checks_vm(desired_angle, steer_req, BYD_STEERING_LIMITS, BYD_STEERING_PARAMS)) {
tx = false;
}
}
// Only allow cancel (ACC_ON_BTN) while stock cruise is engaged, or button release.
if (msg->addr == 0x3B0U) {
bool other_buttons = ((msg->data[0] & 0x58U) != 0U) || // SET, RES, LKAS_ON
((msg->data[1] & 0x80U) != 0U) || // DEC_DISTANCE
((msg->data[2] & 0x1U) != 0U); // INC_DISTANCE
bool cancel = (msg->data[2] & 0x8U) != 0U; // ACC_ON_BTN
tx = !other_buttons && (!cancel || cruise_engaged_prev);
}
return tx;
}
static safety_config byd_init(uint16_t param) {
SAFETY_UNUSED(param);
static const CanMsg BYD_TX_MSGS[] = {
{0x1E2, 0, 8, .check_relay = true}, // STEERING_MODULE_ADAS (lateral steering command)
{0x316, 0, 8, .check_relay = true}, // LKAS_HUD_ADAS (dash HUD)
{0x3B0, 0, 8, .check_relay = false}, // PCM_BUTTONS (cruise cancel button spoof)
};
static RxCheck byd_rx_checks[] = {
{.msg = {{0x11F, 0, 5, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // STEER_MODULE_2 (steering angle)
{.msg = {{0x1F0, 0, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // WHEELSPEED_CLEAN (vehicle speed)
{.msg = {{0x242, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DRIVE_STATE (gas and brake pressed)
{.msg = {{0x32D, 2, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // ACC_HUD_ADAS (cruise state)
};
return BUILD_SAFETY_CFG(byd_rx_checks, BYD_TX_MSGS);
}
const safety_hooks byd_hooks = {
.init = byd_init,
.rx = byd_rx_hook,
.tx = byd_tx_hook,
.get_counter = byd_get_counter,
.get_checksum = byd_get_checksum,
.compute_checksum = byd_compute_checksum,
};
+7 -8
View File
@@ -52,21 +52,20 @@ static ChryslerPlatform chrysler_platform;
#define CHRYSLER_ADDR(name) ((uint32_t)((chrysler_platform == CHRYSLER_RAM_DT) ? CHRYSLER_RAM_DT_##name : \
((chrysler_platform == CHRYSLER_RAM_HD) ? CHRYSLER_RAM_HD_##name : CHRYSLER_##name)))
static uint8_t chrysler_get_counter(const CANPacket_t *msg) {
return (uint8_t)(msg->data[6] >> 4);
}
static void chrysler_rx_hook(const CANPacket_t *msg) {
// Measured EPS torque
if ((msg->bus == 0U) && (msg->addr == CHRYSLER_ADDR(EPS_2))) {
if (msg_matches(msg, CHRYSLER_ADDR(EPS_2), 0U)) {
int torque_meas_new = ((msg->data[4] & 0x7U) << 8) + msg->data[5] - 1024U;
update_sample(&torque_meas, torque_meas_new);
}
// enter controls on rising edge of ACC, exit controls on ACC off
const unsigned int das_3_bus = (chrysler_platform == CHRYSLER_PACIFICA) ? 0U : 2U;
if ((msg->bus == das_3_bus) && (msg->addr == CHRYSLER_ADDR(DAS_3))) {
if (msg_matches(msg, CHRYSLER_ADDR(DAS_3), das_3_bus)) {
bool cruise_engaged = GET_BIT(msg, 21U);
pcm_cruise_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 20U);
@@ -74,22 +73,22 @@ static void chrysler_rx_hook(const CANPacket_t *msg) {
// TODO: use the same message for both
// update vehicle moving
if ((chrysler_platform != CHRYSLER_PACIFICA) && (msg->bus == 0U) && (msg->addr == CHRYSLER_ADDR(ESP_8))) {
if ((chrysler_platform != CHRYSLER_PACIFICA) && msg_matches(msg, CHRYSLER_ADDR(ESP_8), 0U)) {
vehicle_moving = ((msg->data[4] << 8) + msg->data[5]) != 0U;
}
if ((chrysler_platform == CHRYSLER_PACIFICA) && (msg->bus == 0U) && (msg->addr == 514U)) {
if ((chrysler_platform == CHRYSLER_PACIFICA) && msg_matches(msg, 514U, 0U)) {
int speed_l = (msg->data[0] << 4) + (msg->data[1] >> 4);
int speed_r = (msg->data[2] << 4) + (msg->data[3] >> 4);
vehicle_moving = (speed_l != 0) || (speed_r != 0);
vehicle_moving = (speed_l | speed_r) != 0;
}
// exit controls on rising edge of gas press
if ((msg->bus == 0U) && (msg->addr == CHRYSLER_ADDR(ECM_5))) {
if (msg_matches(msg, CHRYSLER_ADDR(ECM_5), 0U)) {
gas_pressed = msg->data[0U] != 0U;
}
// exit controls on rising edge of brake press
if ((msg->bus == 0U) && (msg->addr == CHRYSLER_ADDR(ESP_1))) {
if (msg_matches(msg, CHRYSLER_ADDR(ESP_1), 0U)) {
brake_pressed = ((msg->data[0U] & 0xFU) >> 2U) == 1U;
}
@@ -6,34 +6,10 @@ static uint32_t chrysler_get_checksum(const CANPacket_t *msg) {
}
static uint32_t chrysler_compute_checksum(const CANPacket_t *msg) {
// TODO: clean this up
// http://illmatics.com/Remote%20Car%20Hacking.pdf
uint8_t checksum = 0xFFU;
int len = GET_LEN(msg);
for (int j = 0; j < (len - 1); j++) {
uint8_t shift = 0x80U;
uint8_t curr = (uint8_t)msg->data[j];
for (int i=0; i<8; i++) {
uint8_t bit_sum = curr & shift;
uint8_t temp_chk = checksum & 0x80U;
if (bit_sum != 0U) {
bit_sum = 0x1C;
if (temp_chk != 0U) {
bit_sum = 1;
}
checksum = checksum << 1;
temp_chk = checksum | 1U;
bit_sum ^= temp_chk;
} else {
if (temp_chk != 0U) {
bit_sum = 0x1D;
}
checksum = checksum << 1;
bit_sum ^= checksum;
}
checksum = bit_sum;
shift = shift >> 1;
}
checksum = crc8_update(checksum, msg->data[j], 0x1DU);
}
return (uint8_t)(~checksum);
}
@@ -1,6 +1,5 @@
#include "opendbc/safety/modes/chrysler_common.h"
static safety_config chrysler_cusw_init(uint16_t param) {
SAFETY_UNUSED(param);
@@ -22,33 +21,31 @@ static safety_config chrysler_cusw_init(uint16_t param) {
}
static void chrysler_cusw_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
if (msg->addr == 0x1ECU) {
// Signal: EPS_STATUS.TORQUE_MOTOR
int torque_meas_new = ((msg->data[3] & 0xFU) << 8) + msg->data[4] - 2048U;
update_sample(&torque_meas, torque_meas_new);
}
if (msg_matches(msg, 0x1ECU, 0U)) {
// Signal: EPS_STATUS.TORQUE_MOTOR
int torque_meas_new = ((msg->data[3] & 0xFU) << 8) + msg->data[4] - 2048U;
update_sample(&torque_meas, torque_meas_new);
}
if (msg->addr == 0x2ECU) {
// Signal: ACC_CONTROL.ACC_ACTIVE
bool cruise_engaged = GET_BIT(msg, 7U);
pcm_cruise_check(cruise_engaged);
}
if (msg_matches(msg, 0x2ECU, 0U)) {
// Signal: ACC_CONTROL.ACC_ACTIVE
bool cruise_engaged = GET_BIT(msg, 7U);
pcm_cruise_check(cruise_engaged);
}
if (msg->addr == 0x1E4U) {
// Signal: BRAKE_1.VEHICLE_SPEED
vehicle_moving = (((msg->data[4] & 0x7U) << 8) + msg->data[5]) != 0U;
}
if (msg_matches(msg, 0x1E4U, 0U)) {
// Signal: BRAKE_1.VEHICLE_SPEED
vehicle_moving = (((msg->data[4] & 0x7U) << 8) + msg->data[5]) != 0U;
}
if (msg->addr == 0x1FEU) {
// Signal: ACCEL_GAS.GAS_HUMAN
gas_pressed = msg->data[1] != 0U;
}
if (msg_matches(msg, 0x1FEU, 0U)) {
// Signal: ACCEL_GAS.GAS_HUMAN
gas_pressed = msg->data[1] != 0U;
}
if (msg->addr == 0x1E8U) {
// Signal: BRAKE_3.DRIVER_BRAKE_SWITCH
brake_pressed = GET_BIT(msg, 18U);
}
if (msg_matches(msg, 0x1E8U, 0U)) {
// Signal: BRAKE_3.DRIVER_BRAKE_SWITCH
brake_pressed = GET_BIT(msg, 18U);
}
}
+2 -3
View File
@@ -10,10 +10,9 @@ void default_rx_hook(const CANPacket_t *msg) {
// GCOV_EXCL_STOP
// *** no output safety mode ***
static safety_config nooutput_init(uint16_t param) {
SAFETY_UNUSED(param);
return (safety_config){NULL, 0, NULL, 0, true}; // NOLINT(readability/braces)
return (safety_config){NULL, 0, NULL, 0, true}; // NOLINT(readability/braces)
}
// GCOV_EXCL_START
@@ -36,7 +35,7 @@ static safety_config alloutput_init(uint16_t param) {
const uint16_t ALLOUTPUT_PARAM_PASSTHROUGH = 1;
controls_allowed = true;
bool alloutput_passthrough = GET_FLAG(param, ALLOUTPUT_PARAM_PASSTHROUGH);
return (safety_config){NULL, 0, NULL, 0, !alloutput_passthrough}; // NOLINT(readability/braces)
return (safety_config){NULL, 0, NULL, 0, !alloutput_passthrough}; // NOLINT(readability/braces)
}
static bool alloutput_tx_hook(const CANPacket_t *msg) {
@@ -29,6 +29,7 @@ static bool elm327_tx_hook(const CANPacket_t *msg) {
tx = false;
}
}
return tx;
}
+57 -58
View File
@@ -26,10 +26,10 @@ static uint8_t ford_get_counter(const CANPacket_t *msg) {
if (msg->addr == FORD_BrakeSysFeatures) {
// Signal: VehVActlBrk_No_Cnt
cnt = (msg->data[2] >> 2) & 0xFU;
} else if (msg->addr == FORD_Yaw_Data_FD1) {
}
if (msg->addr == FORD_Yaw_Data_FD1) {
// Signal: VehRollYaw_No_Cnt
cnt = msg->data[5];
} else {
}
return cnt;
}
@@ -39,10 +39,10 @@ static uint32_t ford_get_checksum(const CANPacket_t *msg) {
if (msg->addr == FORD_BrakeSysFeatures) {
// Signal: VehVActlBrk_No_Cs
chksum = msg->data[3];
} else if (msg->addr == FORD_Yaw_Data_FD1) {
}
if (msg->addr == FORD_Yaw_Data_FD1) {
// Signal: VehRollYawW_No_Cs
chksum = msg->data[4];
} else {
}
return chksum;
}
@@ -54,14 +54,14 @@ static uint32_t ford_compute_checksum(const CANPacket_t *msg) {
chksum += msg->data[2] >> 6; // VehVActlBrk_D_Qf
chksum += (msg->data[2] >> 2) & 0xFU; // VehVActlBrk_No_Cnt
chksum = 0xFFU - chksum;
} else if (msg->addr == FORD_Yaw_Data_FD1) {
}
if (msg->addr == FORD_Yaw_Data_FD1) {
chksum += msg->data[0] + msg->data[1]; // VehRol_W_Actl
chksum += msg->data[2] + msg->data[3]; // VehYaw_W_Actl
chksum += msg->data[5]; // VehRollYaw_No_Cnt
chksum += msg->data[6] >> 6; // VehRolWActl_D_Qf
chksum += (msg->data[6] >> 4) & 0x3U; // VehYawWActl_D_Qf
chksum = 0xFFU - chksum;
} else {
}
return chksum;
}
@@ -70,11 +70,12 @@ static bool ford_get_quality_flag_valid(const CANPacket_t *msg) {
bool valid = false;
if (msg->addr == FORD_BrakeSysFeatures) {
valid = (msg->data[2] >> 6) == 0x3U; // VehVActlBrk_D_Qf
} else if (msg->addr == FORD_EngVehicleSpThrottle2) {
}
if (msg->addr == FORD_EngVehicleSpThrottle2) {
valid = ((msg->data[4] >> 5) & 0x3U) == 0x3U; // VehVActlEng_D_Qf
} else if (msg->addr == FORD_Yaw_Data_FD1) {
}
if (msg->addr == FORD_Yaw_Data_FD1) {
valid = ((msg->data[6] >> 4) & 0x3U) == 0x3U; // VehYawWActl_D_Qf
} else {
}
return valid;
}
@@ -96,60 +97,58 @@ static const CurvatureSteeringLimits FORD_STEERING_LIMITS = {
};
static void ford_rx_hook(const CANPacket_t *msg) {
if (msg->bus == FORD_MAIN_BUS) {
// Update in motion state from standstill signal
if (msg->addr == FORD_DesiredTorqBrk) {
// Signal: VehStop_D_Stat
vehicle_moving = ((msg->data[3] >> 3) & 0x3U) != 1U;
}
// Update in motion state from standstill signal
if (msg_matches(msg, FORD_DesiredTorqBrk, FORD_MAIN_BUS)) {
// Signal: VehStop_D_Stat
vehicle_moving = ((msg->data[3] >> 3) & 0x3U) != 1U;
}
// Update vehicle speed
if (msg->addr == FORD_BrakeSysFeatures) {
// Signal: Veh_V_ActlBrk
UPDATE_VEHICLE_SPEED(((msg->data[0] << 8) | msg->data[1]) * 0.01 * KPH_TO_MS);
}
// Update vehicle speed
if (msg_matches(msg, FORD_BrakeSysFeatures, FORD_MAIN_BUS)) {
// Signal: Veh_V_ActlBrk
UPDATE_VEHICLE_SPEED(((msg->data[0] << 8) | msg->data[1]) * 0.01 * KPH_TO_MS);
}
// Check vehicle speed against a second source
if (msg->addr == FORD_EngVehicleSpThrottle2) {
// Disable controls if speeds from ABS and PCM ECUs are too far apart.
// Signal: Veh_V_ActlEng
float filtered_pcm_speed = ((msg->data[6] << 8) | msg->data[7]) * 0.01 * KPH_TO_MS;
UPDATE_VEHICLE_SPEED_2(filtered_pcm_speed);
}
// Check vehicle speed against a second source
if (msg_matches(msg, FORD_EngVehicleSpThrottle2, FORD_MAIN_BUS)) {
// Disable controls if speeds from ABS and PCM ECUs are too far apart.
// Signal: Veh_V_ActlEng
float filtered_pcm_speed = ((msg->data[6] << 8) | msg->data[7]) * 0.01 * KPH_TO_MS;
UPDATE_VEHICLE_SPEED_2(filtered_pcm_speed);
}
// Update vehicle yaw rate
if (msg->addr == FORD_Yaw_Data_FD1) {
// FIXME: safety can receive yaw before new vehicle speed, it should recompute meas on either received
// Signal: VehYaw_W_Actl
// TODO: we should use the speed which results in the closest angle measurement to the desired angle
float ford_yaw_rate = (((msg->data[2] << 8U) | msg->data[3]) * 0.0002) - 6.5;
float current_curvature = ford_yaw_rate / SAFETY_MAX(vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR, 0.1);
// convert current curvature into units on CAN for comparison with desired curvature
update_sample(&curvature_state.meas, ROUND(current_curvature * FORD_STEERING_LIMITS.curvature_to_can));
}
// Update vehicle yaw rate
if (msg_matches(msg, FORD_Yaw_Data_FD1, FORD_MAIN_BUS)) {
// FIXME: safety can receive yaw before new vehicle speed, it should recompute meas on either received
// Signal: VehYaw_W_Actl
// TODO: we should use the speed which results in the closest angle measurement to the desired angle
float ford_yaw_rate = (((msg->data[2] << 8U) | msg->data[3]) * 0.0002) - 6.5;
float current_curvature = ford_yaw_rate / SAFETY_MAX(vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR, 0.1);
// convert current curvature into units on CAN for comparison with desired curvature
update_sample(&curvature_state.meas, ROUND(current_curvature * FORD_STEERING_LIMITS.curvature_to_can));
}
// Update gas pedal
if (msg->addr == FORD_EngVehicleSpThrottle) {
// Pedal position: (0.1 * val) in percent
// Signal: ApedPos_Pc_ActlArb
gas_pressed = (((msg->data[0] & 0x03U) << 8) | msg->data[1]) > 0U;
}
// Update gas pedal
if (msg_matches(msg, FORD_EngVehicleSpThrottle, FORD_MAIN_BUS)) {
// Pedal position: (0.1 * val) in percent
// Signal: ApedPos_Pc_ActlArb
gas_pressed = (((msg->data[0] & 0x03U) << 8) | msg->data[1]) > 0U;
}
// Update brake pedal and cruise state
if (msg->addr == FORD_EngBrakeData) {
// Signal: BpedDrvAppl_D_Actl
brake_pressed = ((msg->data[0] >> 4) & 0x3U) == 2U;
// Update brake pedal and cruise state
if (msg_matches(msg, FORD_EngBrakeData, FORD_MAIN_BUS)) {
// Signal: BpedDrvAppl_D_Actl
brake_pressed = ((msg->data[0] >> 4) & 0x3U) == 2U;
// Signal: CcStat_D_Actl
unsigned int cruise_state = msg->data[1] & 0x07U;
bool cruise_engaged = (cruise_state == 4U) || (cruise_state == 5U);
pcm_cruise_check(cruise_engaged);
acc_main_on = (cruise_state == 3U) || cruise_engaged;
}
// Signal: CcStat_D_Actl
unsigned int cruise_state = msg->data[1] & 0x07U;
bool cruise_engaged = (cruise_state == 4U) || (cruise_state == 5U);
pcm_cruise_check(cruise_engaged);
acc_main_on = (cruise_state == 3U) || cruise_engaged;
}
if (msg->addr == FORD_Steering_Data_FD1) {
mads_button_press = GET_BIT(msg, 40U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
if (msg_matches(msg, FORD_Steering_Data_FD1, FORD_MAIN_BUS)) {
mads_button_press = GET_BIT(msg, 40U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
}
@@ -182,7 +181,7 @@ static bool ford_tx_hook(const CANPacket_t *msg) {
bool cmbb_deny = (msg->data[4] >> 5) & 1U;
// Signal: AccBrkPrchg_B_Rq & AccBrkDecel_B_Rq
bool brake_actuation = ((msg->data[6] >> 6) & 1U) || ((msg->data[6] >> 7) & 1U);
bool brake_actuation = (msg->data[6] & 0xC0U) != 0U;
bool violation = false;
violation |= longitudinal_accel_checks(accel, FORD_LONG_LIMITS);
@@ -190,7 +189,7 @@ static bool ford_tx_hook(const CANPacket_t *msg) {
violation |= longitudinal_gas_checks(gas_pred, FORD_LONG_LIMITS);
// Safety check for stock AEB
violation |= cmbb_deny; // do not prevent stock AEB actuation
violation |= cmbb_deny; // do not prevent stock AEB actuation
violation |= !get_longitudinal_allowed() && brake_actuation;
+78 -65
View File
@@ -39,73 +39,71 @@ static bool gm_non_acc = false;
static void gm_rx_hook(const CANPacket_t *msg) {
const int GM_STANDSTILL_THRSLD = 10; // 0.311kph
if (msg->bus == 0U) {
if (msg->addr == 0x184U) {
int torque_driver_new = ((msg->data[6] & 0x7U) << 8) | msg->data[7];
torque_driver_new = to_signed(torque_driver_new, 11);
// update array of samples
update_sample(&torque_driver, torque_driver_new);
if (msg_matches(msg, 0x184U, 0U)) {
int torque_driver_new = ((msg->data[6] & 0x7U) << 8) | msg->data[7];
torque_driver_new = to_signed(torque_driver_new, 11);
// update array of samples
update_sample(&torque_driver, torque_driver_new);
}
// sample rear wheel speeds
if (msg_matches(msg, 0x34AU, 0U)) {
int left_rear_speed = (msg->data[0] << 8) | msg->data[1];
int right_rear_speed = (msg->data[2] << 8) | msg->data[3];
vehicle_moving = (left_rear_speed > GM_STANDSTILL_THRSLD) || (right_rear_speed > GM_STANDSTILL_THRSLD);
}
// ACC steering wheel buttons (GM_CAM is tied to the PCM)
if (msg_matches(msg, 0x1E1U, 0U) && !gm_pcm_cruise) {
int button = (msg->data[5] & 0x70U) >> 4;
// enter controls on falling edge of set or rising edge of resume (avoids fault)
bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET);
bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME);
if (set || res) {
controls_allowed = true;
}
// sample rear wheel speeds
if (msg->addr == 0x34AU) {
int left_rear_speed = (msg->data[0] << 8) | msg->data[1];
int right_rear_speed = (msg->data[2] << 8) | msg->data[3];
vehicle_moving = (left_rear_speed > GM_STANDSTILL_THRSLD) || (right_rear_speed > GM_STANDSTILL_THRSLD);
// exit controls on cancel press
if (button == GM_BTN_CANCEL) {
controls_allowed = false;
}
// ACC steering wheel buttons (GM_CAM is tied to the PCM)
if ((msg->addr == 0x1E1U) && !gm_pcm_cruise) {
int button = (msg->data[5] & 0x70U) >> 4;
cruise_button_prev = button;
}
// enter controls on falling edge of set or rising edge of resume (avoids fault)
bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET);
bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME);
if (set || res) {
controls_allowed = true;
}
// Reference for brake pressed signals:
// https://github.com/commaai/openpilot/blob/master/selfdrive/car/gm/carstate.py
if (msg_matches(msg, 0xBEU, 0U) && (gm_hw == GM_ASCM)) {
brake_pressed = msg->data[1] >= 8U;
}
// exit controls on cancel press
if (button == GM_BTN_CANCEL) {
controls_allowed = false;
}
if (msg_matches(msg, 0xC9U, 0U) && (gm_hw == GM_CAM)) {
brake_pressed = GET_BIT(msg, 40U);
}
cruise_button_prev = button;
}
if (msg_matches(msg, 0x1C4U, 0U)) {
gas_pressed = msg->data[5] != 0U;
// Reference for brake pressed signals:
// https://github.com/commaai/openpilot/blob/master/selfdrive/car/gm/carstate.py
if ((msg->addr == 0xBEU) && (gm_hw == GM_ASCM)) {
brake_pressed = msg->data[1] >= 8U;
}
if ((msg->addr == 0xC9U) && (gm_hw == GM_CAM)) {
brake_pressed = GET_BIT(msg, 40U);
}
if (msg->addr == 0x1C4U) {
gas_pressed = msg->data[5] != 0U;
// enter controls on rising edge of ACC, exit controls when ACC off
if (gm_pcm_cruise && !gm_non_acc) {
bool cruise_engaged = (msg->data[1] >> 5) != 0U;
pcm_cruise_check(cruise_engaged);
}
}
if (msg->addr == 0xBDU) {
regen_braking = (msg->data[0] >> 4) != 0U;
}
if (msg->addr == 0xC9U) {
acc_main_on = GET_BIT(msg, 29U);
}
if (msg->addr == 0x3D1U) {
bool cruise_engaged = GET_BIT(msg, 39U);
// enter controls on rising edge of ACC, exit controls when ACC off
if (gm_pcm_cruise && !gm_non_acc) {
bool cruise_engaged = (msg->data[1] >> 5) != 0U;
pcm_cruise_check(cruise_engaged);
}
}
if (msg_matches(msg, 0xBDU, 0U)) {
regen_braking = (msg->data[0] >> 4) != 0U;
}
if (msg_matches(msg, 0xC9U, 0U)) {
acc_main_on = GET_BIT(msg, 29U);
}
if (msg_matches(msg, 0x3D1U, 0U)) {
bool cruise_engaged = GET_BIT(msg, 39U);
pcm_cruise_check(cruise_engaged);
}
}
static bool gm_tx_hook(const CANPacket_t *msg) {
@@ -185,10 +183,18 @@ static safety_config gm_init(uint16_t param) {
.max_brake = 400,
};
static const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x409, 0, 7, .check_relay = false}, {0x40A, 0, 7, .check_relay = false}, {0x2CB, 0, 8, .check_relay = true}, {0x370, 0, 6, .check_relay = false}, // pt bus
{0xA1, 1, 7, .check_relay = false}, {0x306, 1, 8, .check_relay = false}, {0x308, 1, 7, .check_relay = false}, {0x310, 1, 2, .check_relay = false}, // obs bus
{0x315, 2, 5, .check_relay = false}}; // ch bus
static const CanMsg GM_ASCM_TX_MSGS[] = {
{0x180, 0, 4, .check_relay = true},
{0x409, 0, 7, .check_relay = false},
{0x40A, 0, 7, .check_relay = false},
{0x2CB, 0, 8, .check_relay = true},
{0x370, 0, 6, .check_relay = false},
{0xA1, 1, 7, .check_relay = false},
{0x306, 1, 8, .check_relay = false},
{0x308, 1, 7, .check_relay = false},
{0x310, 1, 2, .check_relay = false},
{0x315, 2, 5, .check_relay = false},
};
static const LongitudinalLimits GM_CAM_LONG_LIMITS = {
.max_gas = 1346 * GM_GAS_TO_CAN,
@@ -199,11 +205,15 @@ static safety_config gm_init(uint16_t param) {
#ifdef ALLOW_DEBUG
// block PSCMStatus (0x184); forwarded through openpilot to hide an alert from the camera
static const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x315, 0, 5, .check_relay = true}, {0x2CB, 0, 8, .check_relay = true}, {0x370, 0, 6, .check_relay = true}, // pt bus
{0x184, 2, 8, .check_relay = true}}; // camera bus
static const CanMsg GM_CAM_LONG_TX_MSGS[] = {
{0x180, 0, 4, .check_relay = true},
{0x315, 0, 5, .check_relay = true},
{0x2CB, 0, 8, .check_relay = true},
{0x370, 0, 6, .check_relay = true},
{0x184, 2, 8, .check_relay = true},
};
#endif
static RxCheck gm_rx_checks[] = {
GM_COMMON_RX_CHECKS
};
@@ -224,8 +234,11 @@ static safety_config gm_init(uint16_t param) {
GM_NON_ACC_ADDR_CHECK
};
static const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, // pt bus
{0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = true}}; // camera bus
static const CanMsg GM_CAM_TX_MSGS[] = {
{0x180, 0, 4, .check_relay = true},
{0x1E1, 2, 7, .check_relay = false},
{0x184, 2, 8, .check_relay = true},
};
if (GET_FLAG(param, GM_PARAM_HW_CAM)) {
gm_hw = GM_CAM;
+51 -22
View File
@@ -46,7 +46,6 @@ static bool honda_nidec_hybrid = false;
typedef enum {HONDA_NIDEC, HONDA_BOSCH} HondaHw;
static HondaHw honda_hw = HONDA_NIDEC;
static unsigned int honda_get_pt_bus(void) {
return ((honda_hw == HONDA_BOSCH) && !honda_bosch_radarless && !honda_bosch_canfd) ? 1U : 0U;
}
@@ -129,7 +128,7 @@ static void honda_rx_hook(const CANPacket_t *msg) {
// state machine to enter and exit controls for button enabling
// 0x1A6 for the ILX, 0x296 for the Civic Touring
if (((msg->addr == 0x1A6U) || (msg->addr == 0x296U)) && (msg->bus == pt_bus)) {
if (msg_matches(msg, 0x1A6U, pt_bus) || msg_matches(msg, 0x296U, pt_bus)) {
int button = (msg->data[0] & 0xE0U) >> 5;
int cruise_setting = (msg->data[(msg->addr == 0x296U) ? 0U : 5U] & 0x0CU) >> 2U;
@@ -194,7 +193,7 @@ static void honda_rx_hook(const CANPacket_t *msg) {
// disable stock Honda AEB in alternative experience
if (!(alternative_experience & ALT_EXP_DISABLE_STOCK_AEB)) {
if ((msg->bus == 2U) && (msg->addr == 0x1FAU)) {
if (msg_matches(msg, 0x1FAU, 2U)) {
bool honda_stock_aeb = GET_BIT(msg, 29U);
int honda_stock_brake = (msg->data[0] << 2) | (msg->data[1] >> 6);
@@ -216,7 +215,6 @@ static void honda_rx_hook(const CANPacket_t *msg) {
}
static bool honda_tx_hook(const CANPacket_t *msg) {
const LongitudinalLimits HONDA_BOSCH_LONG_LIMITS = {
.max_accel = 200, // accel is used for brakes
.min_accel = -350,
@@ -238,7 +236,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
unsigned int bus_buttons = (honda_bosch_radarless) ? 2U : bus_pt; // the camera controls ACC on radarless Bosch cars
// ACC_HUD: safety check (nidec w/o pedal)
if ((msg->addr == 0x30CU) && (msg->bus == bus_pt)) {
if (msg_matches(msg, 0x30CU, bus_pt)) {
int pcm_speed = (msg->data[0] << 8) | msg->data[1];
int pcm_gas = msg->data[2];
@@ -251,7 +249,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
}
// BRAKE: safety check (nidec)
if ((msg->addr == 0x1FAU) && (msg->bus == bus_pt)) {
if (msg_matches(msg, 0x1FAU, bus_pt)) {
honda_brake = (msg->data[0] << 2) + ((msg->data[1] >> 6) & 0x3U);
if (honda_nidec_hybrid) {
@@ -267,7 +265,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
}
// BRAKE/GAS: safety check (bosch)
if ((msg->addr == 0x1DFU) && (msg->bus == bus_pt)) {
if (msg_matches(msg, 0x1DFU, bus_pt)) {
int accel = (msg->data[3] << 3) | ((msg->data[4] >> 5) & 0x7U);
accel = to_signed(accel, 11);
@@ -283,7 +281,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
}
// ACCEL: safety check (radarless)
if ((msg->addr == 0x1C8U) && (msg->bus == bus_pt)) {
if (msg_matches(msg, 0x1C8U, bus_pt)) {
int accel = (msg->data[0] << 4) | (msg->data[1] >> 4);
accel = to_signed(accel, 12);
@@ -306,7 +304,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
// Bosch supplemental control check
if (msg->addr == 0xE5U) {
if ((GET_BYTES(msg, 0, 4) != 0x10800004U) || ((GET_BYTES(msg, 4, 4) & 0x00FFFFFFU) != 0x0U)) {
if ((GET_BYTES_64_LE(msg, 0, 8) & 0x00FFFFFFFFFFFFFFULL) != 0x0000000010800004ULL) {
tx = false;
}
}
@@ -314,7 +312,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
// FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW
// ensuring that only the cancel button press is sent (VAL 2) when controls are off.
// This avoids unintended engagements while still allowing resume spam
if ((msg->addr == 0x296U) && !controls_allowed && (msg->bus == bus_buttons)) {
if (msg_matches(msg, 0x296U, bus_buttons) && !controls_allowed) {
if (((msg->data[0] >> 5) & 0x7U) != 2U) {
tx = false;
}
@@ -322,7 +320,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
// Only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
if (msg->addr == 0x18DAB0F1U) {
if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
if (GET_BYTES_64_LE(msg, 0, 8) != 0x0000000000803E02ULL) {
tx = false;
}
}
@@ -415,21 +413,52 @@ static safety_config honda_nidec_init(uint16_t param) {
}
static safety_config honda_bosch_init(uint16_t param) {
static CanMsg HONDA_BOSCH_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0xE5, 0, 8, .check_relay = true}, {0x296, 1, 4, .check_relay = false},
{0x33D, 0, 5, .check_relay = true}, {0x33D, 0, 8, .check_relay = true}, {0x33DA, 0, 5, .check_relay = true}, {0x33DB, 0, 8, .check_relay = true}}; // Bosch
// Bosch
static CanMsg HONDA_BOSCH_TX_MSGS[] = {
{0xE4, 0, 5, .check_relay = true},
{0xE5, 0, 8, .check_relay = true},
{0x296, 1, 4, .check_relay = false},
{0x33D, 0, 5, .check_relay = true},
{0x33D, 0, 8, .check_relay = true},
{0x33DA, 0, 5, .check_relay = true},
{0x33DB, 0, 8, .check_relay = true},
};
static CanMsg HONDA_BOSCH_LONG_TX_MSGS[] = {{0xE4, 1, 5, .check_relay = true}, {0x1DF, 1, 8, .check_relay = true}, {0x1EF, 1, 8, .check_relay = false},
{0x1FA, 1, 8, .check_relay = false}, {0x30C, 1, 8, .check_relay = false}, {0x33D, 1, 5, .check_relay = true}, {0x33D, 1, 8, .check_relay = true},
{0x33DA, 1, 5, .check_relay = true}, {0x33DB, 1, 8, .check_relay = true}, {0x39F, 1, 8, .check_relay = false},
{0x18DAB0F1, 1, 8, .check_relay = false}}; // Bosch w/ gas and brakes
// Bosch w/ gas and brakes
static CanMsg HONDA_BOSCH_LONG_TX_MSGS[] = {
{0xE4, 1, 5, .check_relay = true},
{0x1DF, 1, 8, .check_relay = true},
{0x1EF, 1, 8, .check_relay = false},
{0x1FA, 1, 8, .check_relay = false},
{0x30C, 1, 8, .check_relay = false},
{0x33D, 1, 5, .check_relay = true},
{0x33D, 1, 8, .check_relay = true},
{0x33DA, 1, 5, .check_relay = true},
{0x33DB, 1, 8, .check_relay = true},
{0x39F, 1, 8, .check_relay = false},
{0x18DAB0F1, 1, 8, .check_relay = false},
};
static CanMsg HONDA_RADARLESS_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x296, 2, 4, .check_relay = false}, {0x33D, 0, 8, .check_relay = true}}; // Bosch radarless
// Bosch radarless
static CanMsg HONDA_RADARLESS_TX_MSGS[] = {
{0xE4, 0, 5, .check_relay = true},
{0x296, 2, 4, .check_relay = false},
{0x33D, 0, 8, .check_relay = true},
};
static CanMsg HONDA_RADARLESS_LONG_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x33D, 0, 8, .check_relay = true}, {0x1C8, 0, 8, .check_relay = true},
{0x30C, 0, 8, .check_relay = true}}; // Bosch radarless w/ gas and brakes
static CanMsg HONDA_CANFD_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x296, 0, 4, .check_relay = false}, {0x33D, 0, 8, .check_relay = true}};
// Bosch radarless w/ gas and brakes
static CanMsg HONDA_RADARLESS_LONG_TX_MSGS[] = {
{0xE4, 0, 5, .check_relay = true},
{0x33D, 0, 8, .check_relay = true},
{0x1C8, 0, 8, .check_relay = true},
{0x30C, 0, 8, .check_relay = true},
};
static CanMsg HONDA_CANFD_TX_MSGS[] = {
{0xE4, 0, 5, .check_relay = true},
{0x296, 0, 4, .check_relay = false},
{0x33D, 0, 8, .check_relay = true},
};
const uint16_t HONDA_PARAM_ALT_BRAKE = 1;
const uint16_t HONDA_PARAM_RADARLESS = 8;
+77 -82
View File
@@ -71,35 +71,38 @@ static const CanMsg HYUNDAI_TX_MSGS[] = {
static bool hyundai_legacy = false;
static uint8_t hyundai_get_counter(const CANPacket_t *msg) {
uint8_t cnt = 0;
if (msg->addr == 0x260U) {
cnt = (msg->data[7] >> 4) & 0x3U;
} else if (msg->addr == 0x386U) {
}
if (msg->addr == 0x386U) {
cnt = ((msg->data[3] >> 6) << 2) | (msg->data[1] >> 6);
} else if (msg->addr == 0x394U) {
}
if (msg->addr == 0x394U) {
cnt = (msg->data[1] >> 5) & 0x7U;
} else if (msg->addr == 0x421U) {
}
if (msg->addr == 0x421U) {
cnt = msg->data[7] & 0xFU;
} else if (msg->addr == 0x4F1U) {
}
if (msg->addr == 0x4F1U) {
cnt = (msg->data[3] >> 4) & 0xFU;
} else {
}
return cnt;
}
static uint32_t hyundai_get_checksum(const CANPacket_t *msg) {
uint8_t chksum = 0;
if (msg->addr == 0x260U) {
chksum = msg->data[7] & 0xFU;
} else if (msg->addr == 0x386U) {
}
if (msg->addr == 0x386U) {
chksum = ((msg->data[7] >> 6) << 2) | (msg->data[5] >> 6);
} else if (msg->addr == 0x394U) {
}
if (msg->addr == 0x394U) {
chksum = msg->data[6] & 0xFU;
} else if (msg->addr == 0x421U) {
}
if (msg->addr == 0x421U) {
chksum = msg->data[7] >> 4;
} else {
}
return chksum;
}
@@ -124,11 +127,11 @@ static uint32_t hyundai_compute_checksum(const CANPacket_t *msg) {
// sum of nibbles
for (int i = 0; i < 8; i++) {
if ((msg->addr == 0x394U) && (i == 7)) {
continue; // exclude
continue; // exclude
}
uint8_t b = msg->data[i];
if (((msg->addr == 0x260U) && (i == 7)) || ((msg->addr == 0x394U) && (i == 6)) || ((msg->addr == 0x421U) && (i == 7))) {
b &= (msg->addr == 0x421U) ? 0x0FU : 0xF0U; // remove checksum
b &= (msg->addr == 0x421U) ? 0x0FU : 0xF0U; // remove checksum
}
chksum += (b % 16U) + (b / 16U);
}
@@ -139,82 +142,75 @@ static uint32_t hyundai_compute_checksum(const CANPacket_t *msg) {
}
static void hyundai_rx_hook(const CANPacket_t *msg) {
// SCC12 is on bus 2 for camera-based SCC cars, bus 0 on all others
if (msg->addr == 0x421U) {
if (((msg->bus == 0U) && !hyundai_camera_scc) || ((msg->bus == 2U) && hyundai_camera_scc)) {
// 2 bits: 13-14
int cruise_engaged = (GET_BYTES(msg, 0, 4) >> 13) & 0x3U;
hyundai_common_cruise_state_check(cruise_engaged);
if (msg_matches(msg, 0x421U, hyundai_camera_scc ? 2U : 0U)) {
// 2 bits: 13-14
int cruise_engaged = (GET_BYTES_LE(msg, 0, 4) >> 13) & 0x3U;
hyundai_common_cruise_state_check(cruise_engaged);
}
if (msg_matches(msg, 0x420U, hyundai_camera_scc ? 2U : 0U)) {
if (!hyundai_longitudinal) {
acc_main_on = GET_BIT(msg, 0U);
}
}
if (msg->addr == 0x420U) {
if (((msg->bus == 0U) && !hyundai_camera_scc) || ((msg->bus == 2U) && hyundai_camera_scc)) {
if (!hyundai_longitudinal) {
acc_main_on = GET_BIT(msg, 0U);
}
}
if (msg_matches(msg, 0x251U, 0U)) {
int torque_driver_new = (GET_BYTES_LE(msg, 0, 2) & 0x7ffU) - 1024U;
// update array of samples
update_sample(&torque_driver, torque_driver_new);
}
if (msg->bus == 0U) {
if (msg->addr == 0x251U) {
int torque_driver_new = (GET_BYTES(msg, 0, 2) & 0x7ffU) - 1024U;
// update array of samples
update_sample(&torque_driver, torque_driver_new);
}
if (msg_matches(msg, 0x391U, 0U)) {
mads_button_press = GET_BIT(msg, 4U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
if (msg->addr == 0x391U) {
mads_button_press = GET_BIT(msg, 4U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
// ACC steering wheel buttons
if (msg_matches(msg, 0x4F1U, 0U)) {
int cruise_button = msg->data[0] & 0x7U;
bool main_button = GET_BIT(msg, 3U);
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// ACC steering wheel buttons
if (msg->addr == 0x4F1U) {
int cruise_button = msg->data[0] & 0x7U;
bool main_button = GET_BIT(msg, 3U);
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// gas press, different for EV, hybrid, and ICE models
if (msg_matches(msg, 0x371U, 0U) && hyundai_ev_gas_signal) {
gas_pressed = (((msg->data[4] & 0x7FU) << 1) | (msg->data[3] >> 7)) != 0U;
} else if (msg_matches(msg, 0x371U, 0U) && hyundai_hybrid_gas_signal) {
gas_pressed = msg->data[7] != 0U;
} else if (msg_matches(msg, 0x91U, 0U) && hyundai_fcev_gas_signal) {
gas_pressed = msg->data[6] != 0U;
} else if (msg_matches(msg, 0x260U, 0U) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
gas_pressed = (msg->data[7] >> 6) != 0U;
} else {
}
// gas press, different for EV, hybrid, and ICE models
if ((msg->addr == 0x371U) && hyundai_ev_gas_signal) {
gas_pressed = (((msg->data[4] & 0x7FU) << 1) | (msg->data[3] >> 7)) != 0U;
} else if ((msg->addr == 0x371U) && hyundai_hybrid_gas_signal) {
gas_pressed = msg->data[7] != 0U;
} else if ((msg->addr == 0x91U) && hyundai_fcev_gas_signal) {
gas_pressed = msg->data[6] != 0U;
} else if ((msg->addr == 0x260U) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
gas_pressed = (msg->data[7] >> 6) != 0U;
} else {
}
// sample wheel speed, averaging opposite corners
if (msg_matches(msg, 0x386U, 0U)) {
uint32_t front_left_speed = GET_BYTES_LE(msg, 0, 2) & 0x3FFFU;
uint32_t rear_right_speed = GET_BYTES_LE(msg, 6, 2) & 0x3FFFU;
vehicle_moving = (front_left_speed > HYUNDAI_STANDSTILL_THRSLD) || (rear_right_speed > HYUNDAI_STANDSTILL_THRSLD);
}
// sample wheel speed, averaging opposite corners
if (msg->addr == 0x386U) {
uint32_t front_left_speed = GET_BYTES(msg, 0, 2) & 0x3FFFU;
uint32_t rear_right_speed = GET_BYTES(msg, 6, 2) & 0x3FFFU;
vehicle_moving = (front_left_speed > HYUNDAI_STANDSTILL_THRSLD) || (rear_right_speed > HYUNDAI_STANDSTILL_THRSLD);
}
if (msg_matches(msg, 0x394U, 0U)) {
brake_pressed = ((msg->data[5] >> 5U) & 0x3U) == 0x2U;
}
if (msg->addr == 0x394U) {
brake_pressed = ((msg->data[5] >> 5U) & 0x3U) == 0x2U;
}
if (msg_matches(msg, 0x592U, 0U)) {
acc_main_on = GET_BIT(msg, 34U);
bool cruise_engaged = GET_BIT(msg, 35U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if (msg->addr == 0x592U) {
acc_main_on = GET_BIT(msg, 34U);
bool cruise_engaged = GET_BIT(msg, 35U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if (msg_matches(msg, 0x595U, 0U)) {
acc_main_on = GET_BIT(msg, 50U);
bool cruise_engaged = GET_BIT(msg, 51U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if (msg->addr == 0x595U) {
acc_main_on = GET_BIT(msg, 50U);
bool cruise_engaged = GET_BIT(msg, 51U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if ((msg->addr == 0x260U) && hyundai_non_scc && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
acc_main_on = GET_BIT(msg, 25U);
bool cruise_engaged = GET_BIT(msg, 26U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if (msg_matches(msg, 0x260U, 0U) && hyundai_non_scc && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
acc_main_on = GET_BIT(msg, 25U);
bool cruise_engaged = GET_BIT(msg, 26U);
hyundai_common_cruise_state_check(cruise_engaged);
}
hyundai_common_reset_acc_main_on_mismatches();
@@ -267,7 +263,7 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
// LKA STEER: safety check
if (msg->addr == 0x340U) {
int desired_torque = ((GET_BYTES(msg, 0, 4) >> 16) & 0x7ffU) - 1024U;
int desired_torque = ((GET_BYTES_LE(msg, 0, 4) >> 16) & 0x7ffU) - 1024U;
bool steer_req = GET_BIT(msg, 27U);
const TorqueSteeringLimits limits = hyundai_alt_limits_2 ? HYUNDAI_STEERING_LIMITS_ALT_2 :
@@ -280,7 +276,7 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
// UDS: Only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
if (msg->addr == 0x7D0U) {
if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
if (GET_BYTES_64_LE(msg, 0, 8) != 0x0000000000803E02ULL) {
tx = false;
}
}
@@ -303,9 +299,9 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
static safety_config hyundai_init(uint16_t param) {
static const CanMsg HYUNDAI_LONG_TX_MSGS[] = {
HYUNDAI_LONG_COMMON_TX_MSGS(0)
{0x38D, 0, 8, .check_relay = false}, // FCA11 Bus 0
{0x483, 0, 8, .check_relay = false}, // FCA12 Bus 0
{0x7D0, 0, 8, .check_relay = false}, // radar UDS TX addr Bus 0 (for radar disable)
{0x38D, 0, 8, .check_relay = false}, // FCA11 Bus 0
{0x483, 0, 8, .check_relay = false}, // FCA12 Bus 0
{0x7D0, 0, 8, .check_relay = false}, // radar UDS TX addr Bus 0 (for radar disable)
};
static const CanMsg HYUNDAI_CAMERA_SCC_TX_MSGS[] = {
@@ -366,7 +362,6 @@ static safety_config hyundai_init(uint16_t param) {
} else {
SET_TX_MSGS(HYUNDAI_LONG_TX_MSGS, ret);
}
} else if (hyundai_camera_scc) {
static RxCheck hyundai_cam_scc_rx_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
@@ -68,73 +68,69 @@ static uint32_t hyundai_canfd_get_checksum(const CANPacket_t *msg) {
}
static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
const unsigned pt_bus = hyundai_canfd_lka_steer_msg ? 1U : 0U;
const unsigned int scc_bus = hyundai_camera_scc ? 2U : pt_bus;
if (msg->bus == pt_bus) {
// driver torque
if (msg->addr == 0xeaU) {
int torque_driver_new = ((msg->data[11] & 0x1fU) << 8U) | msg->data[10];
torque_driver_new -= 4095;
update_sample(&torque_driver, torque_driver_new);
}
// cruise buttons
const unsigned int button_addr = hyundai_canfd_alt_buttons ? 0x1aaU : 0x1cfU;
if (msg->addr == button_addr) {
bool main_button = false;
int cruise_button = 0;
if (msg->addr == 0x1cfU) {
cruise_button = msg->data[2] & 0x7U;
main_button = GET_BIT(msg, 19U);
mads_button_press = GET_BIT(msg, 23U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
} else {
cruise_button = (msg->data[4] >> 4) & 0x7U;
main_button = GET_BIT(msg, 34U);
mads_button_press = GET_BIT(msg, 39U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// gas press, different for EV, hybrid, and ICE models
if ((msg->addr == 0x35U) && hyundai_ev_gas_signal) {
gas_pressed = msg->data[5] != 0U;
} else if ((msg->addr == 0x105U) && hyundai_hybrid_gas_signal) {
gas_pressed = GET_BIT(msg, 103U) || (msg->data[13] != 0U) || GET_BIT(msg, 112U);
} else if ((msg->addr == 0x100U) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
gas_pressed = GET_BIT(msg, 176U);
} else {
}
// brake press
if (msg->addr == 0x175U) {
brake_pressed = GET_BIT(msg, 81U);
}
// vehicle moving
if (msg->addr == 0xa0U) {
uint32_t fl = (GET_BYTES(msg, 8, 2)) & 0x3FFFU;
uint32_t fr = (GET_BYTES(msg, 10, 2)) & 0x3FFFU;
uint32_t rl = (GET_BYTES(msg, 12, 2)) & 0x3FFFU;
uint32_t rr = (GET_BYTES(msg, 14, 2)) & 0x3FFFU;
vehicle_moving = (fl > HYUNDAI_STANDSTILL_THRSLD) || (fr > HYUNDAI_STANDSTILL_THRSLD) ||
(rl > HYUNDAI_STANDSTILL_THRSLD) || (rr > HYUNDAI_STANDSTILL_THRSLD);
// average of all 4 wheel speeds. Conversion: raw * 0.03125 / 3.6 = m/s
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 * KPH_TO_MS);
}
// driver torque
if (msg_matches(msg, 0xeaU, pt_bus)) {
int torque_driver_new = ((msg->data[11] & 0x1fU) << 8U) | msg->data[10];
torque_driver_new -= 4095;
update_sample(&torque_driver, torque_driver_new);
}
if (msg->bus == scc_bus) {
// cruise state
if ((msg->addr == 0x1a0U) && !hyundai_longitudinal) {
// 1=enabled, 2=driver override
int cruise_status = ((msg->data[8] >> 4) & 0x7U);
bool cruise_engaged = (cruise_status == 1) || (cruise_status == 2);
hyundai_common_cruise_state_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 66U);
// cruise buttons
const unsigned int button_addr = hyundai_canfd_alt_buttons ? 0x1aaU : 0x1cfU;
if (msg_matches(msg, button_addr, pt_bus)) {
bool main_button = false;
int cruise_button = 0;
if (msg_matches(msg, 0x1cfU, pt_bus)) {
cruise_button = msg->data[2] & 0x7U;
main_button = GET_BIT(msg, 19U);
mads_button_press = GET_BIT(msg, 23U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
} else {
cruise_button = (msg->data[4] >> 4) & 0x7U;
main_button = GET_BIT(msg, 34U);
mads_button_press = GET_BIT(msg, 39U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// gas press, different for EV, hybrid, and ICE models
if (msg_matches(msg, 0x35U, pt_bus) && hyundai_ev_gas_signal) {
gas_pressed = msg->data[5] != 0U;
}
if (msg_matches(msg, 0x105U, pt_bus) && hyundai_hybrid_gas_signal) {
gas_pressed = ((msg->data[12] >> 7) | msg->data[13] | (msg->data[14] & 1U)) != 0U;
}
if (msg_matches(msg, 0x100U, pt_bus) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
gas_pressed = GET_BIT(msg, 176U);
}
// brake press
if (msg_matches(msg, 0x175U, pt_bus)) {
brake_pressed = GET_BIT(msg, 81U);
}
// vehicle moving
if (msg_matches(msg, 0xa0U, pt_bus)) {
uint32_t fl = (GET_BYTES_LE(msg, 8, 2)) & 0x3FFFU;
uint32_t fr = (GET_BYTES_LE(msg, 10, 2)) & 0x3FFFU;
uint32_t rl = (GET_BYTES_LE(msg, 12, 2)) & 0x3FFFU;
uint32_t rr = (GET_BYTES_LE(msg, 14, 2)) & 0x3FFFU;
vehicle_moving = (fl > HYUNDAI_STANDSTILL_THRSLD) || (fr > HYUNDAI_STANDSTILL_THRSLD) ||
(rl > HYUNDAI_STANDSTILL_THRSLD) || (rr > HYUNDAI_STANDSTILL_THRSLD);
// average of all 4 wheel speeds. Conversion: raw * 0.03125 / 3.6 = m/s
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 * KPH_TO_MS);
}
// cruise state
if (msg_matches(msg, 0x1a0U, scc_bus) && !hyundai_longitudinal) {
// 1=enabled, 2=driver override
int cruise_status = ((msg->data[8] >> 4) & 0x7U);
bool cruise_engaged = (cruise_status == 1) || (cruise_status == 2);
hyundai_common_cruise_state_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 66U);
}
hyundai_common_reset_acc_main_on_mismatches();
@@ -186,7 +182,7 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
// UDS: only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
if (((msg->addr == 0x730U) && hyundai_canfd_lka_steer_msg) || ((msg->addr == 0x7D0U) && !hyundai_camera_scc)) {
if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
if (GET_BYTES_64_LE(msg, 0, 8) != 0x0000000000803E02ULL) {
tx = false;
}
}
@@ -260,7 +256,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, true)
{0x160, 0, 16, .check_relay = true}, // ADRV_0x160
{0x160, 0, 16, .check_relay = true}, // ADRV_0x160
{0x7D0, 0, 8, .check_relay = false}, // tester present for radar ECU disable
};
@@ -285,7 +281,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
};
ret = BUILD_SAFETY_CFG(hyundai_canfd_lka_steer_msg_long_rx_checks, HYUNDAI_CANFD_LKA_STEER_MSG_LONG_TX_MSGS);
} else {
// Longitudinal checks for LFA steering
static RxCheck hyundai_canfd_long_rx_checks[] = {
@@ -312,7 +307,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
SET_TX_MSGS(HYUNDAI_CANFD_LFA_STEERING_LONG_TX_MSGS, ret);
}
}
} else {
if (hyundai_canfd_lka_steer_msg) {
// *** LKA steering checks ***
@@ -329,7 +323,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEER_MSG_TX_MSGS, ret);
}
} else if (!hyundai_camera_scc) {
// Radar sends SCC messages on these cars instead of camera
static RxCheck hyundai_canfd_radar_scc_rx_checks[] = {
@@ -349,7 +342,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
} else {
SET_RX_CHECKS(hyundai_canfd_radar_scc_rx_checks, ret);
}
} else {
// *** LFA steering checks ***
// Camera sends SCC messages on LFA steering cars.
@@ -74,7 +74,7 @@ void hyundai_common_init(uint16_t param) {
const uint16_t HYUNDAI_PARAM_HYBRID_GAS = 2;
const uint16_t HYUNDAI_PARAM_CAMERA_SCC = 8;
const uint16_t HYUNDAI_PARAM_CANFD_LKA_STEER_MSG = 16;
const uint16_t HYUNDAI_PARAM_ALT_LIMITS = 64; // TODO: shift this down with the rest of the common flags
const uint16_t HYUNDAI_PARAM_ALT_LIMITS = 64; // TODO: shift this down with the rest of the common flags
const uint16_t HYUNDAI_PARAM_FCEV_GAS = 256;
const uint16_t HYUNDAI_PARAM_ALT_LIMITS_2 = 512;
@@ -169,10 +169,9 @@ uint32_t hyundai_common_canfd_compute_checksum(const CANPacket_t *msg) {
if (len == 24) {
crc ^= 0x819dU;
} else if (len == 32) {
}
if (len == 32) {
crc ^= 0x9f5bU;
} else {
}
return crc;
+39 -39
View File
@@ -17,33 +17,31 @@
// track msgs coming from OP so that we know what CAM msgs to drop and what to forward
static void mazda_rx_hook(const CANPacket_t *msg) {
if ((int)msg->bus == MAZDA_MAIN) {
if (msg->addr == MAZDA_ENGINE_DATA) {
// sample speed: scale by 0.01 to get kph
int speed = (msg->data[2] << 8) | msg->data[3];
vehicle_moving = speed > 10; // moving when speed > 0.1 kph
}
if (msg_matches(msg, MAZDA_ENGINE_DATA, MAZDA_MAIN)) {
// sample speed: scale by 0.01 to get kph
int speed = (msg->data[2] << 8) | msg->data[3];
vehicle_moving = speed > 10; // moving when speed > 0.1 kph
}
if (msg->addr == MAZDA_STEER_TORQUE) {
int torque_driver_new = msg->data[0] - 127U;
// update array of samples
update_sample(&torque_driver, torque_driver_new);
}
if (msg_matches(msg, MAZDA_STEER_TORQUE, MAZDA_MAIN)) {
int torque_driver_new = msg->data[0] - 127U;
// update array of samples
update_sample(&torque_driver, torque_driver_new);
}
// enter controls on rising edge of ACC, exit controls on ACC off
if (msg->addr == MAZDA_CRZ_CTRL) {
bool cruise_engaged = msg->data[0] & 0x8U;
pcm_cruise_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 17U);
}
// enter controls on rising edge of ACC, exit controls on ACC off
if (msg_matches(msg, MAZDA_CRZ_CTRL, MAZDA_MAIN)) {
bool cruise_engaged = msg->data[0] & 0x8U;
pcm_cruise_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 17U);
}
if (msg->addr == MAZDA_ENGINE_DATA) {
gas_pressed = (msg->data[4] || (msg->data[5] & 0xF0U));
}
if (msg_matches(msg, MAZDA_ENGINE_DATA, MAZDA_MAIN)) {
gas_pressed = (msg->data[4] | (msg->data[5] & 0xF0U)) != 0U;
}
if (msg->addr == MAZDA_PEDALS) {
brake_pressed = (msg->data[0] & 0x10U);
}
if (msg_matches(msg, MAZDA_PEDALS, MAZDA_MAIN)) {
brake_pressed = (msg->data[0] & 0x10U);
}
}
@@ -60,24 +58,22 @@ static bool mazda_tx_hook(const CANPacket_t *msg) {
bool tx = true;
// Check if msg is sent on the main BUS
if (msg->bus == (unsigned char)MAZDA_MAIN) {
// steer cmd checks
if (msg->addr == MAZDA_LKAS) {
int desired_torque = (((msg->data[0] & 0x0FU) << 8) | msg->data[1]) - 2048U;
// steer cmd checks
if (msg_matches(msg, MAZDA_LKAS, MAZDA_MAIN)) {
int desired_torque = (((msg->data[0] & 0x0FU) << 8) | msg->data[1]) - 2048U;
if (steer_torque_cmd_checks(desired_torque, -1, MAZDA_STEERING_LIMITS)) {
tx = false;
}
if (steer_torque_cmd_checks(desired_torque, -1, MAZDA_STEERING_LIMITS)) {
tx = false;
}
}
// cruise buttons check
if (msg->addr == MAZDA_CRZ_BTNS) {
// allow resume spamming while controls allowed, but
// only allow cancel while controls not allowed
bool cancel_cmd = (msg->data[0] == 0x1U);
if (!controls_allowed && !cancel_cmd) {
tx = false;
}
// cruise buttons check
if (msg_matches(msg, MAZDA_CRZ_BTNS, MAZDA_MAIN)) {
// allow resume spamming while controls allowed, but
// only allow cancel while controls not allowed
bool cancel_cmd = (msg->data[0] == 0x1U);
if (!controls_allowed && !cancel_cmd) {
tx = false;
}
}
@@ -85,7 +81,11 @@ static bool mazda_tx_hook(const CANPacket_t *msg) {
}
static safety_config mazda_init(uint16_t param) {
static const CanMsg MAZDA_TX_MSGS[] = {{MAZDA_LKAS, 0, 8, .check_relay = true}, {MAZDA_CRZ_BTNS, 0, 8, .check_relay = false}, {MAZDA_LKAS_HUD, 0, 8, .check_relay = true}};
static const CanMsg MAZDA_TX_MSGS[] = {
{MAZDA_LKAS, 0, 8, .check_relay = true},
{MAZDA_CRZ_BTNS, 0, 8, .check_relay = false},
{MAZDA_LKAS_HUD, 0, 8, .check_relay = true},
};
static RxCheck mazda_rx_checks[] = {
{.msg = {{MAZDA_CRZ_CTRL, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+61 -57
View File
@@ -5,66 +5,82 @@
static uint8_t mg_crc_lut[256];
static uint32_t mg_get_checksum(const CANPacket_t *msg) {
return msg->data[7];
uint32_t checksum = msg->data[7];
if (msg->addr == 0x1ecU) {
checksum = ((msg->data[2] & 0x7FU) << 8) | msg->data[3];
}
return checksum;
}
static uint32_t mg_compute_checksum(const CANPacket_t *msg) {
uint8_t checksum = 0xFFU;
for (int i = 0; i < 7; i++) {
checksum ^= msg->data[i];
checksum = mg_crc_lut[checksum];
uint32_t checksum;
if (msg->addr == 0x1ecU) {
uint32_t torque = ((msg->data[0] & 0x7U) << 8) | msg->data[1];
uint32_t valid = (msg->data[0] >> 3) & 1U;
uint32_t status = (msg->data[6] >> 4) & 0x7U;
uint32_t counter = msg->data[0] >> 4;
checksum = (0U - ((torque << 1) + (status << 12) + valid + counter)) & 0x7FFFU;
} else {
checksum = 0xFFU;
for (int i = 0; i < 7; i++) {
checksum ^= msg->data[i];
checksum = mg_crc_lut[checksum];
}
checksum ^= 0xFFU;
}
return checksum ^ 0xFFU;
return checksum;
}
static uint8_t mg_get_counter(const CANPacket_t *msg) {
uint8_t counter = 0U;
if (msg->addr == 0x23cU) {
counter = (msg->data[4] >> 4) & 0xFU;
} else if (msg->addr == 0x1ecU) {
}
if (msg->addr == 0x1ecU) {
counter = (msg->data[0] >> 4) & 0xFU;
} else if (msg->addr == 0x242U) {
}
if (msg->addr == 0x242U) {
counter = (msg->data[0] >> 3) & 0xFU;
} else if (msg->addr == 0x1b6U) {
}
if (msg->addr == 0x1b6U) {
counter = msg->data[6] & 0xFU;
} else {
// No counter for this message
}
if (msg->addr == 0xAFU) {
counter = msg->data[5] >> 4U;
}
return counter;
}
static void mg_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Vehicle speed
if (msg->addr == 0x23cU) {
float speed = (((msg->data[2] & 0x7FU) << 8) | msg->data[3]) * 0.015625;
vehicle_moving = speed > 0.0;
UPDATE_VEHICLE_SPEED(speed * KPH_TO_MS);
}
// Vehicle speed
if (msg_matches(msg, 0x23cU, 0U)) {
float speed = (((msg->data[2] & 0x7FU) << 8) | msg->data[3]) * 0.015625;
vehicle_moving = speed > 0.0;
UPDATE_VEHICLE_SPEED(speed * KPH_TO_MS);
}
// Gas pressed
if (msg->addr == 0xafU) {
gas_pressed = msg->data[0] != 0U;
}
// Gas pressed
if (msg_matches(msg, 0xafU, 0U)) {
gas_pressed = msg->data[0] != 0U;
}
// Driver torque
if (msg->addr == 0x1ecU) {
int torque_driver_new = (((msg->data[4] & 0x7U) << 8) | msg->data[5]) - 1024U;
update_sample(&torque_driver, torque_driver_new);
}
// Driver torque
if (msg_matches(msg, 0x1ecU, 0U)) {
int torque_driver_new = (((msg->data[4] & 0x7U) << 8) | msg->data[5]) - 1024U;
update_sample(&torque_driver, torque_driver_new);
}
// Brake pressed
if (msg->addr == 0x1b6U) {
brake_pressed = GET_BIT(msg, 10U);
}
// Brake pressed
if (msg_matches(msg, 0x1b6U, 0U)) {
brake_pressed = GET_BIT(msg, 10U);
}
// Cruise state
if (msg->addr == 0x242U) {
int cruise_state = (msg->data[5] & 0x38U) >> 3;
bool cruise_engaged = (cruise_state == 2) || // Active
(cruise_state == 3); // Override
pcm_cruise_check(cruise_engaged);
}
// Cruise state
if (msg_matches(msg, 0x242U, 0U)) {
int cruise_state = (msg->data[5] & 0x38U) >> 3;
bool cruise_engaged = (cruise_state == 2) || // Active
(cruise_state == 3); // Override
pcm_cruise_check(cruise_engaged);
}
}
@@ -79,22 +95,10 @@ static bool mg_tx_hook(const CANPacket_t *msg) {
.type = TorqueDriverLimited,
};
bool tx = true;
bool violation = false;
// Steering control
if (msg->addr == 0x1fdU) {
int desired_torque = (((msg->data[0] & 0x7U) << 8) | msg->data[1]) - 1024U;
bool steer_req = GET_BIT(msg, 35U);
violation |= steer_torque_cmd_checks(desired_torque, steer_req, MG_STEERING_LIMITS);
}
if (violation) {
tx = false;
}
return tx;
// The TX list dispatches only steering control (0x1fd, bus 0) to this hook.
int desired_torque = (((msg->data[0] & 0x7U) << 8) | msg->data[1]) - 1024U;
bool steer_req = GET_BIT(msg, 35U);
return !steer_torque_cmd_checks(desired_torque, steer_req, MG_STEERING_LIMITS);
}
static safety_config mg_init(uint16_t param) {
@@ -105,9 +109,9 @@ static safety_config mg_init(uint16_t param) {
static const CanMsg MG_TX_MSGS[] = {{0x1fd, 0, 8, .check_relay = true}};
static RxCheck mg_rx_checks[] = {
{.msg = {{0x23c, 0, 8, .frequency = 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // SCS_HSC2_FrP19 (speed)
{.msg = {{0xaf, 0, 8, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // GW_HSC2_HCU_FrP00 (gas pedal)
{.msg = {{0x1ec, 0, 8, .frequency = 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EPS_HSC2_FrP03 (driver torque)
{.msg = {{0x23c, 0, 8, .frequency = 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // SCS_HSC2_FrP19 (speed)
{.msg = {{0xaf, 0, 8, .frequency = 100U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // GW_HSC2_HCU_FrP00 (gas pedal)
{.msg = {{0x1ec, 0, 8, .frequency = 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EPS_HSC2_FrP03 (driver torque)
{.msg = {{0x242, 0, 8, .frequency = 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // RADAR_HSC2_FrP00 (cruise state)
{.msg = {{0x1b6, 0, 8, .frequency = 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EHBS_HSC2_FrP00 (brake pedal)
};
+32 -39
View File
@@ -25,59 +25,54 @@ static const AngleSteeringLimits NISSAN_STEERING_LIMITS = {
.angle_deg_to_can = 100,
.angle_rate_up_lookup = {
{0., 5., 15.},
{5., .8, .15}
{5., .8, .15},
},
.angle_rate_down_lookup = {
{0., 5., 15.},
{5., 3.5, .4}
{5., 3.5, .4},
},
};
static void nissan_rx_hook(const CANPacket_t *msg) {
// Altima: on camera bus, others: on pt bus
if (msg->bus == 0U) {
if (msg->addr == 0x185U) {
// Current steering angle
int angle_meas_new = (msg->data[2] << 10) | (msg->data[3] << 2) | (msg->data[4] >> 6);
// Factor is -0.01, offset is 1310. Flip to correct sign, but keep units in CAN scale
angle_meas_new = -angle_meas_new + (1310.0f * NISSAN_STEERING_LIMITS.angle_deg_to_can);
if (msg_matches(msg, 0x185U, 0U)) {
// Current steering angle
int angle_meas_new = (msg->data[2] << 10) | (msg->data[3] << 2) | (msg->data[4] >> 6);
// Factor is -0.01, offset is 1310. Flip to correct sign, but keep units in CAN scale
angle_meas_new = -angle_meas_new + (1310.0f * NISSAN_STEERING_LIMITS.angle_deg_to_can);
// update array of samples
update_sample(&angle_meas, angle_meas_new);
// update array of samples
update_sample(&angle_meas, angle_meas_new);
}
if (msg_matches(msg, 0x285U, nissan_alt_eps ? 1U : 0U)) {
// Get current speed and standstill
uint16_t right_rear = (msg->data[0] << 8) | (msg->data[1]);
uint16_t left_rear = (msg->data[2] << 8) | (msg->data[3]);
vehicle_moving = (right_rear | left_rear) != 0U;
UPDATE_VEHICLE_SPEED((right_rear + left_rear) / 2.0 * 0.005 * KPH_TO_MS);
}
// X-Trail 0x15c, Leaf 0x239
if (msg_matches(msg, 0x15cU, nissan_alt_eps ? 1U : 0U) || msg_matches(msg, 0x239U, nissan_alt_eps ? 1U : 0U)) {
if (msg->addr == 0x15cU) {
gas_pressed = ((msg->data[5] << 2) | ((msg->data[6] >> 6) & 0x3U)) > 3U;
} else {
gas_pressed = msg->data[0] > 3U;
}
}
if (msg->bus == (nissan_alt_eps ? 1U : 0U)) {
if (msg->addr == 0x285U) {
// Get current speed and standstill
uint16_t right_rear = (msg->data[0] << 8) | (msg->data[1]);
uint16_t left_rear = (msg->data[2] << 8) | (msg->data[3]);
vehicle_moving = (right_rear | left_rear) != 0U;
UPDATE_VEHICLE_SPEED((right_rear + left_rear) / 2.0 * 0.005 * KPH_TO_MS);
}
// X-Trail 0x15c, Leaf 0x239
if ((msg->addr == 0x15cU) || (msg->addr == 0x239U)) {
if (msg->addr == 0x15cU){
gas_pressed = ((msg->data[5] << 2) | ((msg->data[6] >> 6) & 0x3U)) > 3U;
} else {
gas_pressed = msg->data[0] > 3U;
}
}
// X-trail 0x454, Leaf 0x239
if ((msg->addr == 0x454U) || (msg->addr == 0x239U)) {
if (msg->addr == 0x454U){
brake_pressed = (msg->data[2] & 0x80U) != 0U;
} else {
brake_pressed = ((msg->data[4] >> 5) & 1U) != 0U;
}
// X-trail 0x454, Leaf 0x239
if (msg_matches(msg, 0x454U, nissan_alt_eps ? 1U : 0U) || msg_matches(msg, 0x239U, nissan_alt_eps ? 1U : 0U)) {
if (msg->addr == 0x454U) {
brake_pressed = (msg->data[2] & 0x80U) != 0U;
} else {
brake_pressed = ((msg->data[4] >> 5) & 1U) != 0U;
}
}
// Handle cruise enabled
if ((msg->addr == 0x30fU) && (msg->bus == (nissan_alt_eps ? 1U : 2U))) {
if (msg_matches(msg, 0x30fU, nissan_alt_eps ? 1U : 2U)) {
bool cruise_engaged = (msg->data[0] >> 3) & 1U;
pcm_cruise_check(cruise_engaged);
}
@@ -91,7 +86,6 @@ static void nissan_rx_hook(const CANPacket_t *msg) {
}
}
static bool nissan_tx_hook(const CANPacket_t *msg) {
bool tx = true;
bool violation = false;
@@ -116,7 +110,6 @@ static bool nissan_tx_hook(const CANPacket_t *msg) {
return tx;
}
static safety_config nissan_init(uint16_t param) {
static const CanMsg NISSAN_TX_MSGS_LEAF[] = {
{0x169, 0, 8, .check_relay = true}, // LKAS
+30 -43
View File
@@ -6,9 +6,9 @@
#define PSA_STEERING_ALT 773U // RX from EPS, steering angle
#define PSA_DYN_CMM 520U // RX from CMM, gas pedal
#define PSA_HS2_DYN_ABR_38D 909U // RX from UC_FREIN, speed
#define PSA_HS2_DAT_MDD_CMD_452 1106U // RX from BSI, cruise state
#define PSA_DAT_BSI 1042U // RX from BSI, brake
#define PSA_LANE_KEEP_ASSIST 1010U // TX from OP, EPS
#define PSA_HS2_DAT_MDD_CMD_452 1106U // RX from BSI, cruise state
#define PSA_DAT_BSI 1042U // RX from BSI, brake
#define PSA_LANE_KEEP_ASSIST 1010U // TX from OP, EPS
// CAN bus
#define PSA_MAIN_BUS 0U
@@ -19,9 +19,9 @@ static uint8_t psa_get_counter(const CANPacket_t *msg) {
uint8_t cnt = 0;
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
cnt = (msg->data[3] >> 4) & 0xFU;
} else if (msg->addr == PSA_HS2_DYN_ABR_38D) {
}
if (msg->addr == PSA_HS2_DYN_ABR_38D) {
cnt = (msg->data[5] >> 4) & 0xFU;
} else {
}
return cnt;
}
@@ -50,45 +50,37 @@ static uint32_t psa_compute_checksum(const CANPacket_t *msg) {
uint8_t chk = 0;
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
chk = _psa_compute_checksum(msg, 0x4, 5);
} else if (msg->addr == PSA_HS2_DYN_ABR_38D) {
}
if (msg->addr == PSA_HS2_DYN_ABR_38D) {
chk = _psa_compute_checksum(msg, 0x7, 5);
} else {
}
return chk;
}
static void psa_rx_hook(const CANPacket_t *msg) {
if (msg->bus == PSA_MAIN_BUS) {
if (msg->addr == PSA_DYN_CMM) {
gas_pressed = msg->data[3] > 0U; // P002_Com_rAPP
}
if (msg->addr == PSA_STEERING_ALT) {
int angle_meas_new = to_signed((msg->data[0] << 8) | msg->data[1], 16); // ANGLE
update_sample(&angle_meas, angle_meas_new);
}
if (msg->addr == PSA_HS2_DYN_ABR_38D) {
int speed = (msg->data[0] << 8) | msg->data[1];
vehicle_moving = speed > 0;
UPDATE_VEHICLE_SPEED(speed * 0.01 * KPH_TO_MS); // VITESSE_VEHICULE_ROUES
}
if (msg_matches(msg, PSA_DYN_CMM, PSA_MAIN_BUS)) {
gas_pressed = msg->data[3] > 0U; // P002_Com_rAPP
}
if (msg_matches(msg, PSA_STEERING_ALT, PSA_MAIN_BUS)) {
int angle_meas_new = to_signed((msg->data[0] << 8) | msg->data[1], 16); // ANGLE
update_sample(&angle_meas, angle_meas_new);
}
if (msg_matches(msg, PSA_HS2_DYN_ABR_38D, PSA_MAIN_BUS)) {
int speed = (msg->data[0] << 8) | msg->data[1];
vehicle_moving = speed > 0;
UPDATE_VEHICLE_SPEED(speed * 0.01 * KPH_TO_MS); // VITESSE_VEHICULE_ROUES
}
if (msg->bus == PSA_ADAS_BUS) {
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
pcm_cruise_check((msg->data[2U] >> 7U) & 1U); // RVV_ACC_ACTIVATION_REQ
}
if (msg_matches(msg, PSA_HS2_DAT_MDD_CMD_452, PSA_ADAS_BUS)) {
pcm_cruise_check((msg->data[2U] >> 7U) & 1U); // RVV_ACC_ACTIVATION_REQ
}
if (msg->bus == PSA_CAM_BUS) {
if (msg->addr == PSA_DAT_BSI) {
brake_pressed = (msg->data[0U] >> 5U) & 1U; // P013_MainBrake
}
if (msg_matches(msg, PSA_DAT_BSI, PSA_CAM_BUS)) {
brake_pressed = (msg->data[0U] >> 5U) & 1U; // P013_MainBrake
}
}
static bool psa_tx_hook(const CANPacket_t *msg) {
bool tx = true;
static const AngleSteeringLimits PSA_STEERING_LIMITS = {
.max_angle = 3900,
.angle_deg_to_can = 10,
@@ -102,30 +94,25 @@ static bool psa_tx_hook(const CANPacket_t *msg) {
},
};
// Safety check for LKA
if (msg->addr == PSA_LANE_KEEP_ASSIST) {
// SET_ANGLE
int desired_angle = to_signed((msg->data[6] << 6) | ((msg->data[7] & 0xFCU) >> 2), 14);
// TORQUE_FACTOR
bool lka_active = ((msg->data[5] & 0xFEU) >> 1) == 100U;
// The TX list dispatches only PSA_LANE_KEEP_ASSIST on PSA_MAIN_BUS to this hook.
// SET_ANGLE
int desired_angle = to_signed((msg->data[6] << 6) | ((msg->data[7] & 0xFCU) >> 2), 14);
// TORQUE_FACTOR
bool lka_active = ((msg->data[5] & 0xFEU) >> 1) == 100U;
if (steer_angle_cmd_checks(desired_angle, lka_active, PSA_STEERING_LIMITS)) {
tx = false;
}
}
return tx;
return !steer_angle_cmd_checks(desired_angle, lka_active, PSA_STEERING_LIMITS);
}
static safety_config psa_init(uint16_t param) {
SAFETY_UNUSED(param);
static const CanMsg PSA_TX_MSGS[] = {
{PSA_LANE_KEEP_ASSIST, PSA_MAIN_BUS, 8, .check_relay = true}, // EPS steering
{PSA_LANE_KEEP_ASSIST, PSA_MAIN_BUS, 8, .check_relay = true}, // EPS steering
};
static RxCheck psa_rx_checks[] = {
{.msg = {{PSA_HS2_DAT_MDD_CMD_452, PSA_ADAS_BUS, 6, 20U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // cruise state
{.msg = {{PSA_HS2_DYN_ABR_38D, PSA_MAIN_BUS, 8, 25U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // speed
{.msg = {{PSA_STEERING_ALT, PSA_MAIN_BUS, 7, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // steering angle
{.msg = {{PSA_STEERING_ALT, PSA_MAIN_BUS, 7, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // steering angle
{.msg = {{PSA_STEERING, PSA_MAIN_BUS, 7, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // driver torque
{.msg = {{PSA_DYN_CMM, PSA_MAIN_BUS, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // gas pedal
{.msg = {{PSA_DAT_BSI, PSA_CAM_BUS, 8, 20U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // brake
+73 -68
View File
@@ -8,7 +8,6 @@ static uint8_t rivian_get_counter(const CANPacket_t *msg) {
}
static uint32_t rivian_get_checksum(const CANPacket_t *msg) {
// Signal: ESP_Status_Checksum, VDM_PropStatus_Checksum
return msg->data[0];
}
@@ -18,14 +17,7 @@ static uint8_t _rivian_compute_checksum(const CANPacket_t *msg, uint8_t poly, ui
uint8_t crc = 0;
// Skip the checksum byte
for (int i = 1; i < len; i++) {
crc ^= msg->data[i];
for (int j = 0; j < 8; j++) {
if ((crc & 0x80U) != 0U) {
crc = (crc << 1) ^ poly;
} else {
crc <<= 1;
}
}
crc = crc8_update(crc, msg->data[i], poly);
}
return crc ^ xor_output;
}
@@ -34,9 +26,18 @@ static uint32_t rivian_compute_checksum(const CANPacket_t *msg) {
uint8_t chksum = 0;
if (msg->addr == 0x208U) {
chksum = _rivian_compute_checksum(msg, 0x1D, 0xB1);
} else if (msg->addr == 0x150U) {
}
if (msg->addr == 0x150U) {
chksum = _rivian_compute_checksum(msg, 0x1D, 0x9A);
} else {
}
if (msg->addr == 0x380U) {
chksum = _rivian_compute_checksum(msg, 0x1D, 0x1E);
}
if (msg->addr == 0x38FU) {
chksum = _rivian_compute_checksum(msg, 0x1D, 0x37);
}
if (msg->addr == 0x100U) {
chksum = _rivian_compute_checksum(msg, 0x1D, 0x5F);
}
return chksum;
}
@@ -45,50 +46,48 @@ static bool rivian_get_quality_flag_valid(const CANPacket_t *msg) {
bool valid = false;
if (msg->addr == 0x208U) {
valid = ((msg->data[3] >> 3) & 0x3U) == 0x1U; // ESP_Vehicle_Speed_Q
} else if (msg->addr == 0x150U) {
}
if (msg->addr == 0x150U) {
valid = (msg->data[1] >> 6) == 0x1U; // VDM_VehicleSpeedQ
} else {
}
if (msg->addr == 0x38FU) {
valid = ((msg->data[2] >> 5) & 0x3U) == 0x1U; // iBESP2_BrakePedalApplied_Q
}
return valid;
}
static void rivian_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Vehicle speed
if (msg->addr == 0x208U) {
float speed = ((msg->data[6] << 8) | msg->data[7]) * 0.01;
vehicle_moving = speed > 0.0;
UPDATE_VEHICLE_SPEED(speed * KPH_TO_MS);
}
// Gas pressed and second speed source for variable torque limit
if (msg->addr == 0x150U) {
gas_pressed = msg->data[3] | (msg->data[4] & 0xC0U);
// Disable controls if speeds from VDM and ESP ECUs are too far apart.
float vdm_speed = ((msg->data[5] << 8) | msg->data[6]) * 0.01 * KPH_TO_MS;
speed_mismatch_check(vdm_speed);
}
// Driver torque
if (msg->addr == 0x380U) {
int torque_driver_new = (((msg->data[2] << 4) | (msg->data[3] >> 4))) - 2050U;
update_sample(&torque_driver, torque_driver_new);
}
// Brake pressed
if (msg->addr == 0x38fU) {
brake_pressed = (msg->data[2] >> 7) & 1U;
}
// Vehicle speed
if (msg_matches(msg, 0x208U, 0U)) {
float speed = ((msg->data[6] << 8) | msg->data[7]) * 0.01;
vehicle_moving = speed > 0.0;
UPDATE_VEHICLE_SPEED(speed * KPH_TO_MS);
}
if (msg->bus == 2U) {
// Cruise state
if (msg->addr == 0x100U) {
const int feature_status = msg->data[2] >> 5U;
pcm_cruise_check(feature_status == 1);
}
// Gas pressed and second speed source for variable torque limit
if (msg_matches(msg, 0x150U, 0U)) {
gas_pressed = msg->data[3] | (msg->data[4] & 0xC0U);
// Disable controls if speeds from VDM and ESP ECUs are too far apart.
float vdm_speed = ((msg->data[5] << 8) | msg->data[6]) * 0.01 * KPH_TO_MS;
speed_mismatch_check(vdm_speed);
}
// Driver torque
if (msg_matches(msg, 0x380U, 0U)) {
int torque_driver_new = (((msg->data[2] << 4) | (msg->data[3] >> 4))) - 2050U;
update_sample(&torque_driver, torque_driver_new);
}
// Brake pressed
if (msg_matches(msg, 0x38fU, 0U)) {
brake_pressed = (msg->data[2] >> 7) & 1U;
}
// Cruise state
if (msg_matches(msg, 0x100U, 2U)) {
const int feature_status = msg->data[2] >> 5U;
pcm_cruise_check(feature_status == 1);
}
}
@@ -117,23 +116,21 @@ static bool rivian_tx_hook(const CANPacket_t *msg) {
bool tx = true;
if (msg->bus == 0U) {
// Steering control
if (msg->addr == 0x120U) {
int desired_torque = ((msg->data[2] << 3U) | (msg->data[3] >> 5U)) - 1024U;
bool steer_req = (msg->data[3] >> 4) & 1U;
// Steering control
if (msg_matches(msg, 0x120U, 0U)) {
int desired_torque = ((msg->data[2] << 3U) | (msg->data[3] >> 5U)) - 1024U;
bool steer_req = (msg->data[3] >> 4) & 1U;
if (steer_torque_cmd_checks(desired_torque, steer_req, RIVIAN_STEERING_LIMITS)) {
tx = false;
}
if (steer_torque_cmd_checks(desired_torque, steer_req, RIVIAN_STEERING_LIMITS)) {
tx = false;
}
}
// Longitudinal control
if (msg->addr == 0x160U) {
int raw_accel = ((msg->data[2] << 3) | (msg->data[3] >> 5)) - 1024U;
if (longitudinal_accel_checks(raw_accel, RIVIAN_LONG_LIMITS)) {
tx = false;
}
// Longitudinal control
if (msg_matches(msg, 0x160U, 0U)) {
int raw_accel = ((msg->data[2] << 3) | (msg->data[3] >> 5)) - 1024U;
if (longitudinal_accel_checks(raw_accel, RIVIAN_LONG_LIMITS)) {
tx = false;
}
}
@@ -144,16 +141,24 @@ static safety_config rivian_init(uint16_t param) {
// SCCM_WheelTouch: for hiding hold wheel alert
// VDM_AdasSts: for canceling stock ACC
// 0x120 = ACM_lkaHbaCmd, 0x321 = SCCM_WheelTouch, 0x162 = VDM_AdasSts
static const CanMsg RIVIAN_TX_MSGS[] = {{0x120, 0, 8, .check_relay = true}, {0x321, 2, 7, .check_relay = true}, {0x162, 2, 8, .check_relay = true}};
static const CanMsg RIVIAN_TX_MSGS[] = {
{0x120, 0, 8, .check_relay = true},
{0x321, 2, 7, .check_relay = true},
{0x162, 2, 8, .check_relay = true},
};
// 0x160 = ACM_longitudinalRequest
static const CanMsg RIVIAN_LONG_TX_MSGS[] = {{0x120, 0, 8, .check_relay = true}, {0x321, 2, 7, .check_relay = true}, {0x160, 0, 5, .check_relay = true}};
static const CanMsg RIVIAN_LONG_TX_MSGS[] = {
{0x120, 0, 8, .check_relay = true},
{0x321, 2, 7, .check_relay = true},
{0x160, 0, 5, .check_relay = true},
};
static RxCheck rivian_rx_checks[] = {
{.msg = {{0x208, 0, 8, 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // ESP_Status (speed)
{.msg = {{0x150, 0, 7, 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // VDM_PropStatus (gas pedal & 2nd speed)
{.msg = {{0x380, 0, 5, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EPAS_SystemStatus (driver torque)
{.msg = {{0x38f, 0, 6, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // iBESP2 (brakes)
{.msg = {{0x100, 2, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // ACM_Status (cruise state)
{.msg = {{0x208, 0, 8, 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // ESP_Status (speed)
{.msg = {{0x150, 0, 7, 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // VDM_PropStatus (gas pedal & 2nd speed)
{.msg = {{0x38f, 0, 6, 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // iBESP2 (brakes)
{.msg = {{0x380, 0, 5, 100U, .max_counter = 14U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EPAS_SystemStatus (driver torque)
{.msg = {{0x100, 2, 8, 100U, .max_counter = 14U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // ACM_Status (cruise state)
};
bool rivian_longitudinal = false;
+16 -15
View File
@@ -100,9 +100,9 @@ static uint32_t subaru_compute_checksum(const CANPacket_t *msg) {
static void subaru_rx_hook(const CANPacket_t *msg) {
const unsigned int alt_main_bus = subaru_gen2 ? SUBARU_ALT_BUS : SUBARU_MAIN_BUS;
if ((msg->addr == MSG_SUBARU_Steering_Torque) && (msg->bus == SUBARU_MAIN_BUS)) {
if (msg_matches(msg, MSG_SUBARU_Steering_Torque, SUBARU_MAIN_BUS)) {
int torque_driver_new;
torque_driver_new = ((GET_BYTES(msg, 0, 4) >> 16) & 0x7FFU);
torque_driver_new = ((GET_BYTES_LE(msg, 0, 4) >> 16) & 0x7FFU);
torque_driver_new = -1 * to_signed(torque_driver_new, 11);
update_sample(&torque_driver, torque_driver_new);
}
@@ -115,29 +115,29 @@ static void subaru_rx_hook(const CANPacket_t *msg) {
}
// enter controls on rising edge of ACC, exit controls on ACC off
if ((msg->addr == MSG_SUBARU_CruiseControl) && (msg->bus == alt_main_bus)) {
if (msg_matches(msg, MSG_SUBARU_CruiseControl, alt_main_bus)) {
bool cruise_engaged = (msg->data[5] >> 1) & 1U;
pcm_cruise_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 40U);
}
// update vehicle moving with any non-zero wheel speed
if ((msg->addr == MSG_SUBARU_Wheel_Speeds) && (msg->bus == alt_main_bus)) {
uint32_t fr = (GET_BYTES(msg, 1, 3) >> 4) & 0x1FFFU;
uint32_t rr = (GET_BYTES(msg, 3, 3) >> 1) & 0x1FFFU;
uint32_t rl = (GET_BYTES(msg, 4, 3) >> 6) & 0x1FFFU;
uint32_t fl = (GET_BYTES(msg, 6, 2) >> 3) & 0x1FFFU;
if (msg_matches(msg, MSG_SUBARU_Wheel_Speeds, alt_main_bus)) {
uint32_t fr = (GET_BYTES_LE(msg, 1, 3) >> 4) & 0x1FFFU;
uint32_t rr = (GET_BYTES_LE(msg, 3, 3) >> 1) & 0x1FFFU;
uint32_t rl = (GET_BYTES_LE(msg, 4, 3) >> 6) & 0x1FFFU;
uint32_t fl = (GET_BYTES_LE(msg, 6, 2) >> 3) & 0x1FFFU;
vehicle_moving = (fr > 0U) || (rr > 0U) || (rl > 0U) || (fl > 0U);
vehicle_moving = (fr | rr | rl | fl) != 0U;
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.057 * KPH_TO_MS);
}
if ((msg->addr == MSG_SUBARU_Brake_Status) && (msg->bus == alt_main_bus)) {
if (msg_matches(msg, MSG_SUBARU_Brake_Status, alt_main_bus)) {
brake_pressed = (msg->data[7] >> 6) & 1U;
}
if ((msg->addr == MSG_SUBARU_Throttle) && (msg->bus == SUBARU_MAIN_BUS)) {
if (msg_matches(msg, MSG_SUBARU_Throttle, SUBARU_MAIN_BUS)) {
gas_pressed = msg->data[4] != 0U;
}
}
@@ -149,7 +149,7 @@ static bool subaru_tx_hook(const CANPacket_t *msg) {
const LongitudinalLimits SUBARU_LONG_LIMITS = {
.min_gas = 808, // appears to be engine braking
.max_gas = 3400, // approx 2 m/s^2 when maxing cruise_rpm and cruise_throttle
.inactive_gas = 1818, // this is zero acceleration
.inactive_gas = 1818, // this is zero acceleration
.max_brake = 600, // approx -3.5 m/s^2
.min_transmission_rpm = 0,
@@ -161,7 +161,7 @@ static bool subaru_tx_hook(const CANPacket_t *msg) {
// steer cmd checks
if (msg->addr == MSG_SUBARU_ES_LKAS) {
int desired_torque = ((GET_BYTES(msg, 0, 4) >> 16) & 0x1FFFU);
int desired_torque = ((GET_BYTES_LE(msg, 0, 4) >> 16) & 0x1FFFU);
desired_torque = -1 * to_signed(desired_torque, 13);
bool steer_req = (msg->data[3] >> 5) & 1U;
@@ -178,7 +178,7 @@ static bool subaru_tx_hook(const CANPacket_t *msg) {
// check es_distance cruise_throttle limits
if (msg->addr == MSG_SUBARU_ES_Distance) {
int cruise_throttle = (GET_BYTES(msg, 2, 2) & 0x1FFFU);
int cruise_throttle = (GET_BYTES_LE(msg, 2, 2) & 0x1FFFU);
bool cruise_cancel = (msg->data[7] >> 0) & 1U;
if (subaru_longitudinal) {
@@ -207,9 +207,10 @@ static bool subaru_tx_hook(const CANPacket_t *msg) {
violation |= !(is_tester_present || is_button_rdbi);
}
if (violation){
if (violation) {
tx = false;
}
return tx;
}
@@ -29,34 +29,32 @@
static bool subaru_pg_reversed_driver_torque = false;
static void subaru_preglobal_rx_hook(const CANPacket_t *msg) {
if (msg->bus == SUBARU_PG_MAIN_BUS) {
if (msg->addr == MSG_SUBARU_PG_Steering_Torque) {
int torque_driver_new;
torque_driver_new = (msg->data[3] >> 5) + (msg->data[4] << 3);
torque_driver_new = to_signed(torque_driver_new, 11);
torque_driver_new = subaru_pg_reversed_driver_torque ? -torque_driver_new : torque_driver_new;
update_sample(&torque_driver, torque_driver_new);
}
if (msg_matches(msg, MSG_SUBARU_PG_Steering_Torque, SUBARU_PG_MAIN_BUS)) {
int torque_driver_new;
torque_driver_new = (msg->data[3] >> 5) + (msg->data[4] << 3);
torque_driver_new = to_signed(torque_driver_new, 11);
torque_driver_new = subaru_pg_reversed_driver_torque ? -torque_driver_new : torque_driver_new;
update_sample(&torque_driver, torque_driver_new);
}
// enter controls on rising edge of ACC, exit controls on ACC off
if (msg->addr == MSG_SUBARU_PG_CruiseControl) {
bool cruise_engaged = (msg->data[6] >> 1) & 1U;
pcm_cruise_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 48U);
}
// enter controls on rising edge of ACC, exit controls on ACC off
if (msg_matches(msg, MSG_SUBARU_PG_CruiseControl, SUBARU_PG_MAIN_BUS)) {
bool cruise_engaged = (msg->data[6] >> 1) & 1U;
pcm_cruise_check(cruise_engaged);
acc_main_on = GET_BIT(msg, 48U);
}
// update vehicle moving with any non-zero wheel speed
if (msg->addr == MSG_SUBARU_PG_Wheel_Speeds) {
vehicle_moving = ((GET_BYTES(msg, 0, 4) >> 12) != 0U) || (GET_BYTES(msg, 4, 4) != 0U);
}
// update vehicle moving with any non-zero wheel speed
if (msg_matches(msg, MSG_SUBARU_PG_Wheel_Speeds, SUBARU_PG_MAIN_BUS)) {
vehicle_moving = ((GET_BYTES_LE(msg, 0, 4) >> 12) | GET_BYTES_LE(msg, 4, 4)) != 0U;
}
if (msg->addr == MSG_SUBARU_PG_Brake_Pedal) {
brake_pressed = ((GET_BYTES(msg, 0, 4) >> 16) & 0xFFU) > 0U;
}
if (msg_matches(msg, MSG_SUBARU_PG_Brake_Pedal, SUBARU_PG_MAIN_BUS)) {
brake_pressed = ((GET_BYTES_LE(msg, 0, 4) >> 16) & 0xFFU) > 0U;
}
if (msg->addr == MSG_SUBARU_PG_Throttle) {
gas_pressed = msg->data[0] != 0U;
}
if (msg_matches(msg, MSG_SUBARU_PG_Throttle, SUBARU_PG_MAIN_BUS)) {
gas_pressed = msg->data[0] != 0U;
}
}
@@ -75,7 +73,7 @@ static bool subaru_preglobal_tx_hook(const CANPacket_t *msg) {
// steer cmd checks
if (msg->addr == MSG_SUBARU_PG_ES_LKAS) {
int desired_torque = ((GET_BYTES(msg, 0, 4) >> 8) & 0x1FFFU);
int desired_torque = ((GET_BYTES_LE(msg, 0, 4) >> 8) & 0x1FFFU);
desired_torque = -1 * to_signed(desired_torque, 13);
bool steer_req = (msg->data[3] >> 0) & 1U;
@@ -84,6 +82,7 @@ static bool subaru_preglobal_tx_hook(const CANPacket_t *msg) {
tx = false;
}
}
return tx;
}
@@ -99,7 +98,7 @@ static safety_config subaru_preglobal_init(uint16_t param) {
// TODO: do checksum and counter checks after adding the signals to the outback dbc file
static RxCheck subaru_preglobal_rx_checks[] = {
{.msg = {{MSG_SUBARU_PG_Throttle, SUBARU_PG_MAIN_BUS, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Throttle, SUBARU_PG_MAIN_BUS, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Steering_Torque, SUBARU_PG_MAIN_BUS, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_CruiseControl, SUBARU_PG_MAIN_BUS, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Wheel_Speeds, SUBARU_PG_MAIN_BUS, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+101 -107
View File
@@ -38,24 +38,26 @@ extern uint8_t tesla_mads_screen_button_fingers;
uint8_t tesla_mads_screen_button_fingers = 0U;
static uint8_t tesla_get_counter(const CANPacket_t *msg) {
uint8_t cnt = 0;
if (msg->addr == 0x2b9U) {
// Signal: DAS_controlCounter
cnt = msg->data[6] >> 5;
} else if (msg->addr == 0x488U) {
}
if (msg->addr == 0x488U) {
// Signal: DAS_steeringControlCounter
cnt = msg->data[2] & 0x0FU;
} else if ((msg->addr == 0x257U) || (msg->addr == 0x118U) || (msg->addr == 0x145U) || (msg->addr == 0x286U) || (msg->addr == 0x311U)) {
}
if ((msg->addr == 0x257U) || (msg->addr == 0x118U) || (msg->addr == 0x145U) || (msg->addr == 0x286U) || (msg->addr == 0x311U)) {
// Signal: DI_speedCounter, DI_systemStatusCounter, ESP_statusCounter, DI_locStatusCounter, UI_warningCounter
cnt = msg->data[1] & 0x0FU;
} else if (msg->addr == 0x155U) {
}
if (msg->addr == 0x155U) {
// Signal: ESP_wheelRotationCounter
cnt = msg->data[6] >> 4;
} else if (msg->addr == 0x370U) {
}
if (msg->addr == 0x370U) {
// Signal: EPAS3S_sysStatusCounter
cnt = msg->data[6] & 0x0FU;
} else {
}
return cnt;
}
@@ -65,13 +67,14 @@ static int _tesla_get_checksum_byte(const int addr) {
if ((addr == 0x370) || (addr == 0x2b9) || (addr == 0x155)) {
// Signal: EPAS3S_sysStatusChecksum, DAS_controlChecksum, ESP_wheelRotationChecksum
checksum_byte = 7;
} else if (addr == 0x488) {
}
if (addr == 0x488) {
// Signal: DAS_steeringControlChecksum
checksum_byte = 3;
} else if ((addr == 0x257) || (addr == 0x118) || (addr == 0x145) || (addr == 0x286) || (addr == 0x311)) {
}
if ((addr == 0x257) || (addr == 0x118) || (addr == 0x145) || (addr == 0x286) || (addr == 0x311)) {
// Signal: DI_speedChecksum, DI_systemStatusChecksum, ESP_statusChecksum, DI_locStatusChecksum, UI_warningChecksum
checksum_byte = 0;
} else {
}
return checksum_byte;
}
@@ -102,14 +105,13 @@ static uint32_t tesla_compute_checksum(const CANPacket_t *msg) {
}
static bool tesla_get_quality_flag_valid(const CANPacket_t *msg) {
bool valid = false;
if (msg->addr == 0x155U) {
valid = (msg->data[5] & 0x1U) == 0x1U; // ESP_wheelSpeedsQF
} else if (msg->addr == 0x145U) {
}
if (msg->addr == 0x145U) {
int user_brake_status = (msg->data[3] >> 5) & 0x03U;
valid = (user_brake_status != 0) && (user_brake_status != 3); // ESP_driverBrakeApply=NotInit_orOff, Faulty_SNA
} else {
}
return valid;
}
@@ -129,113 +131,105 @@ static int tesla_get_steer_ctrl_type(const int ctrl_type) {
}
static void tesla_rx_hook(const CANPacket_t *msg) {
// Steering angle: (0.1 * val) - 819.2 in deg.
if (msg_matches(msg, 0x370U, 0U)) {
// Store it 1/10 deg to match steering request
const int angle_meas_new = (((msg->data[4] & 0x3FU) << 8) | msg->data[5]) - 8192U;
update_sample(&angle_meas, angle_meas_new);
if (msg->bus == 0U) {
// Steering angle: (0.1 * val) - 819.2 in deg.
if (msg->addr == 0x370U) {
// Store it 1/10 deg to match steering request
const int angle_meas_new = (((msg->data[4] & 0x3FU) << 8) | msg->data[5]) - 8192U;
update_sample(&angle_meas, angle_meas_new);
const int hands_on_level = msg->data[4] >> 6; // EPAS3S_handsOnLevel
const int eac_status = msg->data[6] >> 5; // EPAS3S_eacStatus
const int eac_error_code = msg->data[2] >> 4; // EPAS3S_eacErrorCode
const int hands_on_level = msg->data[4] >> 6; // EPAS3S_handsOnLevel
const int eac_status = msg->data[6] >> 5; // EPAS3S_eacStatus
const int eac_error_code = msg->data[2] >> 4; // EPAS3S_eacErrorCode
// Disengage on normal user override, or if high angle rate fault from user overriding extremely quickly
steering_disengage = (hands_on_level >= 3) || ((eac_status == 0) && (eac_error_code == 9));
}
// Disengage on normal user override, or if high angle rate fault from user overriding extremely quickly
steering_disengage = (hands_on_level >= 3) || ((eac_status == 0) && (eac_error_code == 9));
}
// Vehicle speed (DI_speed)
if (msg->addr == 0x257U) {
// Vehicle speed: ((val * 0.08) - 40) / MS_TO_KPH
float speed = ((((msg->data[2] << 4) | (msg->data[1] >> 4)) * 0.08) - 40.) * KPH_TO_MS;
UPDATE_VEHICLE_SPEED(speed);
}
// 2nd vehicle speed (ESP_B)
if (msg->addr == 0x155U) {
// Disable controls if speeds from DI (Drive Inverter) and ESP ECUs are too far apart.
float esp_speed = (((msg->data[6] & 0x0FU) << 6) | (msg->data[5] >> 2)) * 0.5 * KPH_TO_MS;
speed_mismatch_check(esp_speed);
}
// Gas pressed
if (msg->addr == 0x118U) {
gas_pressed = (msg->data[4] != 0U);
}
// Brake pressed
if (msg->addr == 0x145U) {
brake_pressed = ((msg->data[3] >> 5) & 0x03U) == 2U;
}
// Cruise and Autopark/Summon state
if (msg->addr == 0x286U) {
// Autopark state
int autopark_state = (msg->data[3] >> 1) & 0x0FU; // DI_autoparkState
bool tesla_autopark_now = (autopark_state == 3) || // ACTIVE
(autopark_state == 4) || // COMPLETE
(autopark_state == 9); // SELFPARK_STARTED
// Only consider rising edges while controls are not allowed
if (tesla_autopark_now && !tesla_autopark_prev && !cruise_engaged_prev) {
tesla_autopark = true;
}
if (!tesla_autopark_now) {
tesla_autopark = false;
}
tesla_autopark_prev = tesla_autopark_now;
// Cruise state
int cruise_state = (msg->data[1] >> 4) & 0x07U;
bool cruise_engaged = (cruise_state == 2) || // ENABLED
(cruise_state == 3) || // STANDSTILL
(cruise_state == 4) || // OVERRIDE
(cruise_state == 6) || // PRE_FAULT
(cruise_state == 7); // PRE_CANCEL
cruise_engaged = cruise_engaged && !tesla_autopark;
pcm_cruise_check(cruise_engaged);
}
if (msg->addr == 0x155U) {
vehicle_moving = !GET_BIT(msg, 41U); // ESP_vehicleStandstillSts
if (msg_matches(msg, 0x3DFU, 1U)) {
if (tesla_mads_screen_button_fingers != 0U) {
mads_button_press = (msg->data[3] == tesla_mads_screen_button_fingers) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
}
if (msg->bus == 1U) {
if (msg->addr == 0x3DFU) {
if (tesla_mads_screen_button_fingers != 0U) {
mads_button_press = (msg->data[3] == tesla_mads_screen_button_fingers) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
}
// Vehicle speed (DI_speed)
if (msg_matches(msg, 0x257U, 0U)) {
// Vehicle speed: ((val * 0.08) - 40) / MS_TO_KPH
float speed = ((((msg->data[2] << 4) | (msg->data[1] >> 4)) * 0.08) - 40.) * KPH_TO_MS;
UPDATE_VEHICLE_SPEED(speed);
}
if (msg->bus == 2U) {
// DAS_control
if (msg->addr == 0x2b9U) {
// "AEB_ACTIVE"
tesla_stock_aeb = (msg->data[2] & 0x03U) == 1U;
}
// 2nd vehicle speed (ESP_B)
if (msg_matches(msg, 0x155U, 0U)) {
// Disable controls if speeds from DI (Drive Inverter) and ESP ECUs are too far apart.
float esp_speed = (((msg->data[6] & 0x0FU) << 6) | (msg->data[5] >> 2)) * 0.5 * KPH_TO_MS;
speed_mismatch_check(esp_speed);
}
// DAS_steeringControl
if (msg->addr == 0x488U) {
int steering_control_type = msg->data[2] >> 6;
bool tesla_stock_lkas_now = steering_control_type == tesla_get_steer_ctrl_type(2); // "LANE_KEEP_ASSIST"
// Gas pressed
if (msg_matches(msg, 0x118U, 0U)) {
gas_pressed = (msg->data[4] != 0U);
}
// Only consider rising edges while controls are not allowed
if (tesla_stock_lkas_now && !tesla_stock_lkas_prev && !(controls_allowed || controls_allowed_lateral)) {
tesla_stock_lkas = true;
}
if (!tesla_stock_lkas_now) {
tesla_stock_lkas = false;
}
tesla_stock_lkas_prev = tesla_stock_lkas_now;
// Brake pressed
if (msg_matches(msg, 0x145U, 0U)) {
brake_pressed = ((msg->data[3] >> 5) & 0x03U) == 2U;
}
// Cruise and Autopark/Summon state
if (msg_matches(msg, 0x286U, 0U)) {
// Autopark state
int autopark_state = (msg->data[3] >> 1) & 0x0FU; // DI_autoparkState
bool tesla_autopark_now = (autopark_state == 3) || // ACTIVE
(autopark_state == 4) || // COMPLETE
(autopark_state == 9); // SELFPARK_STARTED
// Only consider rising edges while controls are not allowed
if (tesla_autopark_now && !tesla_autopark_prev && !cruise_engaged_prev) {
tesla_autopark = true;
}
if (!tesla_autopark_now) {
tesla_autopark = false;
}
tesla_autopark_prev = tesla_autopark_now;
// Cruise state
int cruise_state = (msg->data[1] >> 4) & 0x07U;
bool cruise_engaged = (cruise_state == 2) || // ENABLED
(cruise_state == 3) || // STANDSTILL
(cruise_state == 4) || // OVERRIDE
(cruise_state == 6) || // PRE_FAULT
(cruise_state == 7); // PRE_CANCEL
cruise_engaged = cruise_engaged && !tesla_autopark;
pcm_cruise_check(cruise_engaged);
}
if (msg_matches(msg, 0x155U, 0U)) {
vehicle_moving = !GET_BIT(msg, 41U); // ESP_vehicleStandstillSts
}
// DAS_control
if (msg_matches(msg, 0x2b9U, 2U)) {
// "AEB_ACTIVE"
tesla_stock_aeb = (msg->data[2] & 0x03U) == 1U;
}
// DAS_steeringControl
if (msg_matches(msg, 0x488U, 2U)) {
int steering_control_type = msg->data[2] >> 5; // DAS_steeringControlType
bool tesla_stock_lkas_now = steering_control_type == tesla_get_steer_ctrl_type(2); // "LANE_KEEP_ASSIST"
// Only consider rising edges while controls are not allowed
if (tesla_stock_lkas_now && !tesla_stock_lkas_prev && !(controls_allowed || controls_allowed_lateral)) {
tesla_stock_lkas = true;
}
if (!tesla_stock_lkas_now) {
tesla_stock_lkas = false;
}
tesla_stock_lkas_prev = tesla_stock_lkas_now;
}
}
static bool tesla_tx_hook(const CANPacket_t *msg) {
const AngleSteeringLimits TESLA_STEERING_LIMITS = {
.max_angle = 3600, // 360 deg, EPAS faults above this
@@ -269,7 +263,7 @@ static bool tesla_tx_hook(const CANPacket_t *msg) {
// We use 1/10 deg as a unit here
int raw_angle_can = ((msg->data[0] & 0x7FU) << 8) | msg->data[1];
int desired_angle = raw_angle_can - 16384;
int steer_control_type = msg->data[2] >> 6;
int steer_control_type = msg->data[2] >> 5;
const int angle_ctrl_type = tesla_get_steer_ctrl_type(1);
const int lkas_ctrl_type = tesla_get_steer_ctrl_type(2);
bool steer_control_enabled = (steer_control_type == angle_ctrl_type) || // ANGLE_CONTROL
@@ -364,7 +358,6 @@ static bool tesla_fwd_hook(int bus_num, int addr) {
}
static safety_config tesla_init(uint16_t param) {
static const CanMsg TESLA_M3_Y_TX_MSGS[] = {
{0x488, 0, 4, .check_relay = true, .disable_static_blocking = true}, // DAS_steeringControl
{0x2b9, 0, 8, .check_relay = false}, // DAS_control (for cancel)
@@ -380,6 +373,7 @@ static safety_config tesla_init(uint16_t param) {
const uint16_t TESLA_FLAG_FSD_14 = 2;
tesla_fsd_14 = GET_FLAG(param, TESLA_FLAG_FSD_14);
SAFETY_UNUSED(param);
#ifdef ALLOW_DEBUG
const uint16_t TESLA_FLAG_LONGITUDINAL_CONTROL = 1;
tesla_longitudinal = GET_FLAG(param, TESLA_FLAG_LONGITUDINAL_CONTROL);
+195 -200
View File
@@ -89,7 +89,8 @@ static bool toyota_get_quality_flag_valid(const CANPacket_t *msg) {
bool valid = false;
if (msg->addr == 0x260U) {
valid = !GET_BIT(msg, 3U); // STEER_TORQUE_SENSOR.STEER_ANGLE_INITIALIZING
} else if (msg->addr == 0xaaU) { // WHEEL_SPEEDS
}
if (msg->addr == 0xaaU) { // WHEEL_SPEEDS
// each wheel speed is 1-bit fault + 15-bit speed
valid = true;
for (uint8_t i = 0U; i < 4U; i += 1U) {
@@ -98,7 +99,6 @@ static bool toyota_get_quality_flag_valid(const CANPacket_t *msg) {
break;
}
}
} else {
}
return valid;
}
@@ -112,103 +112,100 @@ static int TOYOTA_GET_INTERCEPTOR(const CANPacket_t *msg) {
}
static void toyota_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// get eps motor torque (0.66 factor in dbc)
if (msg_matches(msg, 0x260U, 0U)) {
int torque_meas_new = (msg->data[5] << 8) | msg->data[6];
torque_meas_new = to_signed(torque_meas_new, 16);
// get eps motor torque (0.66 factor in dbc)
if (msg->addr == 0x260U) {
int torque_meas_new = (msg->data[5] << 8) | msg->data[6];
torque_meas_new = to_signed(torque_meas_new, 16);
// scale by dbc_factor
torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100;
// scale by dbc_factor
torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100;
// update array of sample
update_sample(&torque_meas, torque_meas_new);
// update array of sample
update_sample(&torque_meas, torque_meas_new);
// increase torque_meas by 1 to be conservative on rounding
torque_meas.min--;
torque_meas.max++;
// increase torque_meas by 1 to be conservative on rounding
torque_meas.min--;
torque_meas.max++;
// driver torque for angle limiting
int torque_driver_new = (msg->data[1] << 8) | msg->data[2];
torque_driver_new = to_signed(torque_driver_new, 16);
update_sample(&torque_driver, torque_driver_new);
// driver torque for angle limiting
int torque_driver_new = (msg->data[1] << 8) | msg->data[2];
torque_driver_new = to_signed(torque_driver_new, 16);
update_sample(&torque_driver, torque_driver_new);
// LTA request angle should match current angle while inactive, clipped to max accepted angle.
// note that angle can be relative to init angle on some TSS2 platforms, LTA has the same offset
bool steer_angle_initializing = GET_BIT(msg, 3U);
if (!steer_angle_initializing) {
int angle_meas_new = (msg->data[3] << 8U) | msg->data[4];
angle_meas_new = to_signed(angle_meas_new, 16);
update_sample(&angle_meas, angle_meas_new);
}
}
// LTA request angle should match current angle while inactive, clipped to max accepted angle.
// note that angle can be relative to init angle on some TSS2 platforms, LTA has the same offset
bool steer_angle_initializing = GET_BIT(msg, 3U);
if (!steer_angle_initializing) {
int angle_meas_new = (msg->data[3] << 8U) | msg->data[4];
angle_meas_new = to_signed(angle_meas_new, 16);
update_sample(&angle_meas, angle_meas_new);
// enter controls on rising edge of ACC, exit controls on ACC off
// exit controls on rising edge of gas press, if not alternative experience
// exit controls on rising edge of brake press
if (toyota_secoc) {
if (msg_matches(msg, 0x176U, 0U)) {
bool cruise_engaged = GET_BIT(msg, 5U); // PCM_CRUISE.CRUISE_ACTIVE
pcm_cruise_check(cruise_engaged);
}
if (msg_matches(msg, 0x116U, 0U)) {
gas_pressed = msg->data[1] != 0U; // GAS_PEDAL.GAS_PEDAL_USER
}
if (msg_matches(msg, 0x101U, 0U)) {
brake_pressed = GET_BIT(msg, 3U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_rav4_prime_generated.dbc)
}
} else {
if (msg_matches(msg, 0x1D2U, 0U)) {
bool cruise_engaged = GET_BIT(msg, 5U); // PCM_CRUISE.CRUISE_ACTIVE
pcm_cruise_check(cruise_engaged);
if (!enable_gas_interceptor) {
gas_pressed = !GET_BIT(msg, 4U); // PCM_CRUISE.GAS_RELEASED
}
}
// enter controls on rising edge of ACC, exit controls on ACC off
// exit controls on rising edge of gas press, if not alternative experience
// exit controls on rising edge of brake press
if (toyota_secoc) {
if (msg->addr == 0x176U) {
bool cruise_engaged = GET_BIT(msg, 5U); // PCM_CRUISE.CRUISE_ACTIVE
pcm_cruise_check(cruise_engaged);
}
if (msg->addr == 0x116U) {
gas_pressed = msg->data[1] != 0U; // GAS_PEDAL.GAS_PEDAL_USER
}
if (msg->addr == 0x101U) {
brake_pressed = GET_BIT(msg, 3U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_rav4_prime_generated.dbc)
}
} else {
if (msg->addr == 0x1D2U) {
bool cruise_engaged = GET_BIT(msg, 5U); // PCM_CRUISE.CRUISE_ACTIVE
pcm_cruise_check(cruise_engaged);
if (!enable_gas_interceptor) {
gas_pressed = !GET_BIT(msg, 4U); // PCM_CRUISE.GAS_RELEASED
}
}
if (!toyota_alt_brake && (msg->addr == 0x226U)) {
brake_pressed = GET_BIT(msg, 37U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_nodsu_pt_generated.dbc)
}
if (toyota_alt_brake && (msg->addr == 0x224U)) {
brake_pressed = GET_BIT(msg, 5U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_new_mc_pt_generated.dbc)
}
if (!toyota_alt_brake && msg_matches(msg, 0x226U, 0U)) {
brake_pressed = GET_BIT(msg, 37U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_nodsu_pt_generated.dbc)
}
// sample speed
if (msg->addr == 0xaaU) {
int speed = 0;
// sum 4 wheel speeds. conversion: raw * 0.01 - 67.67
for (uint8_t i = 0U; i < 8U; i += 2U) {
int wheel_speed = ((msg->data[i] & 0x7FU) << 8U) | msg->data[(i + 1U)];
speed += wheel_speed - 6767;
}
// check that all wheel speeds are at zero value
vehicle_moving = speed != 0;
UPDATE_VEHICLE_SPEED(speed / 4.0 * 0.01 * KPH_TO_MS);
if (toyota_alt_brake && msg_matches(msg, 0x224U, 0U)) {
brake_pressed = GET_BIT(msg, 5U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_new_mc_pt_generated.dbc)
}
}
if (msg->addr == 0x1D3U) {
acc_main_on = GET_BIT(msg, 15U);
if (msg_matches(msg, 0x1D3U, 0U)) {
acc_main_on = GET_BIT(msg, 15U);
}
if (msg_matches(msg, 0x365U, 0U)) {
acc_main_on = GET_BIT(msg, 0U);
}
// sample gas interceptor
if (msg_matches(msg, 0x201U, 0U)) {
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
// Threshold calculated from DBC gains: round((((15 + 75.555) / 0.159375) + ((15 + 151.111) / 0.159375)) / 2) = 805
const int toyota_gas_interceptor_thrsld = 805;
int gas_interceptor = TOYOTA_GET_INTERCEPTOR(msg);
gas_pressed = gas_interceptor > toyota_gas_interceptor_thrsld;
gas_interceptor_prev = gas_interceptor;
}
// sample speed
if (msg_matches(msg, 0xaaU, 0U)) {
int speed = 0;
// sum 4 wheel speeds. conversion: raw * 0.01 - 67.67
for (uint8_t i = 0U; i < 8U; i += 2U) {
int wheel_speed = ((msg->data[i] & 0x7FU) << 8U) | msg->data[(i + 1U)];
speed += wheel_speed - 6767;
}
// check that all wheel speeds are at zero value
vehicle_moving = speed != 0;
if (msg->addr == 0x365U) {
acc_main_on = GET_BIT(msg, 0U);
}
// sample gas interceptor
if (msg->addr == 0x201U) {
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
// Threshold calculated from DBC gains: round((((15 + 75.555) / 0.159375) + ((15 + 151.111) / 0.159375)) / 2) = 805
const int toyota_gas_interceptor_thrsld = 805;
int gas_interceptor = TOYOTA_GET_INTERCEPTOR(msg);
gas_pressed = gas_interceptor > toyota_gas_interceptor_thrsld;
gas_interceptor_prev = gas_interceptor;
}
UPDATE_VEHICLE_SPEED(speed / 4.0 * 0.01 * KPH_TO_MS);
}
}
@@ -256,142 +253,140 @@ static bool toyota_tx_hook(const CANPacket_t *msg) {
bool tx = true;
// Check if msg is sent on BUS 0
if (msg->bus == 0U) {
// ACCEL: safety check on byte 1-2
if (msg->addr == 0x343U) {
int desired_accel = (msg->data[0] << 8) | msg->data[1];
desired_accel = to_signed(desired_accel, 16);
// ACCEL: safety check on byte 1-2
if (msg_matches(msg, 0x343U, 0U)) {
int desired_accel = (msg->data[0] << 8) | msg->data[1];
desired_accel = to_signed(desired_accel, 16);
bool violation = false;
if (toyota_secoc) {
// SecOC cars move accel to 0x183. Only allow inactive accel on 0x343 to match stock behavior
violation = desired_accel != TOYOTA_LONG_LIMITS.inactive_accel;
bool violation = false;
if (toyota_secoc) {
// SecOC cars move accel to 0x183. Only allow inactive accel on 0x343 to match stock behavior
violation = desired_accel != TOYOTA_LONG_LIMITS.inactive_accel;
}
violation |= longitudinal_accel_checks(desired_accel, TOYOTA_LONG_LIMITS);
// only ACC messages that cancel are allowed when openpilot is not controlling longitudinal
if (toyota_stock_longitudinal) {
bool cancel_req = GET_BIT(msg, 24U);
if (!cancel_req) {
violation = true;
}
violation |= longitudinal_accel_checks(desired_accel, TOYOTA_LONG_LIMITS);
if (desired_accel != TOYOTA_LONG_LIMITS.inactive_accel) {
violation = true;
}
}
// only ACC messages that cancel are allowed when openpilot is not controlling longitudinal
if (toyota_stock_longitudinal) {
bool cancel_req = GET_BIT(msg, 24U);
if (!cancel_req) {
violation = true;
}
if (desired_accel != TOYOTA_LONG_LIMITS.inactive_accel) {
violation = true;
}
if (violation) {
tx = false;
}
}
if (msg_matches(msg, 0x183U, 0U)) {
int desired_accel = (msg->data[0] << 8) | msg->data[1];
desired_accel = to_signed(desired_accel, 16);
tx = !longitudinal_accel_checks(desired_accel, TOYOTA_LONG_LIMITS);
}
// AEB: block all actuation. only used when DSU is unplugged
if (msg_matches(msg, 0x283U, 0U)) {
// only allow the checksum, which is the last byte
bool block = GET_BYTES_64_LE(msg, 0, 6) != 0U;
if (block) {
tx = false;
}
}
// STEERING_LTA angle steering check
if (msg_matches(msg, 0x191U, 0U)) {
// check the STEER_REQUEST, STEER_REQUEST_2, TORQUE_WIND_DOWN, STEER_ANGLE_CMD signals
bool lta_request = GET_BIT(msg, 0U);
bool lta_request2 = GET_BIT(msg, 25U);
int torque_wind_down = msg->data[5];
int lta_angle = (msg->data[1] << 8) | msg->data[2];
lta_angle = to_signed(lta_angle, 16);
bool steer_control_enabled = lta_request || lta_request2;
if (!toyota_lta) {
// using torque (LKA), block LTA msgs with actuation requests
if (steer_control_enabled || (lta_angle != 0) || (torque_wind_down != 0)) {
tx = false;
}
} else {
// check angle rate limits and inactive angle
if (steer_angle_cmd_checks(lta_angle, steer_control_enabled, TOYOTA_ANGLE_STEERING_LIMITS)) {
tx = false;
}
if (violation) {
if (lta_request != lta_request2) {
tx = false;
}
// TORQUE_WIND_DOWN is gated on steer request
if (!steer_control_enabled && (torque_wind_down != 0)) {
tx = false;
}
// TORQUE_WIND_DOWN can only be no or full torque
if ((torque_wind_down != 0) && (torque_wind_down != 100)) {
tx = false;
}
// check if we should wind down torque
int driver_torque = SAFETY_MIN(SAFETY_ABS(torque_driver.min), SAFETY_ABS(torque_driver.max));
if ((driver_torque > TOYOTA_LTA_MAX_DRIVER_TORQUE) && (torque_wind_down != 0)) {
tx = false;
}
int eps_torque = SAFETY_MIN(SAFETY_ABS(torque_meas.min), SAFETY_ABS(torque_meas.max));
if ((eps_torque > TOYOTA_LTA_MAX_MEAS_TORQUE) && (torque_wind_down != 0)) {
tx = false;
}
}
}
if (msg->addr == 0x183U) {
int desired_accel = (msg->data[0] << 8) | msg->data[1];
desired_accel = to_signed(desired_accel, 16);
// STEERING_LTA_2 angle steering check (SecOC)
if (toyota_secoc && msg_matches(msg, 0x131U, 0U)) {
// SecOC cars block any form of LTA actuation for now
bool lta_request = GET_BIT(msg, 3U); // STEERING_LTA_2.STEER_REQUEST
bool lta_request2 = GET_BIT(msg, 0U); // STEERING_LTA_2.STEER_REQUEST_2
int lta_angle_msb = msg->data[2]; // STEERING_LTA_2.STEER_ANGLE_CMD (MSB)
int lta_angle_lsb = msg->data[3]; // STEERING_LTA_2.STEER_ANGLE_CMD (LSB)
tx = !longitudinal_accel_checks(desired_accel, TOYOTA_LONG_LIMITS);
bool actuation = lta_request || lta_request2 || (lta_angle_msb != 0) || (lta_angle_lsb != 0);
if (actuation) {
tx = false;
}
}
// AEB: block all actuation. only used when DSU is unplugged
if (msg->addr == 0x283U) {
// only allow the checksum, which is the last byte
bool block = (GET_BYTES(msg, 0, 4) != 0U) || (msg->data[4] != 0U) || (msg->data[5] != 0U);
if (block) {
// STEER: safety check on bytes 2-3
if (msg_matches(msg, 0x2E4U, 0U)) {
int desired_torque = (msg->data[1] << 8) | msg->data[2];
desired_torque = to_signed(desired_torque, 16);
bool steer_req = GET_BIT(msg, 0U);
// When using LTA (angle control), assert no actuation on LKA message
if (!toyota_lta) {
if (steer_torque_cmd_checks(desired_torque, steer_req, TOYOTA_TORQUE_STEERING_LIMITS)) {
tx = false;
}
} else {
if ((desired_torque != 0) || steer_req) {
tx = false;
}
}
}
// STEERING_LTA angle steering check
if (msg->addr == 0x191U) {
// check the STEER_REQUEST, STEER_REQUEST_2, TORQUE_WIND_DOWN, STEER_ANGLE_CMD signals
bool lta_request = GET_BIT(msg, 0U);
bool lta_request2 = GET_BIT(msg, 25U);
int torque_wind_down = msg->data[5];
int lta_angle = (msg->data[1] << 8) | msg->data[2];
lta_angle = to_signed(lta_angle, 16);
bool steer_control_enabled = lta_request || lta_request2;
if (!toyota_lta) {
// using torque (LKA), block LTA msgs with actuation requests
if (steer_control_enabled || (lta_angle != 0) || (torque_wind_down != 0)) {
tx = false;
}
} else {
// check angle rate limits and inactive angle
if (steer_angle_cmd_checks(lta_angle, steer_control_enabled, TOYOTA_ANGLE_STEERING_LIMITS)) {
tx = false;
}
if (lta_request != lta_request2) {
tx = false;
}
// TORQUE_WIND_DOWN is gated on steer request
if (!steer_control_enabled && (torque_wind_down != 0)) {
tx = false;
}
// TORQUE_WIND_DOWN can only be no or full torque
if ((torque_wind_down != 0) && (torque_wind_down != 100)) {
tx = false;
}
// check if we should wind down torque
int driver_torque = SAFETY_MIN(SAFETY_ABS(torque_driver.min), SAFETY_ABS(torque_driver.max));
if ((driver_torque > TOYOTA_LTA_MAX_DRIVER_TORQUE) && (torque_wind_down != 0)) {
tx = false;
}
int eps_torque = SAFETY_MIN(SAFETY_ABS(torque_meas.min), SAFETY_ABS(torque_meas.max));
if ((eps_torque > TOYOTA_LTA_MAX_MEAS_TORQUE) && (torque_wind_down != 0)) {
tx = false;
}
}
}
// STEERING_LTA_2 angle steering check (SecOC)
if (toyota_secoc && (msg->addr == 0x131U)) {
// SecOC cars block any form of LTA actuation for now
bool lta_request = GET_BIT(msg, 3U); // STEERING_LTA_2.STEER_REQUEST
bool lta_request2 = GET_BIT(msg, 0U); // STEERING_LTA_2.STEER_REQUEST_2
int lta_angle_msb = msg->data[2]; // STEERING_LTA_2.STEER_ANGLE_CMD (MSB)
int lta_angle_lsb = msg->data[3]; // STEERING_LTA_2.STEER_ANGLE_CMD (LSB)
bool actuation = lta_request || lta_request2 || (lta_angle_msb != 0) || (lta_angle_lsb != 0);
if (actuation) {
tx = false;
}
}
// STEER: safety check on bytes 2-3
if (msg->addr == 0x2E4U) {
int desired_torque = (msg->data[1] << 8) | msg->data[2];
desired_torque = to_signed(desired_torque, 16);
bool steer_req = GET_BIT(msg, 0U);
// When using LTA (angle control), assert no actuation on LKA message
if (!toyota_lta) {
if (steer_torque_cmd_checks(desired_torque, steer_req, TOYOTA_TORQUE_STEERING_LIMITS)) {
tx = false;
}
} else {
if ((desired_torque != 0) || steer_req) {
tx = false;
}
}
}
// GAS PEDAL: safety check
if (msg->addr == 0x200U) {
if (longitudinal_interceptor_checks(msg)) {
tx = false;
}
// GAS PEDAL: safety check (gas interceptor)
if (msg_matches(msg, 0x200U, 0U)) {
if (longitudinal_interceptor_checks(msg)) {
tx = false;
}
}
// UDS: Only tester present ("\x0F\x02\x3E\x00\x00\x00\x00\x00") allowed on diagnostics address
if (msg->addr == 0x750U) {
// this address is sub-addressed. only allow tester present to radar (0xF)
bool invalid_uds_msg = (GET_BYTES(msg, 0, 4) != 0x003E020FU) || (GET_BYTES(msg, 4, 4) != 0x0U);
bool invalid_uds_msg = GET_BYTES_64_LE(msg, 0, 8) != 0x00000000003E020FULL;
if (invalid_uds_msg) {
tx = false;
}
@@ -3,7 +3,7 @@
extern const uint16_t FLAG_VOLKSWAGEN_LONG_CONTROL;
const uint16_t FLAG_VOLKSWAGEN_LONG_CONTROL = 1;
static uint8_t volkswagen_crc8_lut_8h2f[256]; // Static lookup table for CRC8 poly 0x2F, aka 8H2F/AUTOSAR
static uint8_t volkswagen_crc8_lut_8h2f[256]; // Static lookup table for CRC8 poly 0x2F, aka 8H2F/AUTOSAR
extern bool volkswagen_longitudinal;
bool volkswagen_longitudinal = false;
@@ -48,44 +48,45 @@ static void volkswagen_common_init(void) {
return;
}
static uint32_t volkswagen_mqb_meb_get_checksum(const CANPacket_t *msg) {
static uint32_t volkswagen_mxb_get_checksum(const CANPacket_t *msg) {
return (uint8_t)msg->data[0];
}
static uint8_t volkswagen_mqb_meb_get_counter(const CANPacket_t *msg) {
// MQB/MEB message counters are consistently found at LSB 8.
static uint8_t volkswagen_mxb_get_counter(const CANPacket_t *msg) {
// MQB/MLB/MEB message counters are consistently found at LSB 8.
return (uint8_t)msg->data[1] & 0xFU;
}
static uint32_t volkswagen_mqb_meb_compute_crc(const CANPacket_t *msg) {
int len = GET_LEN(msg);
// This is CRC-8H2F/AUTOSAR with a twist. See the opendbc/car/volkswagen/ implementation
// of this algorithm for a version with explanatory comments.
// This is CRC-8H2F/AUTOSAR with a counter-dependent data ID. See the
// opendbc/car/volkswagen/ implementation for explanatory comments.
static uint8_t volkswagen_compute_crc(const CANPacket_t *msg, int len, uint8_t salt) {
uint8_t crc = 0xFFU;
for (int i = 1; i < len; i++) {
crc ^= (uint8_t)msg->data[i];
crc = volkswagen_crc8_lut_8h2f[crc];
}
return volkswagen_crc8_lut_8h2f[crc ^ salt] ^ 0xFFU;
}
uint8_t counter = volkswagen_mqb_meb_get_counter(msg);
static uint32_t volkswagen_mxb_compute_crc(const CANPacket_t *msg) {
uint8_t salt = 0;
uint8_t counter = volkswagen_mxb_get_counter(msg);
if (msg->addr == MSG_LH_EPS_03) {
crc ^= (uint8_t[]){0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5}[counter];
} else if (msg->addr == MSG_ESP_05) {
crc ^= (uint8_t[]){0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07}[counter];
} else if (msg->addr == MSG_TSK_06) {
crc ^= (uint8_t[]){0xC4, 0xE2, 0x4F, 0xE4, 0xF8, 0x2F, 0x56, 0x81, 0x9F, 0xE5, 0x83, 0x44, 0x05, 0x3F, 0x97, 0xDF}[counter];
} else if (msg->addr == MSG_MOTOR_20) {
crc ^= (uint8_t[]){0xE9, 0x65, 0xAE, 0x6B, 0x7B, 0x35, 0xE5, 0x5F, 0x4E, 0xC7, 0x86, 0xA2, 0xBB, 0xDD, 0xEB, 0xB4}[counter];
} else if (msg->addr == MSG_GRA_ACC_01) {
crc ^= (uint8_t[]){0x6A, 0x38, 0xB4, 0x27, 0x22, 0xEF, 0xE1, 0xBB, 0xF8, 0x80, 0x84, 0x49, 0xC7, 0x9E, 0x1E, 0x2B}[counter];
} else {
// Undefined CAN message, CRC check expected to fail
salt = 0xF5U;
}
crc = volkswagen_crc8_lut_8h2f[crc];
return (uint8_t)(crc ^ 0xFFU);
if (msg->addr == MSG_ESP_05) {
salt = 0x07U;
}
if (msg->addr == MSG_TSK_06) {
salt = (uint8_t[]){0xC4, 0xE2, 0x4F, 0xE4, 0xF8, 0x2F, 0x56, 0x81, 0x9F, 0xE5, 0x83, 0x44, 0x05, 0x3F, 0x97, 0xDF}[counter];
}
if (msg->addr == MSG_MOTOR_20) {
salt = (uint8_t[]){0xE9, 0x65, 0xAE, 0x6B, 0x7B, 0x35, 0xE5, 0x5F, 0x4E, 0xC7, 0x86, 0xA2, 0xBB, 0xDD, 0xEB, 0xB4}[counter];
}
if (msg->addr == MSG_GRA_ACC_01) {
salt = (uint8_t[]){0x6A, 0x38, 0xB4, 0x27, 0x22, 0xEF, 0xE1, 0xBB, 0xF8, 0x80, 0x84, 0x49, 0xC7, 0x9E, 0x1E, 0x2B}[counter];
}
return volkswagen_compute_crc(msg, GET_LEN(msg), salt);
}
static int volkswagen_mlb_mqb_driver_input_torque(const CANPacket_t *msg) {
@@ -33,35 +33,30 @@ static bool volkswagen_meb_alt_crc = false;
{.msg = {{MSG_ESP_21, 0, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
static uint32_t volkswagen_meb_compute_crc(const CANPacket_t *msg) {
int len = GET_LEN(msg);
uint8_t crc = 0xFFU;
for (int i = 1; i < len; i++) {
crc ^= (uint8_t)msg->data[i];
crc = volkswagen_crc8_lut_8h2f[crc];
}
uint8_t counter = volkswagen_mqb_meb_get_counter(msg);
uint8_t salt = 0;
uint8_t counter = volkswagen_mxb_get_counter(msg);
if (msg->addr == MSG_LH_EPS_03) {
crc ^= (uint8_t[]){0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5}[counter];
} else if (msg->addr == MSG_MOTOR_14) {
crc ^= (uint8_t[]){0x1F, 0x28, 0xC6, 0x85, 0xE6, 0xF8, 0xB0, 0x19, 0x5B, 0x64, 0x35, 0x21, 0xE4, 0xF7, 0x9C, 0x24}[counter];
} else if (msg->addr == MSG_GRA_ACC_01) {
crc ^= (uint8_t[]){0x6A, 0x38, 0xB4, 0x27, 0x22, 0xEF, 0xE1, 0xBB, 0xF8, 0x80, 0x84, 0x49, 0xC7, 0x9E, 0x1E, 0x2B}[counter];
} else if (msg->addr == MSG_QFK_01) {
crc ^= (uint8_t[]){0x20, 0xCA, 0x68, 0xD5, 0x1B, 0x31, 0xE2, 0xDA, 0x08, 0x0A, 0xD4, 0xDE, 0x9C, 0xE4, 0x35, 0x5B}[counter];
} else if (msg->addr == MSG_ESC_51) {
crc ^= (uint8_t[]){0x77, 0x5C, 0xA0, 0x89, 0x4B, 0x7C, 0xBB, 0xD6, 0x1F, 0x6C, 0x4F, 0xF6, 0x20, 0x2B, 0x43, 0xDD}[counter];
} else if (msg->addr == MSG_ESP_21) {
crc ^= (uint8_t[]){0xB4, 0xEF, 0xF8, 0x49, 0x1E, 0xE5, 0xC2, 0xC0, 0x97, 0x19, 0x3C, 0xC9, 0xF1, 0x98, 0xD6, 0x61}[counter];
} else if (msg->addr == MSG_Motor_51) {
crc ^= (uint8_t[]){0x77, 0x5C, 0xA0, 0x89, 0x4B, 0x7C, 0xBB, 0xD6, 0x1F, 0x6C, 0x4F, 0xF6, 0x20, 0x2B, 0x43, 0xDD}[counter];
} else {
// Undefined CAN message, CRC check expected to fail
salt = 0xF5U;
}
crc = volkswagen_crc8_lut_8h2f[crc];
return (uint8_t)(crc ^ 0xFFU);
if (msg->addr == MSG_MOTOR_14) {
salt = (uint8_t[]){0x1F, 0x28, 0xC6, 0x85, 0xE6, 0xF8, 0xB0, 0x19, 0x5B, 0x64, 0x35, 0x21, 0xE4, 0xF7, 0x9C, 0x24}[counter];
}
if (msg->addr == MSG_GRA_ACC_01) {
salt = (uint8_t[]){0x6A, 0x38, 0xB4, 0x27, 0x22, 0xEF, 0xE1, 0xBB, 0xF8, 0x80, 0x84, 0x49, 0xC7, 0x9E, 0x1E, 0x2B}[counter];
}
if (msg->addr == MSG_QFK_01) {
salt = (uint8_t[]){0x20, 0xCA, 0x68, 0xD5, 0x1B, 0x31, 0xE2, 0xDA, 0x08, 0x0A, 0xD4, 0xDE, 0x9C, 0xE4, 0x35, 0x5B}[counter];
}
if (msg->addr == MSG_ESC_51) {
salt = (uint8_t[]){0x77, 0x5C, 0xA0, 0x89, 0x4B, 0x7C, 0xBB, 0xD6, 0x1F, 0x6C, 0x4F, 0xF6, 0x20, 0x2B, 0x43, 0xDD}[counter];
}
if (msg->addr == MSG_ESP_21) {
salt = (uint8_t[]){0xB4, 0xEF, 0xF8, 0x49, 0x1E, 0xE5, 0xC2, 0xC0, 0x97, 0x19, 0x3C, 0xC9, 0xF1, 0x98, 0xD6, 0x61}[counter];
}
if (msg->addr == MSG_Motor_51) {
salt = (uint8_t[]){0x77, 0x5C, 0xA0, 0x89, 0x4B, 0x7C, 0xBB, 0xD6, 0x1F, 0x6C, 0x4F, 0xF6, 0x20, 0x2B, 0x43, 0xDD}[counter];
}
return volkswagen_compute_crc(msg, GET_LEN(msg), salt);
}
static uint32_t volkswagen_meb_alt_crc_compute(const CANPacket_t *msg) {
@@ -70,34 +65,29 @@ static uint32_t volkswagen_meb_alt_crc_compute(const CANPacket_t *msg) {
if (volkswagen_meb_alt_crc) {
if (msg->addr == MSG_QFK_01) {
len = 28;
} else if (msg->addr == MSG_ESC_51) {
}
if (msg->addr == MSG_ESC_51) {
len = 60;
} else if (msg->addr == MSG_Motor_51) {
}
if (msg->addr == MSG_Motor_51) {
len = 44;
} else {
len = 0;
}
}
if (len > 0) {
uint8_t crc = 0xFFU;
for (int i = 1; i < len; i++) {
crc ^= (uint8_t)msg->data[i];
crc = volkswagen_crc8_lut_8h2f[crc];
}
uint8_t counter = volkswagen_mqb_meb_get_counter(msg);
uint8_t salt = 0;
uint8_t counter = volkswagen_mxb_get_counter(msg);
if (msg->addr == MSG_QFK_01) {
crc ^= (uint8_t[]){0x18, 0x71, 0x10, 0x8D, 0xD7, 0xAA, 0xB0, 0x78, 0xAC, 0x12, 0xAE, 0x0C, 0xDD, 0xF1, 0x85, 0x68}[counter];
} else if (msg->addr == MSG_ESC_51) {
crc ^= (uint8_t[]){0x69, 0xDC, 0xF9, 0x64, 0x6A, 0xCE, 0x55, 0x2C, 0xC4, 0x38, 0x8F, 0xD1, 0xC6, 0x43, 0xB4, 0xB1}[counter];
} else if (msg->addr == MSG_Motor_51) {
crc ^= (uint8_t[]){0x2C, 0xB1, 0x1A, 0x75, 0xBB, 0x65, 0x79, 0x47, 0x81, 0x2B, 0xCC, 0x96, 0x17, 0xDB, 0xC0, 0x94}[counter];
} else {
// Undefined CAN message, CRC check expected to fail
salt = (uint8_t[]){0x18, 0x71, 0x10, 0x8D, 0xD7, 0xAA, 0xB0, 0x78, 0xAC, 0x12, 0xAE, 0x0C, 0xDD, 0xF1, 0x85, 0x68}[counter];
}
if (msg->addr == MSG_ESC_51) {
salt = (uint8_t[]){0x69, 0xDC, 0xF9, 0x64, 0x6A, 0xCE, 0x55, 0x2C, 0xC4, 0x38, 0x8F, 0xD1, 0xC6, 0x43, 0xB4, 0xB1}[counter];
}
if (msg->addr == MSG_Motor_51) {
salt = (uint8_t[]){0x2C, 0xB1, 0x1A, 0x75, 0xBB, 0x65, 0x79, 0x47, 0x81, 0x2B, 0xCC, 0x96, 0x17, 0xDB, 0xC0, 0x94}[counter];
}
crc = (uint8_t)(volkswagen_crc8_lut_8h2f[crc] ^ 0xFFU);
uint8_t crc = volkswagen_compute_crc(msg, len, salt);
if (crc == msg->data[0]) {
ret = crc;
}
@@ -142,68 +132,66 @@ static safety_config volkswagen_meb_init(uint16_t param) {
}
static void volkswagen_meb_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Update in-motion state by sampling wheel speeds
if (msg->addr == MSG_ESC_51) {
uint32_t fl = msg->data[8] | (msg->data[9] << 8);
uint32_t fr = msg->data[10] | (msg->data[11] << 8);
uint32_t rl = msg->data[12] | (msg->data[13] << 8);
uint32_t rr = msg->data[14] | (msg->data[15] << 8);
vehicle_moving = (fr > 0U) || (rr > 0U) || (rl > 0U) || (fl > 0U);
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.0075 * KPH_TO_MS);
// Update in-motion state by sampling wheel speeds
if (msg_matches(msg, MSG_ESC_51, 0U)) {
uint32_t fl = msg->data[8] | (msg->data[9] << 8);
uint32_t fr = msg->data[10] | (msg->data[11] << 8);
uint32_t rl = msg->data[12] | (msg->data[13] << 8);
uint32_t rr = msg->data[14] | (msg->data[15] << 8);
vehicle_moving = (fr | rr | rl | fl) != 0U;
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.0075 * KPH_TO_MS);
}
// Check vehicle speed with redundant source
if (msg_matches(msg, MSG_ESP_21, 0U)) {
// Signal: ESP_v_Signal
float esp_speed = ((msg->data[5] << 8) | msg->data[4]) * 0.01 * KPH_TO_MS;
UPDATE_VEHICLE_SPEED_2(esp_speed);
}
if (msg_matches(msg, MSG_QFK_01, 0U)) {
int current_curvature = ((msg->data[6] & 0x7FU) << 8) | msg->data[5];
current_curvature *= GET_BIT(msg, 55U) ? 1 : -1;
update_sample(&curvature_state.meas, current_curvature);
}
if (msg_matches(msg, MSG_LH_EPS_03, 0U)) {
update_sample(&torque_driver, volkswagen_mlb_mqb_driver_input_torque(msg));
}
if (msg_matches(msg, MSG_Motor_51, 0U)) {
int acc_status = (msg->data[11] & 0x07U);
bool cruise_engaged = (acc_status == 3) || (acc_status == 4) || (acc_status == 5);
acc_main_on = cruise_engaged || (acc_status == 2);
if (!acc_main_on) {
controls_allowed = false;
}
// Check vehicle speed with redundant source
if (msg->addr == MSG_ESP_21) {
// Signal: ESP_v_Signal
float esp_speed = ((msg->data[5] << 8) | msg->data[4]) * 0.01 * KPH_TO_MS;
UPDATE_VEHICLE_SPEED_2(esp_speed);
int accel_pedal_value = ((msg->data[1] >> 4) & 0x0FU) | ((msg->data[2] & 0x1FU) << 4);
gas_pressed = accel_pedal_value > 0;
}
if (msg_matches(msg, MSG_GRA_ACC_01, 0U)) {
// Enter controls on falling edge of Set or Resume with main switch on
// Signal: GRA_ACC_01.GRA_Tip_Setzen
// Signal: GRA_ACC_01.GRA_Tip_Wiederaufnahme
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 19U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
if (msg->addr == MSG_QFK_01) {
int current_curvature = ((msg->data[6] & 0x7FU) << 8) | msg->data[5];
current_curvature *= GET_BIT(msg, 55U) ? 1 : -1;
update_sample(&curvature_state.meas, current_curvature);
// Always exit controls on rising edge of Cancel
if (GET_BIT(msg, 13U)) {
controls_allowed = false;
}
}
if (msg->addr == MSG_LH_EPS_03) {
update_sample(&torque_driver, volkswagen_mlb_mqb_driver_input_torque(msg));
}
if (msg->addr == MSG_Motor_51) {
int acc_status = (msg->data[11] & 0x07U);
bool cruise_engaged = (acc_status == 3) || (acc_status == 4) || (acc_status == 5);
acc_main_on = cruise_engaged || (acc_status == 2);
if (!acc_main_on) {
controls_allowed = false;
}
int accel_pedal_value = ((msg->data[1] >> 4) & 0x0FU) | ((msg->data[2] & 0x1FU) << 4);
gas_pressed = accel_pedal_value > 0;
}
if (msg->addr == MSG_GRA_ACC_01) {
// Enter controls on falling edge of Set or Resume with main switch on
// Signal: GRA_ACC_01.GRA_Tip_Setzen
// Signal: GRA_ACC_01.GRA_Tip_Wiederaufnahme
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 19U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
// Always exit controls on rising edge of Cancel
if (GET_BIT(msg, 13U)) {
controls_allowed = false;
}
}
if (msg->addr == MSG_MOTOR_14) {
brake_pressed = GET_BIT(msg, 28U);
}
if (msg_matches(msg, MSG_MOTOR_14, 0U)) {
brake_pressed = GET_BIT(msg, 28U);
}
}
@@ -270,7 +258,7 @@ static bool volkswagen_meb_tx_hook(const CANPacket_t *msg) {
.max_steer_power = 125,
};
int desired_curvature_raw = GET_BYTES(msg, 3, 2) & 0x7FFFU;
int desired_curvature_raw = GET_BYTES_LE(msg, 3, 2) & 0x7FFFU;
bool desired_curvature_sign = GET_BIT(msg, 39U);
if (!desired_curvature_sign) {
@@ -292,7 +280,7 @@ const safety_hooks volkswagen_meb_hooks = {
.init = volkswagen_meb_init,
.rx = volkswagen_meb_rx_hook,
.tx = volkswagen_meb_tx_hook,
.get_counter = volkswagen_mqb_meb_get_counter,
.get_checksum = volkswagen_mqb_meb_get_checksum,
.get_counter = volkswagen_mxb_get_counter,
.get_checksum = volkswagen_mxb_get_checksum,
.compute_checksum = volkswagen_meb_alt_crc_compute,
};
@@ -3,11 +3,14 @@
#include "opendbc/safety/declarations.h"
#include "opendbc/safety/modes/volkswagen_common.h"
static safety_config volkswagen_mlb_init(uint16_t param) {
// Transmit of LS_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
static const CanMsg VOLKSWAGEN_MLB_STOCK_TX_MSGS[] = {{MSG_HCA_01, 0, 8, .check_relay = true}, {MSG_LDW_02, 0, 8, .check_relay = true},
{MSG_LS_01, 0, 4, .check_relay = false}, {MSG_LS_01, 2, 4, .check_relay = false}};
static const CanMsg VOLKSWAGEN_MLB_STOCK_TX_MSGS[] = {
{MSG_HCA_01, 0, 8, .check_relay = true},
{MSG_LDW_02, 0, 8, .check_relay = true},
{MSG_LS_01, 0, 4, .check_relay = false},
{MSG_LS_01, 2, 4, .check_relay = false},
};
static RxCheck volkswagen_mlb_rx_checks[] = {
// TODO: implement checksum validation
@@ -26,56 +29,51 @@ static safety_config volkswagen_mlb_init(uint16_t param) {
}
static void volkswagen_mlb_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Check all wheel speeds for any movement
// Signals: ESP_03.ESP_[VL|VR|HL|HR]_Radgeschw
if (msg->addr == MSG_ESP_03) {
uint32_t speed = 0;
speed += ((msg->data[3] & 0xFU) << 8) | msg->data[2]; // FL
speed += (msg->data[4] << 4) | (msg->data[3] >> 4); // FR
speed += ((msg->data[6] & 0xFU) << 8) | msg->data[5]; // RL
speed += (msg->data[7] << 4) | (msg->data[6] >> 4); // RR
vehicle_moving = speed > 0U;
}
// Update driver input torque
if (msg->addr == MSG_LH_EPS_03) {
update_sample(&torque_driver, volkswagen_mlb_mqb_driver_input_torque(msg));
}
if (msg->addr == MSG_LS_01) {
// Always exit controls on rising edge of Cancel
// Signal: LS_01.LS_Abbrechen
if (GET_BIT(msg, 13U)) {
controls_allowed = false;
}
}
// Signal: Motor_03.MO_Fahrpedalrohwert_01
// Signal: Motor_03.MO_Fahrer_bremst
if (msg->addr == MSG_MOTOR_03) {
gas_pressed = msg->data[6] != 0U;
volkswagen_brake_pedal_switch = GET_BIT(msg, 35U);
}
if (msg->addr == MSG_ESP_05) {
volkswagen_brake_pressure_detected = GET_BIT(msg, 26U);
}
brake_pressed = volkswagen_brake_pedal_switch || volkswagen_brake_pressure_detected;
// Check all wheel speeds for any movement
// Signals: ESP_03.ESP_[VL|VR|HL|HR]_Radgeschw
if (msg_matches(msg, MSG_ESP_03, 0U)) {
uint32_t speed = 0;
speed += ((msg->data[3] & 0xFU) << 8) | msg->data[2]; // FL
speed += (msg->data[4] << 4) | (msg->data[3] >> 4); // FR
speed += ((msg->data[6] & 0xFU) << 8) | msg->data[5]; // RL
speed += (msg->data[7] << 4) | (msg->data[6] >> 4); // RR
vehicle_moving = speed > 0U;
}
if (msg->bus == 1U) {
if (msg->addr == MSG_TSK_04) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Signal: TSK_04.TSK_Status_GRA_ACC_02
int acc_status = (msg->data[7] & 0xC0U) >> 6;
bool cruise_engaged = (acc_status == 1) || (acc_status == 2);
// Update driver input torque
if (msg_matches(msg, MSG_LH_EPS_03, 0U)) {
update_sample(&torque_driver, volkswagen_mlb_mqb_driver_input_torque(msg));
}
pcm_cruise_check(cruise_engaged);
if (msg_matches(msg, MSG_LS_01, 0U)) {
// Always exit controls on rising edge of Cancel
// Signal: LS_01.LS_Abbrechen
if (GET_BIT(msg, 13U)) {
controls_allowed = false;
}
}
// Signal: Motor_03.MO_Fahrpedalrohwert_01
// Signal: Motor_03.MO_Fahrer_bremst
if (msg_matches(msg, MSG_MOTOR_03, 0U)) {
gas_pressed = msg->data[6] != 0U;
volkswagen_brake_pedal_switch = GET_BIT(msg, 35U);
}
if (msg_matches(msg, MSG_ESP_05, 0U)) {
volkswagen_brake_pressure_detected = GET_BIT(msg, 26U);
}
brake_pressed = volkswagen_brake_pedal_switch || volkswagen_brake_pressure_detected;
if (msg_matches(msg, MSG_TSK_04, 1U)) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Signal: TSK_04.TSK_Status_GRA_ACC_02
int acc_status = (msg->data[7] & 0xC0U) >> 6;
bool cruise_engaged = (acc_status == 1) || (acc_status == 2);
pcm_cruise_check(cruise_engaged);
}
}
static bool volkswagen_mlb_tx_hook(const CANPacket_t *msg) {
@@ -116,12 +114,11 @@ static bool volkswagen_mlb_tx_hook(const CANPacket_t *msg) {
return tx;
}
// TODO: rename these functions to MXB or something
const safety_hooks volkswagen_mlb_hooks = {
.init = volkswagen_mlb_init,
.rx = volkswagen_mlb_rx_hook,
.tx = volkswagen_mlb_tx_hook,
.get_counter = volkswagen_mqb_meb_get_counter,
.get_checksum = volkswagen_mqb_meb_get_checksum,
.compute_checksum = volkswagen_mqb_meb_compute_crc,
.get_counter = volkswagen_mxb_get_counter,
.get_checksum = volkswagen_mxb_get_checksum,
.compute_checksum = volkswagen_mxb_compute_crc,
};
@@ -6,11 +6,22 @@
static safety_config volkswagen_mqb_init(uint16_t param) {
// Transmit of GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
// MSG_LH_EPS_03: openpilot needs to replace apparent driver steering input torque to pacify VW Emergency Assist
static const CanMsg VOLKSWAGEN_MQB_STOCK_TX_MSGS[] = {{MSG_HCA_01, 0, 8, .check_relay = true}, {MSG_GRA_ACC_01, 0, 8, .check_relay = false}, {MSG_GRA_ACC_01, 2, 8, .check_relay = false},
{MSG_LDW_02, 0, 8, .check_relay = true}, {MSG_LH_EPS_03, 2, 8, .check_relay = true}};
static const CanMsg VOLKSWAGEN_MQB_STOCK_TX_MSGS[] = {
{MSG_HCA_01, 0, 8, .check_relay = true},
{MSG_GRA_ACC_01, 0, 8, .check_relay = false},
{MSG_GRA_ACC_01, 2, 8, .check_relay = false},
{MSG_LDW_02, 0, 8, .check_relay = true},
{MSG_LH_EPS_03, 2, 8, .check_relay = true},
};
static const CanMsg VOLKSWAGEN_MQB_LONG_TX_MSGS[] = {{MSG_HCA_01, 0, 8, .check_relay = true}, {MSG_LDW_02, 0, 8, .check_relay = true}, {MSG_LH_EPS_03, 2, 8, .check_relay = true},
{MSG_ACC_02, 0, 8, .check_relay = true}, {MSG_ACC_06, 0, 8, .check_relay = true}, {MSG_ACC_07, 0, 8, .check_relay = true}};
static const CanMsg VOLKSWAGEN_MQB_LONG_TX_MSGS[] = {
{MSG_HCA_01, 0, 8, .check_relay = true},
{MSG_LDW_02, 0, 8, .check_relay = true},
{MSG_LH_EPS_03, 2, 8, .check_relay = true},
{MSG_ACC_02, 0, 8, .check_relay = true},
{MSG_ACC_06, 0, 8, .check_relay = true},
{MSG_ACC_07, 0, 8, .check_relay = true},
};
static RxCheck volkswagen_mqb_rx_checks[] = {
{.msg = {{MSG_ESP_19, 0, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
@@ -35,80 +46,78 @@ static safety_config volkswagen_mqb_init(uint16_t param) {
}
static void volkswagen_mqb_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Update in-motion state by sampling wheel speeds
if (msg->addr == MSG_ESP_19) {
// sum 4 wheel speeds
int speed = 0;
for (uint8_t i = 0U; i < 8U; i += 2U) {
int wheel_speed = msg->data[i] | (msg->data[i + 1U] << 8);
speed += wheel_speed;
}
// Check all wheel speeds for any movement
vehicle_moving = speed > 0;
// Update in-motion state by sampling wheel speeds
if (msg_matches(msg, MSG_ESP_19, 0U)) {
// sum 4 wheel speeds
int speed = 0;
for (uint8_t i = 0U; i < 8U; i += 2U) {
int wheel_speed = msg->data[i] | (msg->data[i + 1U] << 8);
speed += wheel_speed;
}
// Update driver input torque samples
// Signal: LH_EPS_03.EPS_Lenkmoment (absolute torque)
// Signal: LH_EPS_03.EPS_VZ_Lenkmoment (direction)
if (msg->addr == MSG_LH_EPS_03) {
update_sample(&torque_driver, volkswagen_mlb_mqb_driver_input_torque(msg));
}
if (msg->addr == MSG_TSK_06) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Always exit controls on main switch off
// Signal: TSK_06.TSK_Status
int acc_status = (msg->data[3] & 0x7U);
bool cruise_engaged = (acc_status == 3) || (acc_status == 4) || (acc_status == 5);
acc_main_on = cruise_engaged || (acc_status == 2);
if (!volkswagen_longitudinal) {
pcm_cruise_check(cruise_engaged);
}
if (!acc_main_on) {
controls_allowed = false;
}
}
if (msg->addr == MSG_GRA_ACC_01) {
// If using openpilot longitudinal, enter controls on falling edge of Set or Resume with main switch on
// Signal: GRA_ACC_01.GRA_Tip_Setzen
// Signal: GRA_ACC_01.GRA_Tip_Wiederaufnahme
if (volkswagen_longitudinal) {
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 19U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
}
// Always exit controls on rising edge of Cancel
// Signal: GRA_ACC_01.GRA_Abbrechen
if (GET_BIT(msg, 13U)) {
controls_allowed = false;
}
}
// Signal: Motor_20.MO_Fahrpedalrohwert_01
if (msg->addr == MSG_MOTOR_20) {
gas_pressed = ((GET_BYTES(msg, 0, 4) >> 12) & 0xFFU) != 0U;
}
// Signal: Motor_14.MO_Fahrer_bremst (ECU detected brake pedal switch F63)
if (msg->addr == MSG_MOTOR_14) {
volkswagen_brake_pedal_switch = GET_BIT(msg, 28U);
}
// Signal: ESP_05.ESP_Fahrer_bremst (ESP detected driver brake pressure above platform specified threshold)
if (msg->addr == MSG_ESP_05) {
volkswagen_brake_pressure_detected = GET_BIT(msg, 26U);
}
brake_pressed = volkswagen_brake_pedal_switch || volkswagen_brake_pressure_detected;
// Check all wheel speeds for any movement
vehicle_moving = speed > 0;
}
// Update driver input torque samples
// Signal: LH_EPS_03.EPS_Lenkmoment (absolute torque)
// Signal: LH_EPS_03.EPS_VZ_Lenkmoment (direction)
if (msg_matches(msg, MSG_LH_EPS_03, 0U)) {
update_sample(&torque_driver, volkswagen_mlb_mqb_driver_input_torque(msg));
}
if (msg_matches(msg, MSG_TSK_06, 0U)) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Always exit controls on main switch off
// Signal: TSK_06.TSK_Status
int acc_status = (msg->data[3] & 0x7U);
bool cruise_engaged = (acc_status == 3) || (acc_status == 4) || (acc_status == 5);
acc_main_on = cruise_engaged || (acc_status == 2);
if (!volkswagen_longitudinal) {
pcm_cruise_check(cruise_engaged);
}
if (!acc_main_on) {
controls_allowed = false;
}
}
if (msg_matches(msg, MSG_GRA_ACC_01, 0U)) {
// If using openpilot longitudinal, enter controls on falling edge of Set or Resume with main switch on
// Signal: GRA_ACC_01.GRA_Tip_Setzen
// Signal: GRA_ACC_01.GRA_Tip_Wiederaufnahme
if (volkswagen_longitudinal) {
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 19U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
}
// Always exit controls on rising edge of Cancel
// Signal: GRA_ACC_01.GRA_Abbrechen
if (GET_BIT(msg, 13U)) {
controls_allowed = false;
}
}
// Signal: Motor_20.MO_Fahrpedalrohwert_01
if (msg_matches(msg, MSG_MOTOR_20, 0U)) {
gas_pressed = ((GET_BYTES_LE(msg, 0, 4) >> 12) & 0xFFU) != 0U;
}
// Signal: Motor_14.MO_Fahrer_bremst (ECU detected brake pedal switch F63)
if (msg_matches(msg, MSG_MOTOR_14, 0U)) {
volkswagen_brake_pedal_switch = GET_BIT(msg, 28U);
}
// Signal: ESP_05.ESP_Fahrer_bremst (ESP detected driver brake pressure above platform specified threshold)
if (msg_matches(msg, MSG_ESP_05, 0U)) {
volkswagen_brake_pressure_detected = GET_BIT(msg, 26U);
}
brake_pressed = volkswagen_brake_pedal_switch || volkswagen_brake_pressure_detected;
}
static bool volkswagen_mqb_tx_hook(const CANPacket_t *msg) {
@@ -183,7 +192,7 @@ const safety_hooks volkswagen_mqb_hooks = {
.init = volkswagen_mqb_init,
.rx = volkswagen_mqb_rx_hook,
.tx = volkswagen_mqb_tx_hook,
.get_counter = volkswagen_mqb_meb_get_counter,
.get_checksum = volkswagen_mqb_meb_get_checksum,
.compute_checksum = volkswagen_mqb_meb_compute_crc,
.get_counter = volkswagen_mxb_get_counter,
.get_checksum = volkswagen_mxb_get_checksum,
.compute_checksum = volkswagen_mxb_compute_crc,
};
@@ -23,9 +23,9 @@ static uint8_t volkswagen_pq_get_counter(const CANPacket_t *msg) {
if (msg->addr == MSG_LENKHILFE_3) {
counter = (uint8_t)(msg->data[1] & 0xF0U) >> 4;
} else if (msg->addr == MSG_GRA_NEU) {
}
if (msg->addr == MSG_GRA_NEU) {
counter = (uint8_t)(msg->data[2] & 0xF0U) >> 4;
} else {
}
return counter;
@@ -48,11 +48,19 @@ static uint32_t volkswagen_pq_compute_checksum(const CANPacket_t *msg) {
static safety_config volkswagen_pq_init(uint16_t param) {
// Transmit of GRA_Neu is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
static const CanMsg VOLKSWAGEN_PQ_STOCK_TX_MSGS[] = {{MSG_HCA_1, 0, 5, .check_relay = true}, {MSG_LDW_1, 0, 8, .check_relay = true},
{MSG_GRA_NEU, 0, 4, .check_relay = false}, {MSG_GRA_NEU, 2, 4, .check_relay = false}};
static const CanMsg VOLKSWAGEN_PQ_STOCK_TX_MSGS[] = {
{MSG_HCA_1, 0, 5, .check_relay = true},
{MSG_LDW_1, 0, 8, .check_relay = true},
{MSG_GRA_NEU, 0, 4, .check_relay = false},
{MSG_GRA_NEU, 2, 4, .check_relay = false},
};
static const CanMsg VOLKSWAGEN_PQ_LONG_TX_MSGS[] = {{MSG_HCA_1, 0, 5, .check_relay = true}, {MSG_LDW_1, 0, 8, .check_relay = true},
{MSG_ACC_SYSTEM, 0, 8, .check_relay = true}, {MSG_ACC_GRA_ANZEIGE, 0, 8, .check_relay = true}};
static const CanMsg VOLKSWAGEN_PQ_LONG_TX_MSGS[] = {
{MSG_HCA_1, 0, 5, .check_relay = true},
{MSG_LDW_1, 0, 8, .check_relay = true},
{MSG_ACC_SYSTEM, 0, 8, .check_relay = true},
{MSG_ACC_GRA_ANZEIGE, 0, 8, .check_relay = true},
};
static RxCheck volkswagen_pq_rx_checks[] = {
{.msg = {{MSG_LENKHILFE_3, 0, 6, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
@@ -75,72 +83,70 @@ static safety_config volkswagen_pq_init(uint16_t param) {
}
static void volkswagen_pq_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
// Update in-motion state from speed value.
// Signal: Bremse_1.BR1_Rad_kmh
if (msg->addr == MSG_BREMSE_1) {
int speed = ((msg->data[2] & 0xFEU) >> 1) | (msg->data[3] << 7);
vehicle_moving = speed > 0;
// Update in-motion state from speed value.
// Signal: Bremse_1.BR1_Rad_kmh
if (msg_matches(msg, MSG_BREMSE_1, 0U)) {
int speed = ((msg->data[2] & 0xFEU) >> 1) | (msg->data[3] << 7);
vehicle_moving = speed > 0;
}
// Update driver input torque samples
// Signal: Lenkhilfe_3.LH3_LM (absolute torque)
// Signal: Lenkhilfe_3.LH3_LMSign (direction)
if (msg_matches(msg, MSG_LENKHILFE_3, 0U)) {
int torque_driver_new = msg->data[2] | ((msg->data[3] & 0x3U) << 8);
int sign = (msg->data[3] & 0x4U) >> 2;
if (sign == 1) {
torque_driver_new *= -1;
}
update_sample(&torque_driver, torque_driver_new);
}
// Update driver input torque samples
// Signal: Lenkhilfe_3.LH3_LM (absolute torque)
// Signal: Lenkhilfe_3.LH3_LMSign (direction)
if (msg->addr == MSG_LENKHILFE_3) {
int torque_driver_new = msg->data[2] | ((msg->data[3] & 0x3U) << 8);
int sign = (msg->data[3] & 0x4U) >> 2;
if (sign == 1) {
torque_driver_new *= -1;
}
update_sample(&torque_driver, torque_driver_new);
}
if (volkswagen_longitudinal) {
if (msg->addr == MSG_MOTOR_5) {
// ACC main switch on is a prerequisite to enter controls, exit controls immediately on main switch off
// Signal: Motor_5.MO5_GRA_Hauptsch
acc_main_on = GET_BIT(msg, 50U);
if (!acc_main_on) {
controls_allowed = false;
}
}
if (msg->addr == MSG_GRA_NEU) {
// If ACC main switch is on, enter controls on falling edge of Set or Resume
// Signal: GRA_Neu.GRA_Neu_Setzen
// Signal: GRA_Neu.GRA_Neu_Recall
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 17U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
// Exit controls on rising edge of Cancel, override Set/Resume if present simultaneously
// Signal: GRA_ACC_01.GRA_Abbrechen
if (GET_BIT(msg, 9U)) {
controls_allowed = false;
}
}
} else {
if (msg->addr == MSG_MOTOR_2) {
// Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages
// Signal: Motor_2.MO2_Sta_GRA
int acc_status = (msg->data[2] & 0xC0U) >> 6;
bool cruise_engaged = (acc_status == 1) || (acc_status == 2);
pcm_cruise_check(cruise_engaged);
if (volkswagen_longitudinal) {
if (msg_matches(msg, MSG_MOTOR_5, 0U)) {
// ACC main switch on is a prerequisite to enter controls, exit controls immediately on main switch off
// Signal: Motor_5.MO5_GRA_Hauptsch
acc_main_on = GET_BIT(msg, 50U);
if (!acc_main_on) {
controls_allowed = false;
}
}
// Signal: Motor_3.MO3_Pedalwert
if (msg->addr == MSG_MOTOR_3) {
gas_pressed = (msg->data[2]);
if (msg_matches(msg, MSG_GRA_NEU, 0U)) {
// If ACC main switch is on, enter controls on falling edge of Set or Resume
// Signal: GRA_Neu.GRA_Neu_Setzen
// Signal: GRA_Neu.GRA_Neu_Recall
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 17U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
// Exit controls on rising edge of Cancel, override Set/Resume if present simultaneously
// Signal: GRA_ACC_01.GRA_Abbrechen
if (GET_BIT(msg, 9U)) {
controls_allowed = false;
}
}
} else {
if (msg_matches(msg, MSG_MOTOR_2, 0U)) {
// Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages
// Signal: Motor_2.MO2_Sta_GRA
int acc_status = (msg->data[2] & 0xC0U) >> 6;
bool cruise_engaged = (acc_status == 1) || (acc_status == 2);
pcm_cruise_check(cruise_engaged);
}
}
// Signal: Motor_2.MO2_BLS
if (msg->addr == MSG_MOTOR_2) {
brake_pressed = (msg->data[2] & 0x1U);
}
// Signal: Motor_3.MO3_Pedalwert
if (msg_matches(msg, MSG_MOTOR_3, 0U)) {
gas_pressed = (msg->data[2]);
}
// Signal: Motor_2.MO2_BLS
if (msg_matches(msg, MSG_MOTOR_2, 0U)) {
brake_pressed = (msg->data[2] & 0x1U);
}
}
+39 -54
View File
@@ -30,9 +30,10 @@
#include "opendbc/safety/modes/elm327.h"
#include "opendbc/safety/modes/body.h"
#include "opendbc/safety/modes/psa.h"
#include "opendbc/safety/modes/byd.h"
#include "opendbc/safety/modes/hyundai_canfd.h"
uint32_t GET_BYTES(const CANPacket_t *msg, int start, int len) {
uint32_t GET_BYTES_LE(const CANPacket_t *msg, int start, int len) {
uint32_t ret = 0U;
for (int i = 0; i < len; i++) {
const uint32_t shift = i * 8;
@@ -41,6 +42,16 @@ uint32_t GET_BYTES(const CANPacket_t *msg, int start, int len) {
return ret;
}
// Read up to eight bytes in little-endian order, without alignment assumptions.
uint64_t GET_BYTES_64_LE(const CANPacket_t *msg, int start, int len) {
uint64_t ret = 0U;
for (int i = 0; i < len; i++) {
const uint32_t shift = i * 8;
ret |= ((uint64_t)msg->data[start + i]) << shift;
}
return ret;
}
const int MAX_WRONG_COUNTERS = 5;
// This can be set by the safety hooks
@@ -114,16 +125,12 @@ static bool is_msg_valid(RxCheck addr_list[], int index) {
}
static int get_addr_check_index(const CANPacket_t *msg, RxCheck addr_list[], const int len) {
int addr = msg->addr;
int length = GET_LEN(msg);
int index = -1;
for (int i = 0; i < len; i++) {
// if multiple msgs are allowed, determine which one is present on the bus
if (!addr_list[i].status.msg_seen) {
for (uint8_t j = 0U; (j < MAX_ADDR_CHECK_MSGS) && (addr_list[i].msg[j].addr != 0); j++) {
if ((addr == addr_list[i].msg[j].addr) && (msg->bus == addr_list[i].msg[j].bus) &&
(length == addr_list[i].msg[j].len)) {
if (msg_matches(msg, addr_list[i].msg[j].addr, addr_list[i].msg[j].bus, addr_list[i].msg[j].len)) {
addr_list[i].status.index = j;
addr_list[i].status.msg_seen = true;
break;
@@ -133,8 +140,7 @@ static int get_addr_check_index(const CANPacket_t *msg, RxCheck addr_list[], con
if (addr_list[i].status.msg_seen) {
int idx = addr_list[i].status.index;
if ((addr == addr_list[i].msg[idx].addr) && (msg->bus == addr_list[i].msg[idx].bus) &&
(length == addr_list[i].msg[idx].len)) {
if (msg_matches(msg, addr_list[i].msg[idx].addr, addr_list[i].msg[idx].bus, addr_list[i].msg[idx].len)) {
index = i;
break;
}
@@ -228,12 +234,9 @@ bool safety_rx_hook(const CANPacket_t *msg) {
}
static bool tx_msg_safety_check(const CANPacket_t *msg, const CanMsg msg_list[], int len) {
int addr = msg->addr;
int length = GET_LEN(msg);
bool whitelisted = false;
for (int i = 0; i < len; i++) {
if ((addr == msg_list[i].addr) && (msg->bus == msg_list[i].bus) && (length == msg_list[i].len)) {
if (msg_matches(msg, msg_list[i].addr, msg_list[i].bus, msg_list[i].len)) {
whitelisted = true;
break;
}
@@ -321,31 +324,29 @@ void gen_crc_lookup_table_16(uint16_t poly, uint16_t crc_lut[]) {
}
// 1Hz safety function called by main. Now just a check for lagging safety messages
void safety_tick(const safety_config *cfg) {
void safety_tick(void) {
const uint8_t MAX_MISSED_MSGS = 10U;
bool rx_checks_invalid = false;
uint32_t ts = microsecond_timer_get();
if (cfg != NULL) {
for (int i=0; i < cfg->rx_checks_len; i++) {
uint32_t elapsed_time = safety_get_ts_elapsed(ts, cfg->rx_checks[i].status.last_timestamp);
// lag threshold is max of: 1s and MAX_MISSED_MSGS * expected timestep.
// Quite conservative to not risk false triggers.
// 2s of lag is worse case, since the function is called at 1Hz
uint32_t frequency = cfg->rx_checks[i].msg[cfg->rx_checks[i].status.index].frequency;
uint32_t timestep = 1e6 / frequency;
bool lagging = elapsed_time > SAFETY_MAX(timestep * MAX_MISSED_MSGS, 1e6);
cfg->rx_checks[i].status.lagging = lagging;
if (lagging) {
controls_allowed = false;
mads_exit_controls(MADS_DISENGAGE_REASON_LAG);
}
for (int i=0; i < current_safety_config.rx_checks_len; i++) {
uint32_t elapsed_time = safety_get_ts_elapsed(ts, current_safety_config.rx_checks[i].status.last_timestamp);
// lag threshold is max of: 1s and MAX_MISSED_MSGS * expected timestep.
// Quite conservative to not risk false triggers.
// 2s of lag is worse case, since the function is called at 1Hz
uint32_t frequency = current_safety_config.rx_checks[i].msg[current_safety_config.rx_checks[i].status.index].frequency;
uint32_t timestep = 1e6 / frequency;
bool lagging = elapsed_time > SAFETY_MAX(timestep * MAX_MISSED_MSGS, 1e6);
current_safety_config.rx_checks[i].status.lagging = lagging;
if (lagging) {
controls_allowed = false;
mads_exit_controls(MADS_DISENGAGE_REASON_LAG);
}
// enforce minimum frequency for safety-relevant messages
bool frequency_invalid = !cfg->rx_checks[i].msg[cfg->rx_checks[i].status.index].ignore_frequency_check && (frequency < 10U);
if (lagging || frequency_invalid || !is_msg_valid(cfg->rx_checks, i)) {
rx_checks_invalid = true;
controls_allowed = false;
}
// enforce minimum frequency for safety-relevant messages
bool frequency_invalid = !current_safety_config.rx_checks[i].msg[current_safety_config.rx_checks[i].status.index].ignore_frequency_check && (frequency < 10U);
if (lagging || frequency_invalid || !is_msg_valid(current_safety_config.rx_checks, i)) {
rx_checks_invalid = true;
controls_allowed = false;
}
}
@@ -395,10 +396,7 @@ static void relay_malfunction_reset(void) {
// resets values and min/max for sample_t struct
static void reset_sample(struct sample_t *sample) {
for (int i = 0; i < MAX_SAMPLE_VALS; i++) {
sample->values[i] = 0;
}
update_sample(sample, 0);
*sample = (struct sample_t){0};
}
int set_safety_hooks(uint16_t mode, uint16_t param) {
@@ -428,6 +426,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
{SAFETY_GWM, &gwm_hooks},
{SAFETY_CHRYSLER_CUSW, &chrysler_cusw_hooks},
{SAFETY_PSA, &psa_hooks},
{SAFETY_BYD, &byd_hooks},
{SAFETY_SUBARU_PREGLOBAL, &subaru_preglobal_hooks},
{SAFETY_VOLKSWAGEN_MLB, &volkswagen_mlb_hooks},
{SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks},
@@ -455,11 +454,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
rt_angle_msgs = 0;
ts_angle_check_last = 0;
desired_angle_last = 0;
curvature_state.desired_last = 0;
curvature_state.rt_msgs = 0;
curvature_state.rt_msgs_prev = 0;
curvature_state.ts_check_last = 0;
curvature_state.steer_power_last = 0;
curvature_state = (CurvatureSteeringState){0};
ts_torque_check_last = 0;
ts_steer_req_mismatch_last = 0;
valid_steer_req_count = 0;
@@ -475,17 +470,12 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
reset_sample(&torque_meas);
reset_sample(&torque_driver);
reset_sample(&angle_meas);
reset_sample(&curvature_state.meas);
controls_allowed = false;
relay_malfunction_reset();
safety_rx_checks_invalid = false;
current_safety_config.rx_checks = NULL;
current_safety_config.rx_checks_len = 0;
current_safety_config.tx_msgs = NULL;
current_safety_config.tx_msgs_len = 0;
current_safety_config.disable_forwarding = false;
current_safety_config = (safety_config){0};
int set_status = -1; // not set
int hook_config_count = sizeof(safety_hook_registry) / sizeof(safety_hook_config);
@@ -498,12 +488,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
}
}
if ((set_status == 0) && (current_hooks->init != NULL)) {
safety_config cfg = current_hooks->init(param);
current_safety_config.rx_checks = cfg.rx_checks;
current_safety_config.rx_checks_len = cfg.rx_checks_len;
current_safety_config.tx_msgs = cfg.tx_msgs;
current_safety_config.tx_msgs_len = cfg.tx_msgs_len;
current_safety_config.disable_forwarding = cfg.disable_forwarding;
current_safety_config = current_hooks->init(param);
// reset all dynamic fields in addr struct
for (int j = 0; j < current_safety_config.rx_checks_len; j++) {
current_safety_config.rx_checks[j].status = (RxStatus){0};
+53 -86
View File
@@ -75,12 +75,24 @@ def add_regen_tests(cls):
class SafetyTestBase(unittest.TestCase):
safety: libsafety_py.LibSafety | None
safety: libsafety_py.LibSafety
DBC: str | None = None
packer: CANPackerSafety
SAFETY_MODEL: int | None
SAFETY_PARAM = 0
def setUp(self):
self.safety = libsafety_py.libsafety
if self.DBC is not None:
self.packer = CANPackerSafety(self.DBC)
if self.SAFETY_MODEL is not None:
self.safety.set_safety_hooks(self.SAFETY_MODEL, self.SAFETY_PARAM)
self.safety.init_tests()
@classmethod
def setUpClass(cls):
if cls.__name__ == "SafetyTestBase":
cls.safety = None
# Classes defined in this module and classes named *Base are shared test helpers.
if cls.__module__ == __name__ or cls.__name__.endswith('Base'):
raise unittest.SkipTest
def _reset_safety_hooks(self):
@@ -157,12 +169,6 @@ class LongitudinalAccelSafetyTest(SafetyTestBase, abc.ABC):
MIN_ACCEL: float = -3.5
INACTIVE_ACCEL: float = 0.0
@classmethod
def setUpClass(cls):
if cls.__name__ == "LongitudinalAccelSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _accel_msg(self, accel: float):
pass
@@ -235,12 +241,6 @@ class TorqueSteeringSafetyTestBase(SafetyTestBase, abc.ABC):
NO_STEER_REQ_BIT = False
@classmethod
def setUpClass(cls):
if cls.__name__ == "TorqueSteeringSafetyTestBase":
cls.safety = None
raise unittest.SkipTest
@property
def MAX_TORQUE(self):
return max(self.MAX_TORQUE_LOOKUP[1])
@@ -322,12 +322,6 @@ class TorqueSteeringSafetyTestBase(SafetyTestBase, abc.ABC):
class SteerRequestCutSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
@classmethod
def setUpClass(cls):
if cls.__name__ == "SteerRequestCutSafetyTest":
cls.safety = None
raise unittest.SkipTest
# Safety around steering request bit mismatch tolerance
MIN_VALID_STEERING_FRAMES: int
MAX_INVALID_STEERING_FRAMES: int
@@ -347,7 +341,9 @@ class SteerRequestCutSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
- We can always recover from violations if steer_req=1
"""
for min_valid_steer_frames in range(self.MIN_VALID_STEERING_FRAMES * 2):
# dense around the threshold, sparse elsewhere (the valid frame counter saturates at MIN_VALID_STEERING_FRAMES)
valid_frames = self._boundary_values([self.MIN_VALID_STEERING_FRAMES], 0, self.MIN_VALID_STEERING_FRAMES * 2, sparse_count=10)
for min_valid_steer_frames in map(int, valid_frames):
# Reset match count and rt timer to allow cut (valid_steer_req_count, ts_steer_req_mismatch_last)
self.safety.init_tests()
self.safety.set_timer(self.MIN_VALID_STEERING_RT_INTERVAL)
@@ -365,7 +361,7 @@ class SteerRequestCutSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
self.assertEqual(should_tx and idx < self.MAX_INVALID_STEERING_FRAMES, tx)
# Keep blocking after one steer_req mismatch
for _ in range(100):
for _ in range(10):
self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)))
# Make sure we can recover
@@ -423,7 +419,7 @@ class SteerRequestCutSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)))
# Keep blocking after one steer_req mismatch
for _ in range(100):
for _ in range(10):
self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)))
# Make sure we can recover
@@ -437,12 +433,6 @@ class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
DRIVER_TORQUE_ALLOWANCE = 0
DRIVER_TORQUE_FACTOR = 0
@classmethod
def setUpClass(cls):
if cls.__name__ == "DriverTorqueSteeringSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _torque_driver_msg(self, torque):
pass
@@ -451,6 +441,21 @@ class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
for _ in range(MAX_SAMPLE_VALS):
self._rx(self._torque_driver_msg(torque))
def test_driver_torque_measurements(self):
for torque in (50, -50, *([0] * (MAX_SAMPLE_VALS - 2))):
self.assertTrue(self._rx(self._torque_driver_msg(torque)))
self.assertEqual(-50, self.safety.get_torque_driver_min())
self.assertEqual(50, self.safety.get_torque_driver_max())
self.assertTrue(self._rx(self._torque_driver_msg(0)))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(-50, self.safety.get_torque_driver_min())
self.assertTrue(self._rx(self._torque_driver_msg(0)))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(0, self.safety.get_torque_driver_min())
def test_non_realtime_limit_up(self):
self._reset_torque_driver_measurement(0)
super().test_non_realtime_limit_up()
@@ -538,12 +543,6 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
MAX_TORQUE_ERROR = 0
TORQUE_MEAS_TOLERANCE = 0
@classmethod
def setUpClass(cls):
if cls.__name__ == "MotorTorqueSteeringSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _torque_meas_msg(self, torque):
pass
@@ -571,23 +570,18 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
self.assertEqual(send, self._tx(self._torque_cmd_msg(torque)))
def test_non_realtime_limit_down(self):
self.safety.set_controls_allowed(True)
for speed in self._torque_speed_range:
self._reset_speed_measurement(speed)
max_torque = self._get_max_torque(speed)
torque_meas = max_torque - self.MAX_TORQUE_ERROR - 50
self.safety.set_rt_torque_last(max_torque)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(max_torque)
self.assertTrue(self._tx(self._torque_cmd_msg(max_torque - self.MAX_RATE_DOWN)))
self.safety.set_rt_torque_last(max_torque)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(max_torque)
self.assertFalse(self._tx(self._torque_cmd_msg(max_torque - self.MAX_RATE_DOWN + 1)))
for sign in (-1, 1):
for delta in (self.MAX_RATE_DOWN, self.MAX_RATE_DOWN - 1):
self.safety.set_controls_allowed(True)
self.safety.set_rt_torque_last(sign * max_torque)
self.safety.set_torque_meas(sign * torque_meas, sign * torque_meas)
self.safety.set_desired_torque_last(sign * max_torque)
self.assertEqual(delta == self.MAX_RATE_DOWN, self._tx(self._torque_cmd_msg(sign * (max_torque - delta))))
def test_exceed_torque_sensor(self):
self.safety.set_controls_allowed(True)
@@ -659,12 +653,6 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
class VehicleSpeedSafetyTest(SafetyTestBase):
@classmethod
def setUpClass(cls):
if cls.__name__ == "VehicleSpeedSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _speed_msg(self, speed):
pass
@@ -686,12 +674,6 @@ class AngleSteeringSafetyTest(VehicleSpeedSafetyTest):
# Real time limits
LATERAL_FREQUENCY: int = -1 # Hz
@classmethod
def setUpClass(cls):
if cls.__name__ == "AngleSteeringSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _angle_cmd_msg(self, angle: float, enabled: bool, increment_timer: bool = True):
pass
@@ -831,12 +813,6 @@ class CurvatureSteeringSafetyTest(VehicleSpeedSafetyTest):
CURVATURE_TO_CAN: float
SEND_RATE: float
@classmethod
def setUpClass(cls):
if cls.__name__ == "CurvatureSteeringSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _curvature_cmd_msg(self, curvature: float, steer_req: bool):
pass
@@ -942,12 +918,6 @@ class SafetyTest(SafetyTestBase):
FWD_BLACKLISTED_ADDRS: dict[int, list[int]] = {} # {bus: [addr]}
FWD_BUS_LOOKUP: dict[int, int] = {0: 2, 2: 0}
@classmethod
def setUpClass(cls):
if cls.__name__ == "SafetyTest" or cls.__name__.endswith('Base'):
cls.safety = None
raise unittest.SkipTest
# ***** standard tests for all safety modes *****
def test_tx_msg_in_scanned_range(self):
@@ -969,9 +939,10 @@ class SafetyTest(SafetyTestBase):
self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(bus, addr), f"{addr=:#x} from {bus=} to {fwd_bus=}")
def test_spam_can_buses(self):
tx_msgs = {(addr, bus) for addr, bus in self.TX_MSGS}
for bus in range(4):
for addr in self.SCANNED_ADDRS:
if [addr, bus] not in self.TX_MSGS:
if (addr, bus) not in tx_msgs:
self.assertFalse(self._tx(make_msg(bus, addr, 8)), f"allowed TX {addr=} {bus=}")
def test_default_controls_not_allowed(self):
@@ -1074,12 +1045,6 @@ class CarSafetyTest(SafetyTest, MadsSafetyTestBase):
GAS_PRESSED_THRESHOLD = 0
RELAY_MALFUNCTION_ADDRS: dict[int, tuple[int, ...]] | None = None
@classmethod
def setUpClass(cls):
if cls.__name__ == "CarSafetyTest" or cls.__name__.endswith('Base'):
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _user_brake_msg(self, brake):
pass
@@ -1251,10 +1216,12 @@ class CarSafetyTest(SafetyTest, MadsSafetyTestBase):
self.assertEqual(self.safety.get_controls_allowed(), within_delta)
def test_safety_tick(self):
self.safety.set_timer(int(2e6))
self.safety.set_controls_allowed(True)
self.safety.set_controls_allowed_lateral(True)
self.safety.safety_tick_current_safety_config()
self.assertFalse(self.safety.get_controls_allowed())
self.assertFalse(self.safety.get_controls_allowed_lateral())
self.assertFalse(self.safety.safety_config_valid())
# Missing valid RX messages must disable controls even before they time out.
for elapsed in (0, int(2e6)):
with self.subTest(elapsed=elapsed):
self._reset_safety_hooks()
self.safety.set_timer(elapsed)
self.safety.set_controls_allowed(True)
self.safety.safety_tick()
self.assertFalse(self.safety.get_controls_allowed())
self.assertFalse(self.safety.safety_config_valid())
@@ -1,5 +1,3 @@
import unittest
from opendbc.sunnypilot.car.hyundai.values import HyundaiSafetyFlagsSP
import opendbc.safety.tests.common as common
from opendbc.safety.tests.libsafety import libsafety_py
@@ -78,12 +76,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
DISABLED_ECU_UDS_MSG: tuple[int, int]
DISABLED_ECU_ACTUATION_MSG: tuple[int, int]
@classmethod
def setUpClass(cls):
if cls.__name__ == "HyundaiLongitudinalBase":
cls.safety = None
raise unittest.SkipTest
# override these tests from CarSafetyTest, hyundai longitudinal uses button enable
def test_disable_control_allowed_from_cruise(self):
pass
@@ -1,4 +1,5 @@
import os
import re
import subprocess
import tempfile
from pathlib import Path
@@ -20,12 +21,14 @@ def _build_libsafety(release: bool = False) -> str:
'-std=gnu11', '-Wfatal-errors', '-Wno-pointer-to-int-cast',
'-g', '-O0', '-fno-omit-frame-pointer',
]
ldflags = [
'-fsanitize=undefined', '-fno-sanitize-recover=undefined',
]
# Coverage must exclude the branches inserted by UBSan.
if os.environ.get("SAFETY_COVERAGE") == "1":
ldflags = ['-fprofile-arcs', '-ftest-coverage'] if not release else []
else:
ldflags = ['-fsanitize=undefined', '-fno-sanitize-recover=undefined']
cflags += ldflags
if not release:
cflags += ['-DALLOW_DEBUG', '-fprofile-arcs', '-ftest-coverage']
ldflags += ['-fprofile-arcs', '-ftest-coverage']
cflags += ['-DALLOW_DEBUG']
fd, safety_os = tempfile.mkstemp(suffix='.os', dir=libsafety_dir)
os.close(fd)
@@ -37,114 +40,38 @@ def _build_libsafety(release: bool = False) -> str:
return libsafety_so
def cdef_from_file(path: Path) -> str:
source = path.read_text()
source = re.sub(r"//[^\n]*|/\*.*?\*/", "", source, flags=re.DOTALL)
source = re.sub(r"__attribute__\(\(.*\)\)", "", source)
# Keep integer constants, type declarations, and function signatures, including definitions.
constants = re.findall(r"^#define \w+ \d+[UuLl]*[ \t]*$", source, re.MULTILINE)
types = re.findall(r"^(?:typedef|struct|enum)\b(?:[^;{]|\{[^}]*\})+;", source, re.MULTILINE)
functions = re.findall(r"^((?!typedef\b)\w[\w *]*\b\w+\([^;{}]*\))\s*[;{]", source, re.MULTILINE)
return "\n".join([*constants, *types, *(f"{signature};" for signature in dict.fromkeys(functions))])
ffi = FFI()
safety_dir = Path(libsafety_dir).parents[1]
ffi.cdef(cdef_from_file(safety_dir / "can.h"), packed=True)
for path in (safety_dir / "declarations.h", safety_dir / "ignition.h", safety_dir / "sunnypilot" / "mads_declarations.h", Path(libsafety_dir) / "safety.c"):
ffi.cdef(cdef_from_file(path))
ffi.cdef("""
typedef struct {
unsigned char fd : 1;
unsigned char bus : 3;
unsigned char data_len_code : 4;
unsigned char rejected : 1;
unsigned char returned : 1;
unsigned char extended : 1;
unsigned int addr : 29;
unsigned char checksum;
unsigned char data[64];
} CANPacket_t;
""", packed=True)
class CANPacket:
pass
# Functions not captured by cdef_from_file (macros, non-standard formatting, or generated)
ffi.cdef("""
bool safety_rx_hook(CANPacket_t *msg);
bool safety_tx_hook(CANPacket_t *msg);
int safety_fwd_hook(int bus_num, int addr);
int set_safety_hooks(uint16_t mode, uint16_t param);
void set_controls_allowed(bool c);
bool get_controls_allowed(void);
bool get_longitudinal_allowed(void);
void set_alternative_experience(int mode);
int get_alternative_experience(void);
void set_relay_malfunction(bool c);
bool get_relay_malfunction(void);
bool get_gas_pressed_prev(void);
void set_gas_pressed_prev(bool);
bool get_brake_pressed_prev(void);
bool get_regen_braking_prev(void);
bool get_steering_disengage_prev(void);
bool get_acc_main_on(void);
float get_vehicle_speed_min(void);
float get_vehicle_speed_max(void);
int get_current_safety_mode(void);
int get_current_safety_param(void);
void set_torque_meas(int min, int max);
int get_torque_meas_min(void);
int get_torque_meas_max(void);
void set_torque_driver(int min, int max);
int get_torque_driver_min(void);
int get_torque_driver_max(void);
void set_desired_torque_last(int t);
void set_rt_torque_last(int t);
void set_desired_angle_last(int t);
int get_desired_angle_last();
void set_angle_meas(int min, int max);
int get_angle_meas_min(void);
int get_angle_meas_max(void);
void set_desired_curvature_last(int t);
int get_desired_curvature_last();
void set_curvature_meas(int min, int max);
int get_curvature_meas_min(void);
int get_curvature_meas_max(void);
bool get_cruise_engaged_prev(void);
void set_cruise_engaged_prev(bool engaged);
bool get_vehicle_moving(void);
void set_timer(uint32_t t);
void safety_tick_current_safety_config();
bool safety_config_valid();
void init_tests(void);
void set_honda_fwd_brake(bool c);
bool get_honda_fwd_brake(void);
void set_honda_alt_brake_msg(bool c);
int get_desired_angle_last(void);
void set_honda_bosch_long(bool c);
int get_honda_hw(void);
void set_ignition_can(bool c);
uint32_t get_acc_main_on_mismatches(void);
int get_temp_debug(void);
void mutation_set_active_mutant(int id);
int mutation_get_active_mutant(void);
void ignition_can_hook(const CANPacket_t *msg);
bool get_ignition_can(void);
void set_ignition_can(bool c);
bool get_controls_allowed_lateral(void);
bool get_controls_requested_lateral(void);
void set_current_safety_param_sp(uint16_t param);
uint16_t get_current_safety_param_sp(void);
bool get_enable_mads(void);
bool get_disengage_lateral_on_brake(void);
bool get_pause_lateral_on_brake(void);
void set_mads_button_press(int mads_button_press);
void set_controls_allowed_lateral(bool c);
void set_controls_requested_lateral(bool c);
bool get_mads_acc_main(void);
void set_acc_main_on(bool c);
int get_mads_button_press(void);
void mads_set_current_disengage_reason(int reason);
int mads_get_current_disengage_reason(void);
int get_temp_debug(void);
uint32_t get_acc_main_on_mismatches(void);
void set_mads_params(bool enable_mads, bool disengage_lateral_on_brake, bool pause_lateral_on_brake);
void mads_apply_alternative_experience(int mode);
void tick_mads_state(bool vm, bool acc_main, bool op_allowed, bool braking, bool steering_disengage);
void set_heartbeat_engaged_mads(bool c);
void mads_heartbeat_engaged_check(void);
void set_steering_disengage(bool c);
int get_gas_interceptor_prev(void);
""")
class LibSafety:
@@ -13,10 +13,6 @@ uint32_t microsecond_timer_get(void) {
#include "opendbc/safety/safety.h"
#include "opendbc/safety/ignition.h"
void safety_tick_current_safety_config() {
safety_tick(&current_safety_config);
}
bool safety_config_valid() {
if (current_safety_config.rx_checks_len <= 0) {
printf("missing RX checks\n");
@@ -54,20 +50,16 @@ void set_relay_malfunction(bool c){
relay_malfunction = c;
}
void set_ignition_can(bool c){
ignition_can = c;
}
bool get_controls_allowed(void){
return controls_allowed;
}
bool get_ignition_can(void){
return ignition_can;
bool get_safety_rx_checks_invalid(void){
return safety_rx_checks_invalid;
}
int get_alternative_experience(void){
return alternative_experience;
bool get_ignition_can(void){
return ignition_can;
}
bool get_relay_malfunction(void){
@@ -168,10 +160,6 @@ void set_desired_angle_last(int t){
desired_angle_last = t;
}
int get_desired_angle_last(void){
return desired_angle_last;
}
void set_angle_meas(int min, int max){
angle_meas.min = min;
angle_meas.max = max;
@@ -213,14 +201,6 @@ void set_honda_alt_brake_msg(bool c){
honda_alt_brake_msg = c;
}
void set_honda_bosch_long(bool c){
honda_bosch_long = c;
}
int get_honda_hw(void) {
return honda_hw;
}
void set_honda_fwd_brake(bool c){
honda_fwd_brake = c;
}
@@ -573,7 +573,7 @@ class MadsSafetyTestBase(unittest.TestCase):
# Simulate message lag — safety_tick clears both controls_allowed and controls_allowed_lateral
self.safety.set_timer(int(2e6))
self.safety.safety_tick_current_safety_config()
self.safety.safety_tick()
self.assertFalse(self.safety.get_controls_allowed_lateral())
self.assertFalse(self.safety.get_controls_allowed_lateral())
self.assertFalse(self.safety.get_controls_allowed())
@@ -461,7 +461,6 @@ def compile_mutated_library(preprocessed_source, sites, output_so):
prelude = """
static int __mutation_active_id = -1;
void mutation_set_active_mutant(int id) { __mutation_active_id = id; }
int mutation_get_active_mutant(void) { return __mutation_active_id; }
"""
marker_re = re.compile(r'^\s*#\s+\d+\s+"[^\n]*\n?', re.MULTILINE)
instrumented = prelude + marker_re.sub("", instrumented)
@@ -40,6 +40,9 @@ def replay_drive(msgs, safety_mode, param, alternative_experience, param_sp):
print(f" disengage lateral on brake: {_disengage_lateral_on_brake}")
print(f" pause lateral on brake: {_pause_lateral_on_brake}")
if not any(m.which() == "sentinel" and m.sentinel.type == "startOfRoute" for m in msgs):
print("WARNING: Replay starts mid-route; missing prior safety state may cause safety violations that did not appear in the route.")
init_segment(safety, msgs, safety_mode, param)
rx_tot, rx_invalid, tx_tot, tx_blocked, tx_controls, tx_controls_lateral, tx_controls_blocked, tx_controls_lateral_blocked = 0, 0, 0, 0, 0, 0, 0, 0
@@ -62,7 +65,7 @@ def replay_drive(msgs, safety_mode, param, alternative_experience, param_sp):
# skip start and end of route, warm up/down period
if msg.logMonoTime - start_t > 1e9 and end_t - msg.logMonoTime > 1e9:
safety.safety_tick_current_safety_config()
safety.safety_tick()
safety_tick_rx_invalid |= not safety.safety_config_valid() or safety_tick_rx_invalid
if msg.which() == 'sendcan':
+7 -3
View File
@@ -6,11 +6,15 @@ cd $DIR
source ../../../setup.sh
# reset coverage data
rm -f ./libsafety/*.gcda
# TODO: get UBSan and coverage without running the tests twice.
# Run UBSan separately so its checks do not count as coverage branches.
SAFETY_COVERAGE=0 python -m unittest discover -s .
# reset coverage data, including metadata from previous builds
rm -f ./libsafety/*.gcda ./libsafety/*.gcno
# run safety tests and generate coverage data
python -m unittest discover -s .
SAFETY_COVERAGE=1 python -m unittest discover -s .
# NOTE: we accept that these tools will have slight differences,
# and in return, we get to use the stock toolchain instead of
+21 -12
View File
@@ -3,21 +3,14 @@ import unittest
from opendbc.car.structs import CarParams
import opendbc.safety.tests.common as common
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.common import CANPackerSafety
class TestBody(common.SafetyTest):
DBC = "comma_body"
SAFETY_MODEL = CarParams.SafetyModel.body
TX_MSGS = [[0x250, 0], [0x251, 0],
[0x1, 0], [0x1, 1], [0x1, 2], [0x1, 3]]
FWD_BUS_LOOKUP = {}
def setUp(self):
self.packer = CANPackerSafety("comma_body")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.body, 0)
self.safety.init_tests()
def _motors_data_msg(self, speed_l, speed_r):
values = {"SPEED_L": speed_l, "SPEED_R": speed_r}
return self.packer.make_can_msg_safety("MOTORS_DATA", 0, values)
@@ -36,6 +29,23 @@ class TestBody(common.SafetyTest):
self.assertTrue(self._rx(self._motors_data_msg(0, 0)))
self.assertTrue(self.safety.get_controls_allowed())
self._reset_safety_hooks()
for _ in range(16):
self.assertTrue(self._rx(self._motors_data_msg(0, 0)))
msg = self._motors_data_msg(0, 0)
msg[0].data[7] ^= 0xff
self.assertFalse(self._rx(msg))
self._reset_safety_hooks()
for _ in range(16):
self.assertTrue(self._rx(self._motors_data_msg(0, 0)))
msg = self._motors_data_msg(0, 0)
for _ in range(common.MAX_WRONG_COUNTERS + 1):
valid = self._rx(msg)
self.assertFalse(valid)
def test_tx_hook(self):
self.assertFalse(self._tx(self._torque_cmd_msg(0, 0)))
self.safety.set_controls_allowed(True)
@@ -48,9 +58,8 @@ class TestBody(common.SafetyTest):
# 0xdeadfaceU allowed for CAN flashing mode
self.assertTrue(self._tx(common.make_msg(0, 0x250, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0\x0a')))
self.assertFalse(self._tx(common.make_msg(0, 0x250, dat=b'\xcf\xfa\xad\xde\x1e\x0b\xb0\x0a'))) # wrong signature
self.assertFalse(self._tx(common.make_msg(0, 0x250, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0'))) # not correct data/len
self.assertFalse(self._tx(common.make_msg(0, 0x251, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0\x0a'))) # wrong address
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,212 @@
#!/usr/bin/env python3
import itertools
import unittest
import numpy as np
from opendbc.car.byd.carcontroller import get_safety_CP
from opendbc.car.byd.values import CarControllerParams
from opendbc.car.lateral import get_max_angle_delta_vm, get_max_angle_vm
from opendbc.car.structs import CarParams
from opendbc.car.vehicle_model import VehicleModel
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import away_round
STEERING_MODULE_ADAS = 0x1E2
LKAS_HUD_ADAS = 0x316
PCM_BUTTONS = 0x3B0
def safety_max_can(max_angle_float, can_offset=0):
# Matches C: max_angle_can = (int)(max_angle * 10 + 1.) which is floor(max_angle * 10) + 1
return int(max_angle_float * 10 + 1.) + can_offset
class TestBydSafety(common.CarSafetyTest, common.AngleSteeringSafetyTest):
DBC = "byd_atto3"
SAFETY_MODEL = CarParams.SafetyModel.byd
RELAY_MALFUNCTION_ADDRS = {0: (STEERING_MODULE_ADAS, LKAS_HUD_ADAS)}
FWD_BLACKLISTED_ADDRS = {2: [STEERING_MODULE_ADAS, LKAS_HUD_ADAS]}
TX_MSGS = [[STEERING_MODULE_ADAS, 0], [LKAS_HUD_ADAS, 0], [PCM_BUTTONS, 0]]
MAIN_BUS = 0
CAM_BUS = 2
STEER_ANGLE_MAX = 390 # deg, EPS fault limit
DEG_TO_CAN = 10
# BYD uses get_max_angle_delta_vm and get_max_angle_vm for lateral accel and jerk limits
ANGLE_RATE_BP = None
ANGLE_RATE_UP = None
ANGLE_RATE_DOWN = None
# Real time limits
LATERAL_FREQUENCY = 50 # Hz
def _get_steer_cmd_angle_max(self, speed):
return get_max_angle_vm(max(speed, 1), self.VM, CarControllerParams)
def setUp(self):
super().setUp()
self.VM = VehicleModel(get_safety_CP())
def _angle_cmd_msg(self, angle: float, enabled: bool, increment_timer: bool = True):
values = {"STEER_ANGLE": angle, "STEER_REQ": 1 if enabled else 0, "STEER_REQ_ACTIVE_LOW": 0 if enabled else 1}
if increment_timer:
self.safety.set_timer(self.__class__.cnt_angle_cmd * int(1e6 / self.LATERAL_FREQUENCY))
self.__class__.cnt_angle_cmd += 1
return self.packer.make_can_msg_safety("STEERING_MODULE_ADAS", self.MAIN_BUS, values)
cnt_angle_cmd = 0
def _angle_meas_msg(self, angle: float):
values = {"STEER_ANGLE_2": angle}
return self.packer.make_can_msg_safety("STEER_MODULE_2", self.MAIN_BUS, values)
def _pcm_status_msg(self, enable):
# ACC_STATE: 0=OFF, 3=ACC_ACTIVE
values = {"ACC_STATE": 3 if enable else 0}
return self.packer.make_can_msg_safety("ACC_HUD_ADAS", self.CAM_BUS, values)
def _speed_msg(self, speed):
values = {"WHEELSPEED_CLEAN": speed * 3.6}
return self.packer.make_can_msg_safety("WHEELSPEED_CLEAN", self.MAIN_BUS, values)
def _user_brake_msg(self, brake):
values = {"BRAKE_PRESSED": 1 if brake else 0}
return self.packer.make_can_msg_safety("DRIVE_STATE", self.MAIN_BUS, values)
def _user_gas_msg(self, gas):
values = {"RAW_THROTTLE": int(gas * 100)}
return self.packer.make_can_msg_safety("DRIVE_STATE", self.MAIN_BUS, values)
def test_cruise_buttons(self):
buttons = ("SET_BTN", "RES_BTN", "LKAS_ON_BTN", "DEC_DISTANCE_BTN", "INC_DISTANCE_BTN", "ACC_ON_BTN")
for cruise_engaged, controls_allowed in itertools.product((False, True), repeat=2):
self.assertTrue(self._rx(self._pcm_status_msg(cruise_engaged)))
self.safety.set_controls_allowed(controls_allowed)
for pressed in itertools.product((False, True), repeat=len(buttons)):
values = dict(zip(buttons, pressed, strict=True))
values.update(SET_ME_1_1=1, SET_ME_1_2=1)
with self.subTest(cruise_engaged=cruise_engaged, controls_allowed=controls_allowed, buttons=pressed):
msg = self.packer.make_can_msg_safety("PCM_BUTTONS", self.MAIN_BUS, values)
should_tx = not any(pressed[:-1]) and (not pressed[-1] or cruise_engaged)
self.assertEqual(should_tx, self._tx(msg))
def test_rx_checksums(self):
for name, bus, signal, initial, corrupt in (
("WHEELSPEED_CLEAN", self.MAIN_BUS, "WHEELSPEED_CLEAN", 72, 0),
("ACC_HUD_ADAS", self.CAM_BUS, "ACC_STATE", 0, 3),
):
for byte in range(8):
with self.subTest(message=name, byte=byte):
self.safety.set_safety_hooks(CarParams.SafetyModel.byd, 0)
self.safety.init_tests()
for _ in range(16):
msg = self.packer.make_can_msg_safety(name, bus, {signal: initial})
self.assertTrue(self._rx(msg))
speed_min = self.safety.get_vehicle_speed_min()
speed_max = self.safety.get_vehicle_speed_max()
msg = self.packer.make_can_msg_safety(name, bus, {signal: corrupt})
msg[0].data[byte] ^= 0xFF
self.safety.set_controls_allowed(name == "WHEELSPEED_CLEAN")
self.assertFalse(self._rx(msg))
self.assertFalse(self.safety.get_controls_allowed())
self.assertEqual(speed_min, self.safety.get_vehicle_speed_min())
self.assertEqual(speed_max, self.safety.get_vehicle_speed_max())
def test_rx_counters(self):
for name, bus, signal, value in (
("WHEELSPEED_CLEAN", self.MAIN_BUS, "WHEELSPEED_CLEAN", 72),
("ACC_HUD_ADAS", self.CAM_BUS, "ACC_STATE", 3),
):
with self.subTest(message=name):
# Check both counter locations and rollover with valid checksums.
for _ in range(32):
msg = self.packer.make_can_msg_safety(name, bus, {signal: value})
self.assertTrue(self._rx(msg))
self.safety.set_controls_allowed(True)
# Replayed frames are rejected after the common counter tolerance.
for i in range(common.MAX_WRONG_COUNTERS + 1):
should_rx = i < common.MAX_WRONG_COUNTERS - 1
self.assertEqual(should_rx, self._rx(msg))
self.assertEqual(should_rx, self.safety.get_controls_allowed())
# A valid sequence clears the counter faults.
for _ in range(common.MAX_WRONG_COUNTERS):
msg = self.packer.make_can_msg_safety(name, bus, {signal: 0})
self.assertTrue(self._rx(msg))
def test_angle_cmd_when_enabled(self):
# We properly test lateral acceleration and jerk below
pass
def test_lateral_accel_limit(self):
for speed in np.linspace(0, 40, 100):
speed = max(speed, 1)
# match both CAN encoding (0.1 kph/LSB) and VEHICLE_SPEED_FACTOR=1000 rounding in UPDATE_VEHICLE_SPEED
sent = speed + 1
sent_can = away_round(sent / 0.1 * 3.6) * 0.1 / 3.6
speed = round(sent_can * 1000) / 1000 - 1
for sign in (-1, 1):
self.safety.set_controls_allowed(True)
self._reset_speed_measurement(speed + 1) # safety fudges the speed
max_angle_float = get_max_angle_vm(speed, self.VM, CarControllerParams)
# at limit (safety tolerance adds 1 CAN unit)
max_angle_can = safety_max_can(max_angle_float)
max_angle_can = min(max_angle_can, self.STEER_ANGLE_MAX * self.DEG_TO_CAN)
max_angle = sign * max_angle_can / self.DEG_TO_CAN
self.safety.set_desired_angle_last(sign * max_angle_can)
self.assertTrue(self._tx(self._angle_cmd_msg(max_angle, True)))
# 1 unit above limit
over_can = safety_max_can(max_angle_float, 1)
over_can_clipped = min(over_can, self.STEER_ANGLE_MAX * self.DEG_TO_CAN)
over_angle = sign * over_can_clipped / self.DEG_TO_CAN
self._tx(self._angle_cmd_msg(over_angle, True))
# at low speeds max angle is above STEER_ANGLE_MAX, so adding 1 has no effect
should_tx = over_can >= self.STEER_ANGLE_MAX * self.DEG_TO_CAN
self.assertEqual(should_tx, self._tx(self._angle_cmd_msg(over_angle, True)))
def test_lateral_jerk_limit(self):
for speed in np.linspace(0, 40, 100):
speed = max(speed, 1)
# match both CAN encoding (0.1 kph/LSB) and VEHICLE_SPEED_FACTOR=1000 rounding in UPDATE_VEHICLE_SPEED
sent = speed + 1
sent_can = away_round(sent / 0.1 * 3.6) * 0.1 / 3.6
speed = round(sent_can * 1000) / 1000 - 1
for sign in (-1, 1):
self.safety.set_controls_allowed(True)
self._reset_speed_measurement(speed + 1) # safety fudges the speed
self._tx(self._angle_cmd_msg(0, True))
max_delta_float = get_max_angle_delta_vm(speed, self.VM, CarControllerParams)
# Stay within limits
# Up
max_delta_can = safety_max_can(max_delta_float)
max_angle_delta = sign * max_delta_can / self.DEG_TO_CAN
self.assertTrue(self._tx(self._angle_cmd_msg(max_angle_delta, True)))
# Don't change
self.assertTrue(self._tx(self._angle_cmd_msg(max_angle_delta, True)))
# Down
self.assertTrue(self._tx(self._angle_cmd_msg(0, True)))
# Inject too high rates
# Up
over_delta_can = safety_max_can(max_delta_float, 1)
max_angle_delta = sign * over_delta_can / self.DEG_TO_CAN
self.assertFalse(self._tx(self._angle_cmd_msg(max_angle_delta, True)))
# Don't change
self.safety.set_desired_angle_last(sign * over_delta_can)
self.assertTrue(self._tx(self._angle_cmd_msg(max_angle_delta, True)))
# Down
self.assertFalse(self._tx(self._angle_cmd_msg(0, True)))
# Recover
self.assertTrue(self._tx(self._angle_cmd_msg(0, True)))
if __name__ == "__main__":
unittest.main()
@@ -3,12 +3,11 @@ import unittest
from opendbc.car.chrysler.values import ChryslerSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
class TestChryslerSafety(common.CarSafetyTest, common.MotorTorqueSteeringSafetyTest):
DBC = "chrysler_pacifica_2017_hybrid_generated"
SAFETY_MODEL = CarParams.SafetyModel.chrysler
TX_MSGS = [[0x23B, 0], [0x292, 0], [0x2A6, 0], [0x2D9, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0x292, 0x2A6, 0x2D9)}
FWD_BLACKLISTED_ADDRS = {2: [0x292, 0x2A6, 0x2D9]}
@@ -23,12 +22,6 @@ class TestChryslerSafety(common.CarSafetyTest, common.MotorTorqueSteeringSafetyT
DAS_BUS = 0
def setUp(self):
self.packer = CANPackerSafety("chrysler_pacifica_2017_hybrid_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.chrysler, 0)
self.safety.init_tests()
def _button_msg(self, cancel=False, resume=False, accel=False, decel=False):
values = {"ACC_Cancel": cancel, "ACC_Resume": resume, "ACC_Accel": accel, "ACC_Decel": decel}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS", self.DAS_BUS, values)
@@ -96,9 +89,11 @@ class TestChryslerSafety(common.CarSafetyTest, common.MotorTorqueSteeringSafetyT
def _lkas_button_msg(self, enabled):
values = {"TOGGLE_LKAS": enabled}
return self.packer.make_can_msg_safety("TRACTION_BUTTON", 0, values)
class TestChryslerRamDTSafety(TestChryslerSafety):
DBC = "chrysler_ram_dt_generated"
SAFETY_PARAM = ChryslerSafetyFlags.RAM_DT
TX_MSGS = [[0xB1, 2], [0xA6, 0], [0xFA, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0xA6, 0xFA)}
FWD_BLACKLISTED_ADDRS = {2: [0xA6, 0xFA]}
@@ -111,12 +106,6 @@ class TestChryslerRamDTSafety(TestChryslerSafety):
LKAS_ACTIVE_VALUE = 2
def setUp(self):
self.packer = CANPackerSafety("chrysler_ram_dt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.chrysler, ChryslerSafetyFlags.RAM_DT)
self.safety.init_tests()
def _speed_msg(self, speed):
values = {"Vehicle_Speed": speed}
return self.packer.make_can_msg_safety("ESP_8", 0, values)
@@ -124,9 +113,11 @@ class TestChryslerRamDTSafety(TestChryslerSafety):
def _lkas_button_msg(self, enabled):
values = {"LKAS_Button": enabled}
return self.packer.make_can_msg_safety("Center_Stack_2", 0, values)
class TestChryslerRamHDSafety(TestChryslerSafety):
DBC = "chrysler_ram_hd_generated"
SAFETY_PARAM = ChryslerSafetyFlags.RAM_HD
TX_MSGS = [[0x275, 0], [0x276, 0], [0x23A, 2]]
RELAY_MALFUNCTION_ADDRS = {0: (0x276, 0x275)}
FWD_BLACKLISTED_ADDRS = {2: [0x275, 0x276]}
@@ -140,12 +131,6 @@ class TestChryslerRamHDSafety(TestChryslerSafety):
LKAS_ACTIVE_VALUE = 2
def setUp(self):
self.packer = CANPackerSafety("chrysler_ram_hd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.chrysler, ChryslerSafetyFlags.RAM_HD)
self.safety.init_tests()
def _speed_msg(self, speed):
values = {"Vehicle_Speed": speed}
return self.packer.make_can_msg_safety("ESP_8", 0, values)
@@ -153,7 +138,5 @@ class TestChryslerRamHDSafety(TestChryslerSafety):
def _lkas_button_msg(self, enabled):
values = {"LKAS_Button": enabled}
return self.packer.make_can_msg_safety("Center_Stack_2", 0, values)
if __name__ == "__main__":
unittest.main()
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
class TestChryslerCuswSafety(common.CarSafetyTest, common.MotorTorqueSteeringSafetyTest):
DBC = "chrysler_cusw"
SAFETY_MODEL = CarParams.SafetyModel.chryslerCusw
TX_MSGS = [[0x1F6, 0], [0x2FA, 0], [0x5DC, 0]]
STANDSTILL_THRESHOLD = 0
RELAY_MALFUNCTION_ADDRS = {0: (0x1F6, 0x5DC)}
@@ -18,12 +17,6 @@ class TestChryslerCuswSafety(common.CarSafetyTest, common.MotorTorqueSteeringSaf
MAX_RT_DELTA = 150
MAX_TORQUE_ERROR = 80
def setUp(self):
self.packer = CANPackerSafety("chrysler_cusw")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.chryslerCusw, 0)
self.safety.init_tests()
def _button_msg(self, cancel=False, resume=False):
values = {"ACC_Cancel": cancel, "ACC_Resume": resume}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS", 0, values)
@@ -56,6 +49,8 @@ class TestChryslerCuswSafety(common.CarSafetyTest, common.MotorTorqueSteeringSaf
for controls_allowed in (True, False):
self.safety.set_controls_allowed(controls_allowed)
self.assertFalse(self._tx(self._button_msg()))
# resume only while controls allowed
self.assertEqual(controls_allowed, self._tx(self._button_msg(resume=True)))
@@ -69,7 +64,5 @@ class TestChryslerCuswSafety(common.CarSafetyTest, common.MotorTorqueSteeringSaf
self.assertTrue(self._rx(self._torque_meas_msg(0)), f"{count=}")
self.assertTrue(self._rx(self._user_gas_msg(0)), f"{count=}")
self.assertTrue(self._rx(self._pcm_status_msg(False)), f"{count=}")
if __name__ == "__main__":
unittest.main()
@@ -3,9 +3,6 @@ import unittest
import opendbc.safety.tests.common as common
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
class TestDefaultRxHookBase(common.SafetyTest):
FWD_BUS_LOOKUP = {}
@@ -14,36 +11,20 @@ class TestDefaultRxHookBase(common.SafetyTest):
for bus in range(4):
for addr in self.SCANNED_ADDRS:
self.assertTrue(self._rx(common.make_msg(bus, addr, 8)), f"failed RX {addr=}")
class TestNoOutput(TestDefaultRxHookBase):
SAFETY_MODEL = CarParams.SafetyModel.noOutput
TX_MSGS = []
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.noOutput, 0)
self.safety.init_tests()
class TestSilent(TestNoOutput):
"""SILENT uses same hooks as NOOUTPUT"""
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.silent, 0)
self.safety.init_tests()
SAFETY_MODEL = CarParams.SafetyModel.silent
class TestAllOutput(TestDefaultRxHookBase):
SAFETY_MODEL = CarParams.SafetyModel.allOutput
# Allow all messages
TX_MSGS = [[addr, bus] for addr in common.SafetyTest.SCANNED_ADDRS
for bus in range(4)]
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.allOutput, 0)
self.safety.init_tests()
def test_spam_can_buses(self):
# asserts tx allowed for all scanned addrs
for bus in range(4):
@@ -58,17 +39,18 @@ class TestAllOutput(TestDefaultRxHookBase):
def test_tx_hook_on_wrong_safety_mode(self):
# No point, since we allow all messages
pass
class TestAllOutputPassthrough(TestAllOutput):
SAFETY_PARAM = 1
FWD_BLACKLISTED_ADDRS = {}
FWD_BUS_LOOKUP = {0: 2, 2: 0}
class TestSafetyFramework(common.SafetyTestBase):
SAFETY_MODEL = CarParams.SafetyModel.noOutput
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.allOutput, 1)
self.safety.init_tests()
def test_unsupported_safety_mode(self):
self.safety.set_controls_allowed(True)
self.assertEqual(self.safety.set_safety_hooks(0xFFFF, 0), -1)
self.assertFalse(self.safety.get_controls_allowed())
self.assertFalse(self.safety.safety_tx_hook(common.make_msg(0, 0x123)))
if __name__ == "__main__":
unittest.main()
@@ -4,24 +4,18 @@ import unittest
import opendbc.safety.tests.common as common
from opendbc.car.structs import CarParams
from opendbc.safety import DLC_TO_LEN
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.test_defaults import TestDefaultRxHookBase
GM_CAMERA_DIAG_ADDR = 0x24B
class TestElm327(TestDefaultRxHookBase):
SAFETY_MODEL = CarParams.SafetyModel.elm327
TX_MSGS = [[addr, bus] for addr in [GM_CAMERA_DIAG_ADDR, *range(0x600, 0x800),
*range(0x18DA00F1, 0x18DB00F1, 0x100), # 29-bit UDS physical addressing
*[0x18DB33F1], # 29-bit UDS functional address
] for bus in range(4)]
FWD_BUS_LOOKUP = {}
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.elm327, 0)
self.safety.init_tests()
def test_tx_hook(self):
# ensure we can transmit arbitrary data on allowed addresses
for bus in range(4):
@@ -46,7 +40,5 @@ class TestElm327(TestDefaultRxHookBase):
def test_tx_hook_on_wrong_safety_mode(self):
# No point, since we allow many diagnostic addresses
pass
if __name__ == "__main__":
unittest.main()
+23 -84
View File
@@ -7,8 +7,6 @@ import opendbc.safety.tests.common as common
from opendbc.car.lateral import MAX_LATERAL_ACCEL, MAX_LATERAL_JERK
from opendbc.car.ford.values import FordSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.common import CANPackerSafety
MSG_BrakeSysFeatures = 0x415 # RX from ABS, for vehicle speed
MSG_EngVehicleSpThrottle2 = 0x202 # RX from PCM, for second vehicle speed
@@ -20,50 +18,19 @@ MSG_Lane_Assist_Data1 = 0x3CA # TX by OP, Lane Keep Assist
MSG_LateralMotionControl = 0x3D3 # TX by OP, Lateral Control message
MSG_LateralMotionControl2 = 0x3D6 # TX by OP, alternate Lateral Control message
MSG_IPMA_Data = 0x3D8 # TX by OP, IPMA and LKAS user interface
def checksum(msg):
addr, dat, bus = msg
ret = bytearray(dat)
if addr == MSG_Yaw_Data_FD1:
chksum = dat[0] + dat[1] # VehRol_W_Actl
chksum += dat[2] + dat[3] # VehYaw_W_Actl
chksum += dat[5] # VehRollYaw_No_Cnt
chksum += dat[6] >> 6 # VehRolWActl_D_Qf
chksum += (dat[6] >> 4) & 0x3 # VehYawWActl_D_Qf
chksum = 0xff - (chksum & 0xff)
ret[4] = chksum
elif addr == MSG_BrakeSysFeatures:
chksum = dat[0] + dat[1] # Veh_V_ActlBrk
chksum += (dat[2] >> 2) & 0xf # VehVActlBrk_No_Cnt
chksum += dat[2] >> 6 # VehVActlBrk_D_Qf
chksum = 0xff - (chksum & 0xff)
ret[3] = chksum
elif addr == MSG_EngVehicleSpThrottle2:
chksum = (dat[2] >> 3) & 0xf # VehVActlEng_No_Cnt
chksum += (dat[4] >> 5) & 0x3 # VehVActlEng_D_Qf
chksum += dat[6] + dat[7] # Veh_V_ActlEng
chksum = 0xff - (chksum & 0xff)
ret[1] = chksum
return addr, ret, bus
class Buttons:
CANCEL = 0
RESUME = 1
TJA_TOGGLE = 2
# Ford safety has four different configurations tested here:
# * CAN with openpilot longitudinal
# * CAN FD with stock longitudinal
# * CAN FD with openpilot longitudinal
class TestFordSafetyBase(common.CarSafetyTest):
DBC = "ford_lincoln_base_pt"
SAFETY_MODEL = CarParams.SafetyModel.ford
STANDSTILL_THRESHOLD = 1
RELAY_MALFUNCTION_ADDRS = {0: (MSG_ACCDATA_3, MSG_Lane_Assist_Data1, MSG_LateralMotionControl,
MSG_LateralMotionControl2, MSG_IPMA_Data)}
@@ -80,13 +47,7 @@ class TestFordSafetyBase(common.CarSafetyTest):
CURVATURE_ERROR_MIN_SPEED = 10.0 # m/s
LATERAL_FREQUENCY = 20 # Hz, for per-frame jerk limit
cnt_speed = 0
cnt_speed_2 = 0
cnt_yaw_rate = 0
cnt_lat_ctl = 0
packer: CANPackerSafety
safety: libsafety_py.LibSafety
lat_ctl_frame = 0
def _get_max_curvature_can(self, speed):
fudged_speed = max(speed - 1.0, 1.0)
@@ -130,16 +91,14 @@ class TestFordSafetyBase(common.CarSafetyTest):
# ABS vehicle speed
def _speed_msg(self, speed: float, quality_flag=True):
values = {"Veh_V_ActlBrk": speed * 3.6, "VehVActlBrk_D_Qf": 3 if quality_flag else 0, "VehVActlBrk_No_Cnt": self.cnt_speed % 16}
self.__class__.cnt_speed += 1
return self.packer.make_can_msg_safety("BrakeSysFeatures", 0, values, fix_checksum=checksum)
values = {"Veh_V_ActlBrk": speed * 3.6, "VehVActlBrk_D_Qf": 3 if quality_flag else 0}
return self.packer.make_can_msg_safety("BrakeSysFeatures", 0, values)
# PCM vehicle speed
def _speed_msg_2(self, speed: float, quality_flag=True):
# Ford relies on speed for driver curvature limiting, so it checks two sources
values = {"Veh_V_ActlEng": speed * 3.6, "VehVActlEng_D_Qf": 3 if quality_flag else 0, "VehVActlEng_No_Cnt": self.cnt_speed_2 % 16}
self.__class__.cnt_speed_2 += 1
return self.packer.make_can_msg_safety("EngVehicleSpThrottle2", 0, values, fix_checksum=checksum)
values = {"Veh_V_ActlEng": speed * 3.6, "VehVActlEng_D_Qf": 3 if quality_flag else 0}
return self.packer.make_can_msg_safety("EngVehicleSpThrottle2", 0, values)
# Standstill state
def _vehicle_moving_msg(self, speed: float):
@@ -148,10 +107,8 @@ class TestFordSafetyBase(common.CarSafetyTest):
# Current curvature
def _yaw_rate_msg(self, curvature: float, speed: float, quality_flag=True):
values = {"VehYaw_W_Actl": curvature * speed, "VehYawWActl_D_Qf": 3 if quality_flag else 0,
"VehRollYaw_No_Cnt": self.cnt_yaw_rate % 256}
self.__class__.cnt_yaw_rate += 1
return self.packer.make_can_msg_safety("Yaw_Data_FD1", 0, values, fix_checksum=checksum)
values = {"VehYaw_W_Actl": curvature * speed, "VehYawWActl_D_Qf": 3 if quality_flag else 0}
return self.packer.make_can_msg_safety("Yaw_Data_FD1", 0, values)
# Drive throttle input
def _user_gas_msg(self, gas: float):
@@ -169,6 +126,11 @@ class TestFordSafetyBase(common.CarSafetyTest):
}
return self.packer.make_can_msg_safety("EngBrakeData", 0, values)
def test_enable_control_allowed_from_queue_assist(self):
msg = self.packer.make_can_msg_safety("EngBrakeData", 0, {"BpedDrvAppl_D_Actl": 1, "CcStat_D_Actl": 4})
self.assertTrue(self._rx(msg))
self.assertTrue(self.safety.get_controls_allowed())
# LKAS command
def _lkas_command_msg(self, action: int):
values = {
@@ -180,8 +142,8 @@ class TestFordSafetyBase(common.CarSafetyTest):
def _lat_ctl_msg(self, enabled: bool, path_offset: float, path_angle: float, curvature: float, curvature_rate: float,
increment_timer: bool = True):
if increment_timer:
self.safety.set_timer(self.cnt_lat_ctl * int(1e6 / self.LATERAL_FREQUENCY))
self.__class__.cnt_lat_ctl += 1
self.safety.set_timer(self.lat_ctl_frame * int(1e6 / self.LATERAL_FREQUENCY))
self.__class__.lat_ctl_frame += 1
if self.STEER_MESSAGE == MSG_LateralMotionControl:
values = {
"LatCtl_D_Rq": 1 if enabled else 0,
@@ -467,9 +429,9 @@ class TestFordSafetyBase(common.CarSafetyTest):
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._pcm_status_msg(main_button_msg_valid))
self.assertEqual(enable_mads and main_button_msg_valid, self.safety.get_controls_allowed_lateral())
class TestFordCANFDStockSafety(TestFordSafetyBase):
SAFETY_PARAM = FordSafetyFlags.CANFD
STEER_MESSAGE = MSG_LateralMotionControl2
TX_MSGS = [
@@ -481,14 +443,6 @@ class TestFordCANFDStockSafety(TestFordSafetyBase):
FWD_BLACKLISTED_ADDRS = {2: [MSG_ACCDATA_3, MSG_Lane_Assist_Data1, MSG_LateralMotionControl2,
MSG_IPMA_Data]}
def setUp(self):
self.packer = CANPackerSafety("ford_lincoln_base_pt")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.ford, FordSafetyFlags.CANFD)
self.safety.init_tests()
class TestFordLongitudinalSafetyBase(TestFordSafetyBase):
MAX_ACCEL = 2.0 # accel is used for brakes, but openpilot can set positive values
MIN_ACCEL = -3.5
@@ -538,9 +492,9 @@ class TestFordLongitudinalSafetyBase(TestFordSafetyBase):
should_tx = (controls_allowed and self.MIN_ACCEL <= brake <= self.MAX_ACCEL) or brake == self.INACTIVE_ACCEL
should_tx = should_tx and (controls_allowed or not brake_actuation)
self.assertEqual(should_tx, self._tx(self._acc_command_msg(self.INACTIVE_GAS, brake, brake_actuation)))
class TestFordLongitudinalSafety(TestFordLongitudinalSafetyBase):
# Make sure we enforce long safety even without long flag for CAN
SAFETY_PARAM = 0
STEER_MESSAGE = MSG_LateralMotionControl
TX_MSGS = [
@@ -552,16 +506,9 @@ class TestFordLongitudinalSafety(TestFordLongitudinalSafetyBase):
FWD_BLACKLISTED_ADDRS = {2: [MSG_ACCDATA, MSG_ACCDATA_3, MSG_Lane_Assist_Data1, MSG_LateralMotionControl,
MSG_IPMA_Data]}
def setUp(self):
self.packer = CANPackerSafety("ford_lincoln_base_pt")
self.safety = libsafety_py.libsafety
# Make sure we enforce long safety even without long flag for CAN
self.safety.set_safety_hooks(CarParams.SafetyModel.ford, 0)
self.safety.init_tests()
class TestFordCANFDLongitudinalSafety(TestFordLongitudinalSafetyBase):
SAFETY_PARAM = FordSafetyFlags.LONG_CONTROL | FordSafetyFlags.CANFD
STEER_MESSAGE = MSG_LateralMotionControl2
TX_MSGS = [
@@ -573,13 +520,5 @@ class TestFordCANFDLongitudinalSafety(TestFordLongitudinalSafetyBase):
FWD_BLACKLISTED_ADDRS = {2: [MSG_ACCDATA, MSG_ACCDATA_3, MSG_Lane_Assist_Data1, MSG_LateralMotionControl2,
MSG_IPMA_Data]}
def setUp(self):
self.packer = CANPackerSafety("ford_lincoln_base_pt")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.ford, FordSafetyFlags.LONG_CONTROL | FordSafetyFlags.CANFD)
self.safety.init_tests()
if __name__ == "__main__":
unittest.main()
+20 -63
View File
@@ -3,20 +3,15 @@ import unittest
from opendbc.car.gm.values import GMSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
from opendbc.sunnypilot.car.gm.values_ext import GMSafetyFlagsSP
class Buttons:
UNPRESS = 1
RES_ACCEL = 2
DECEL_SET = 3
CANCEL = 6
class GmLongitudinalBase(common.CarSafetyTest, common.LongitudinalGasBrakeSafetyTest):
RELAY_MALFUNCTION_ADDRS = {0: (0x180, 0x2CB), 2: (0x184,)} # ASCMLKASteeringCmd, ASCMGasRegenCmd, PSCMStatus
@@ -71,9 +66,10 @@ class GmLongitudinalBase(common.CarSafetyTest, common.LongitudinalGasBrakeSafety
self.safety.set_controls_allowed(1)
self._rx(self._button_msg(Buttons.CANCEL))
self.assertFalse(self.safety.get_controls_allowed())
class TestGmSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest):
DBC = "gm_global_a_powertrain_generated"
SAFETY_MODEL = CarParams.SafetyModel.gm
STANDSTILL_THRESHOLD = 10 * 0.0311
# Ensures ASCM is off on ASCM cars, and relay is not malfunctioning for camera-ACC cars
RELAY_MALFUNCTION_ADDRS = {0: (0x180,), 2: (0x184,)} # ASCMLKASteeringCmd, PSCMStatus
@@ -92,11 +88,8 @@ class TestGmSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTe
EXTRA_SAFETY_PARAM = 0
def setUp(self):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
super().setUp()
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, 0)
self.safety.init_tests()
def _pcm_status_msg(self, enable):
if self.PCM_CRUISE:
@@ -133,8 +126,6 @@ class TestGmSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTe
def _button_msg(self, buttons):
values = {"ACCButtons": buttons}
return self.packer.make_can_msg_safety("ASCMSteeringButton", self.BUTTONS_BUS, values)
class TestGmEVSafetyBase(TestGmSafetyBase):
EXTRA_SAFETY_PARAM = GMSafetyFlags.EV
@@ -142,8 +133,6 @@ class TestGmEVSafetyBase(TestGmSafetyBase):
def _user_regen_msg(self, regen):
values = {"RegenPaddle": 2 if regen else 0}
return self.packer.make_can_msg_safety("EBCMRegenPaddle", 0, values)
class TestGmAscmSafety(GmLongitudinalBase, TestGmSafetyBase):
TX_MSGS = [[0x180, 0], [0x409, 0], [0x40A, 0], [0x2CB, 0], [0x370, 0], # pt bus
[0xA1, 1], [0x306, 1], [0x308, 1], [0x310, 1], # obs bus
@@ -157,36 +146,24 @@ class TestGmAscmSafety(GmLongitudinalBase, TestGmSafetyBase):
MIN_GAS = -650 # maximum regen
INACTIVE_GAS = -650
def setUp(self):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, self.EXTRA_SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return self.EXTRA_SAFETY_PARAM
class TestGmAscmEVSafety(TestGmAscmSafety, TestGmEVSafetyBase):
pass
class TestGmCameraSafetyBase(TestGmSafetyBase):
def _user_brake_msg(self, brake):
values = {"BrakePressed": brake}
return self.packer.make_can_msg_safety("ECMEngineStatus", 0, values)
class TestGmCameraSafety(TestGmCameraSafetyBase):
TX_MSGS = [[0x180, 0], # pt bus
[0x184, 2]] # camera bus
FWD_BLACKLISTED_ADDRS = {2: [0x180], 0: [0x184]} # block LKAS message and PSCMStatus
BUTTONS_BUS = 2 # tx only
def setUp(self):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM
def test_buttons(self):
# Only CANCEL button is allowed while cruise is enabled
@@ -201,12 +178,8 @@ class TestGmCameraSafety(TestGmCameraSafetyBase):
for enabled in (True, False):
self._rx(self._pcm_status_msg(enabled))
self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL)))
class TestGmCameraEVSafety(TestGmCameraSafety, TestGmEVSafetyBase):
pass
class TestGmCameraLongitudinalSafety(GmLongitudinalBase, TestGmCameraSafetyBase):
TX_MSGS = [[0x180, 0], [0x315, 0], [0x2CB, 0], [0x370, 0], # pt bus
[0x184, 2]] # camera bus
@@ -218,45 +191,31 @@ class TestGmCameraLongitudinalSafety(GmLongitudinalBase, TestGmCameraSafetyBase)
MIN_GAS = -540 # maximum regen
INACTIVE_GAS = -500
def setUp(self):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | GMSafetyFlags.HW_CAM_LONG | self.EXTRA_SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return GMSafetyFlags.HW_CAM | GMSafetyFlags.HW_CAM_LONG | self.EXTRA_SAFETY_PARAM
class TestGmCameraLongitudinalEVSafety(TestGmCameraLongitudinalSafety, TestGmEVSafetyBase):
pass
class TestGmCameraNonACCSafety(TestGmCameraSafety):
@property
def SAFETY_PARAM(self):
return GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM
def setUp(self):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(GMSafetyFlagsSP.NON_ACC)
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM)
self.safety.init_tests()
def _pcm_status_msg(self, enable):
values = {"CruiseActive": enable}
return self.packer.make_can_msg_safety("ECMCruiseControl", 0, values)
class TestGmCameraEVNonACCSafety(TestGmCameraNonACCSafety, TestGmEVSafetyBase):
pass
class TestGmIgnition(common.SafetyTestBase):
DBC = "gm_global_a_powertrain_generated"
SAFETY_MODEL = None
class TestGmIgnition(unittest.TestCase):
TX_MSGS: list = []
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.init_tests()
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
def _msg(self, mode):
return self.packer.make_can_msg_safety("BCMGeneralPlatformStatus", 0, {"SystemPowerMode": mode})
@@ -270,7 +229,5 @@ class TestGmIgnition(unittest.TestCase):
self.assertTrue(self.safety.get_ignition_can())
self.safety.ignition_can_hook(self._msg(0))
self.assertFalse(self.safety.get_ignition_can())
if __name__ == "__main__":
unittest.main()
+39 -138
View File
@@ -6,14 +6,12 @@ from opendbc.car.honda.values import HondaSafetyFlags
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.car.structs import CarParams
from opendbc.safety.tests.common import CANPackerSafety, MAX_WRONG_COUNTERS
from opendbc.safety.tests.common import MAX_WRONG_COUNTERS
from opendbc.safety.tests.gas_interceptor_common import GasInterceptorSafetyTest
from opendbc.sunnypilot.car.honda.values_ext import HondaSafetyFlagsSP
HONDA_N_COMMON_TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x30C, 0], [0x33D, 0]]
class Btn:
NONE = 0
MAIN = 1
@@ -31,8 +29,6 @@ class Btn:
# * Bosch with Longitudinal Support
# * Bosch Radarless
# * Bosch Radarless with Longitudinal Support
class HondaButtonEnableBase(common.CarSafetyTest):
# override these inherited tests since we're using button enable
@@ -113,11 +109,11 @@ class HondaButtonEnableBase(common.CarSafetyTest):
self.assertFalse(self.safety.get_controls_allowed())
# counter
# reset wrong_counters to zero by sending valid messages
# Skip every other counter to trigger counter faults.
for i in range(MAX_WRONG_COUNTERS + 1):
self.__class__.cnt_speed += 1
self.__class__.cnt_button += 1
self.__class__.cnt_powertrain_data += 1
self._speed_msg(0)
self._button_msg(Btn.SET)
self._user_gas_msg(0)
if i < MAX_WRONG_COUNTERS:
self.safety.set_controls_allowed(1)
self._rx(self._button_msg(Btn.SET))
@@ -137,8 +133,6 @@ class HondaButtonEnableBase(common.CarSafetyTest):
self._rx(self._user_gas_msg(0))
self._rx(self._button_msg(Btn.SET, main_on=True))
self.assertTrue(self.safety.get_controls_allowed())
class HondaPcmEnableBase(common.CarSafetyTest):
def test_buttons(self):
@@ -164,8 +158,6 @@ class HondaPcmEnableBase(common.CarSafetyTest):
self.assertFalse(self.safety.get_controls_allowed())
else:
self.assertEqual(controls_allowed, self.safety.get_controls_allowed())
class HondaBase(common.CarSafetyTest):
MAX_BRAKE = 255
PT_BUS: int | None = None # must be set when inherited
@@ -194,28 +186,23 @@ class HondaBase(common.CarSafetyTest):
"ACC_STATUS": cruise_on,
"BRAKE_PRESSED": brake_pressed,
"PEDAL_GAS": gas_pressed,
"COUNTER": self.cnt_powertrain_data % 4
}
self.__class__.cnt_powertrain_data += 1
return self.packer.make_can_msg_safety("POWERTRAIN_DATA", self.PT_BUS, values)
def _pcm_status_msg(self, enable):
return self._powertrain_data_msg(cruise_on=enable)
def _speed_msg(self, speed):
values = {"XMISSION_SPEED": speed, "COUNTER": self.cnt_speed % 4}
self.__class__.cnt_speed += 1
values = {"XMISSION_SPEED": speed}
return self.packer.make_can_msg_safety("ENGINE_DATA", self.PT_BUS, values)
def _acc_state_msg(self, main_on):
values = {"MAIN_ON": main_on, "COUNTER": self.cnt_acc_state % 4}
self.__class__.cnt_acc_state += 1
values = {"MAIN_ON": main_on}
return self.packer.make_can_msg_safety("SCM_FEEDBACK", self.PT_BUS, values)
def _button_msg(self, buttons, main_on=False, bus=None):
bus = self.PT_BUS if bus is None else bus
values = {"CRUISE_BUTTONS": buttons, "COUNTER": self.cnt_button % 4}
self.__class__.cnt_button += 1
values = {"CRUISE_BUTTONS": buttons}
return self.packer.make_can_msg_safety("SCM_BUTTONS", bus, values)
def _user_brake_msg(self, brake):
@@ -279,12 +266,11 @@ class HondaBase(common.CarSafetyTest):
self.assertEqual(1, self.safety.get_mads_button_press())
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press())
# ********************* Honda Nidec **********************
class TestHondaNidecSafetyBase(HondaBase):
DBC = "honda_civic_touring_2016_can_generated"
SAFETY_MODEL = CarParams.SafetyModel.hondaNidec
TX_MSGS = HONDA_N_COMMON_TX_MSGS
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x194, 0x33D, 0x30C]}
RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x194, 0x33D, 0x30C)}
@@ -297,12 +283,6 @@ class TestHondaNidecSafetyBase(HondaBase):
BRAKE_SIG = "COMPUTER_BRAKE"
def setUp(self):
self.packer = CANPackerSafety("honda_civic_touring_2016_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, 0)
self.safety.init_tests()
def _send_brake_msg(self, brake, aeb_req=0, bus=0):
values = {self.BRAKE_SIG: brake, "AEB_REQ_1": aeb_req}
return self.packer.make_can_msg_safety("BRAKE_COMMAND", bus, values)
@@ -381,8 +361,6 @@ class TestHondaNidecPcmSafety(HondaPcmEnableBase, TestHondaNidecSafetyBase):
# Nidec doesn't disengage on falling edge of cruise. See comment in safety_honda.h
def test_disable_control_allowed_from_cruise(self):
pass
class TestHondaNidecGasInterceptorSafety(GasInterceptorSafetyTest, HondaButtonEnableBase, TestHondaNidecSafetyBase):
"""
Covers the Honda Nidec safety mode with a gas interceptor, switches to a button-enable car
@@ -392,49 +370,37 @@ class TestHondaNidecGasInterceptorSafety(GasInterceptorSafetyTest, HondaButtonEn
INTERCEPTOR_THRESHOLD = 492
def setUp(self):
self.packer = CANPackerSafety("honda_civic_touring_2016_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(HondaSafetyFlagsSP.GAS_INTERCEPTOR)
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, 0)
self.safety.init_tests()
class TestHondaNidecPcmAltSafety(TestHondaNidecPcmSafety):
"""
Covers the Honda Nidec safety mode with alt SCM messages
"""
def setUp(self):
self.packer = CANPackerSafety("acura_ilx_2016_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, HondaSafetyFlags.NIDEC_ALT)
self.safety.init_tests()
DBC = "acura_ilx_2016_can_generated"
SAFETY_PARAM = HondaSafetyFlags.NIDEC_ALT
def _acc_state_msg(self, main_on):
values = {"MAIN_ON": main_on, "COUNTER": self.cnt_acc_state % 4}
self.__class__.cnt_acc_state += 1
values = {"MAIN_ON": main_on}
return self.packer.make_can_msg_safety("SCM_BUTTONS", self.PT_BUS, values)
def _button_msg(self, buttons, main_on=False, bus=None):
bus = self.PT_BUS if bus is None else bus
values = {"CRUISE_BUTTONS": buttons, "MAIN_ON": main_on, "COUNTER": self.cnt_button % 4}
self.__class__.cnt_button += 1
values = {"CRUISE_BUTTONS": buttons, "MAIN_ON": main_on}
return self.packer.make_can_msg_safety("SCM_BUTTONS", bus, values)
class TestHondaNidecAltGasInterceptorSafety(GasInterceptorSafetyTest, HondaButtonEnableBase, TestHondaNidecSafetyBase):
"""
Covers the Honda Nidec safety mode with alt SCM messages and gas interceptor, switches to a button-enable car
"""
DBC = "acura_ilx_2016_can_generated"
SAFETY_PARAM = HondaSafetyFlags.NIDEC_ALT
TX_MSGS = HONDA_N_COMMON_TX_MSGS + [[0x200, 0]]
INTERCEPTOR_THRESHOLD = 492
def setUp(self):
self.packer = CANPackerSafety("acura_ilx_2016_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(HondaSafetyFlagsSP.GAS_INTERCEPTOR)
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, HondaSafetyFlags.NIDEC_ALT)
self.safety.init_tests()
def _acc_state_msg(self, main_on):
values = {"MAIN_ON": main_on, "COUNTER": self.cnt_acc_state % 4}
@@ -446,12 +412,11 @@ class TestHondaNidecAltGasInterceptorSafety(GasInterceptorSafetyTest, HondaButto
values = {"CRUISE_BUTTONS": buttons, "MAIN_ON": main_on, "COUNTER": self.cnt_button % 4}
self.__class__.cnt_button += 1
return self.packer.make_can_msg_safety("SCM_BUTTONS", bus, values)
# ********************* Honda Bosch **********************
class TestHondaBoschSafetyBase(HondaBase):
DBC = "honda_civic_hatchback_ex_2017_can_generated"
SAFETY_MODEL = CarParams.SafetyModel.hondaBosch
PT_BUS = 1
STEER_BUS = 0
BUTTONS_BUS = 1
@@ -460,13 +425,8 @@ class TestHondaBoschSafetyBase(HondaBase):
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D, 0x33DA, 0x33DB]}
RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0xE5, 0x33D, 0x33DA, 0x33DB)} # STEERING_CONTROL, BOSCH_SUPPLEMENTAL_1
def setUp(self):
self.packer = CANPackerSafety("honda_civic_hatchback_ex_2017_can_generated")
self.safety = libsafety_py.libsafety
def _alt_brake_msg(self, brake):
values = {"BRAKE_PRESSED": brake, "COUNTER": self.cnt_brake % 4}
self.__class__.cnt_brake += 1
values = {"BRAKE_PRESSED": brake}
return self.packer.make_can_msg_safety("BRAKE_MODULE", self.PT_BUS, values)
def _send_brake_msg(self, brake):
@@ -480,16 +440,11 @@ class TestHondaBoschSafetyBase(HondaBase):
# do not block resume if we are engaged already
self.safety.set_controls_allowed(1)
self.assertTrue(self._tx(self._button_msg(Btn.RESUME, bus=self.BUTTONS_BUS)))
class TestHondaBoschAltBrakeSafetyBase(TestHondaBoschSafetyBase):
"""
Base Bosch safety test class with an alternate brake message
"""
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.ALT_BRAKE)
self.safety.init_tests()
SAFETY_PARAM = HondaSafetyFlags.ALT_BRAKE
def _user_brake_msg(self, brake):
return self._alt_brake_msg(brake)
@@ -513,28 +468,20 @@ class TestHondaBoschAltBrakeSafetyBase(TestHondaBoschSafetyBase):
self.safety.set_controls_allowed(1)
self._rx(self._alt_brake_msg(1))
self.assertTrue(self.safety.get_controls_allowed())
class TestHondaBoschSafety(HondaPcmEnableBase, TestHondaBoschSafetyBase):
"""
Covers the Honda Bosch safety mode with stock longitudinal
"""
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, 0)
self.safety.init_tests()
class TestHondaBoschAltBrakeSafety(HondaPcmEnableBase, TestHondaBoschAltBrakeSafetyBase):
"""
Covers the Honda Bosch safety mode with stock longitudinal and an alternate brake message
"""
class TestHondaBoschLongSafety(HondaButtonEnableBase, TestHondaBoschSafetyBase):
"""
Covers the Honda Bosch safety mode with longitudinal control
"""
SAFETY_PARAM = HondaSafetyFlags.BOSCH_LONG
NO_GAS = -30000
MAX_GAS = 2000
MAX_ACCEL = 2.0 # accel is used for brakes, but openpilot can set positive values
@@ -546,11 +493,6 @@ class TestHondaBoschLongSafety(HondaButtonEnableBase, TestHondaBoschSafetyBase):
# 0x1DF is to test that radar is disabled
RELAY_MALFUNCTION_ADDRS = {1: (0xE4, 0x1DF, 0x33D, 0x33DA, 0x33DB)} # STEERING_CONTROL, ACC_CONTROL
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.BOSCH_LONG)
self.safety.init_tests()
def _send_gas_brake_msg(self, gas, accel):
values = {
"GAS_COMMAND": gas,
@@ -589,6 +531,8 @@ class TestHondaBoschLongSafety(HondaButtonEnableBase, TestHondaBoschSafetyBase):
class TestHondaBoschRadarlessSafetyBase(TestHondaBoschSafetyBase):
"""Base class for radarless Honda Bosch"""
DBC = "honda_bosch_radarless_generated"
PT_BUS = 0
STEER_BUS = 0
BUTTONS_BUS = 2 # camera controls ACC, need to send buttons on bus 2
@@ -596,48 +540,27 @@ class TestHondaBoschRadarlessSafetyBase(TestHondaBoschSafetyBase):
TX_MSGS = [[0xE4, 0], [0x296, 2], [0x33D, 0]]
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x33D]}
RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x33D)} # STEERING_CONTROL
def setUp(self):
self.packer = CANPackerSafety("honda_bosch_radarless_generated")
self.safety = libsafety_py.libsafety
class TestHondaBoschRadarlessSafety(HondaPcmEnableBase, TestHondaBoschRadarlessSafetyBase):
"""
Covers the Honda Bosch Radarless safety mode with stock longitudinal
"""
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.RADARLESS)
self.safety.init_tests()
SAFETY_PARAM = HondaSafetyFlags.RADARLESS
class TestHondaBoschRadarlessAltBrakeSafety(HondaPcmEnableBase, TestHondaBoschRadarlessSafetyBase, TestHondaBoschAltBrakeSafetyBase):
"""
Covers the Honda Bosch Radarless safety mode with stock longitudinal and an alternate brake message
"""
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.RADARLESS | HondaSafetyFlags.ALT_BRAKE)
self.safety.init_tests()
SAFETY_PARAM = HondaSafetyFlags.RADARLESS | HondaSafetyFlags.ALT_BRAKE
class TestHondaBoschRadarlessLongSafety(common.LongitudinalAccelSafetyTest, HondaButtonEnableBase,
TestHondaBoschRadarlessSafetyBase):
"""
Covers the Honda Bosch Radarless safety mode with longitudinal control
"""
SAFETY_PARAM = HondaSafetyFlags.RADARLESS | HondaSafetyFlags.BOSCH_LONG
TX_MSGS = [[0xE4, 0], [0x33D, 0], [0x1C8, 0], [0x30C, 0]]
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x33D, 0x1C8, 0x30C]}
RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x1C8, 0x30C, 0x33D)}
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.RADARLESS | HondaSafetyFlags.BOSCH_LONG)
self.safety.init_tests()
def _accel_msg(self, accel):
values = {
"ACCEL_COMMAND": accel,
@@ -647,10 +570,10 @@ class TestHondaBoschRadarlessLongSafety(common.LongitudinalAccelSafetyTest, Hond
# Longitudinal doesn't need to send buttons
def test_spam_cancel_safety_check(self):
pass
class TestHondaBoschCANFDSafetyBase(TestHondaBoschSafetyBase):
"""Base class for CANFD Honda Bosch"""
DBC = "honda_common_canfd_generated"
PT_BUS = 0
STEER_BUS = 0
BUTTONS_BUS = 0
@@ -658,48 +581,26 @@ class TestHondaBoschCANFDSafetyBase(TestHondaBoschSafetyBase):
TX_MSGS = [[0xE4, 0], [0x296, 0], [0x33D, 0]]
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x33D]}
RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x33D)}
def setUp(self):
self.packer = CANPackerSafety("honda_common_canfd_generated")
self.safety = libsafety_py.libsafety
class TestHondaBoschCANFDSafety(HondaPcmEnableBase, TestHondaBoschCANFDSafetyBase):
"""
Covers the Honda Bosch CANFD safety mode with stock longitudinal
"""
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.BOSCH_CANFD)
self.safety.init_tests()
SAFETY_PARAM = HondaSafetyFlags.BOSCH_CANFD
class TestHondaBoschCANFDAltBrakeSafety(HondaPcmEnableBase, TestHondaBoschCANFDSafetyBase, TestHondaBoschAltBrakeSafetyBase):
"""
Covers the Honda Bosch CANFD safety mode with stock longitudinal and an alternate brake message
"""
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.BOSCH_CANFD | HondaSafetyFlags.ALT_BRAKE)
self.safety.init_tests()
SAFETY_PARAM = HondaSafetyFlags.BOSCH_CANFD | HondaSafetyFlags.ALT_BRAKE
class TestHondaNidecHybridSafety(TestHondaNidecPcmSafety):
"""
Covers the Honda Nidec safety mode with hybrid brake
"""
BRAKE_SIG = "COMPUTER_BRAKE_HYBRID"
DBC = "honda_clarity_hybrid_2018_can_generated"
def setUp(self):
self.packer = CANPackerSafety("honda_clarity_hybrid_2018_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(HondaSafetyFlagsSP.NIDEC_HYBRID)
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, 0)
self.safety.init_tests()
if __name__ == "__main__":
unittest.main()
@@ -5,8 +5,8 @@ import unittest
from opendbc.car.hyundai.values import HyundaiSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.common import CANPackerSafety
from opendbc.safety.tests.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase
@@ -32,8 +32,6 @@ _ALL_NON_SCC_HEV_EV_COMBOS = [
"SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS},
]
ALL_NON_SCC_HEV_EV_COMBOS = [{**p, **lda} for lda in LDA_BUTTON for p in _ALL_NON_SCC_HEV_EV_COMBOS]
# 4 bit checkusm used in some hyundai messages
# lives outside the can packer because we never send this msg
def checksum(msg):
@@ -67,10 +65,11 @@ def checksum(msg):
ret[6 if addr == 0x394 else 7] |= chksum << (4 if addr == 0x421 else 0)
return addr, ret, bus
@parameterized_class(LDA_BUTTON)
class TestHyundaiSafety(HyundaiButtonBase, common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest):
DBC = "hyundai_can_generated"
SAFETY_MODEL = CarParams.SafetyModel.hyundai
TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0]]
STANDSTILL_THRESHOLD = 12 # 0.375 kph
RELAY_MALFUNCTION_ADDRS = {0: (0x340, 0x485)} # LKAS11
@@ -102,11 +101,8 @@ class TestHyundaiSafety(HyundaiButtonBase, common.CarSafetyTest, common.DriverTo
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0)
self.safety.init_tests()
def _button_msg(self, buttons, main_button=0, bus=0):
values = {"CF_Clu_CruiseSwState": buttons, "CF_Clu_CruiseSwMain": main_button, "CF_Clu_AliveCnt1": self.cnt_button}
@@ -224,10 +220,10 @@ class TestHyundaiSafety(HyundaiButtonBase, common.CarSafetyTest, common.DriverTo
self.assertEqual(enable_mads and has_lda_button_param, self.safety.get_controls_allowed_lateral())
finally:
self.safety.set_current_safety_param_sp(default_safety_param_sp)
@parameterized_class(LDA_BUTTON)
class TestHyundaiSafetyAltLimits(TestHyundaiSafety):
SAFETY_PARAM = HyundaiSafetyFlags.ALT_LIMITS
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE_LOOKUP = [0], [270]
@@ -239,15 +235,12 @@ class TestHyundaiSafetyAltLimits(TestHyundaiSafety):
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.ALT_LIMITS)
self.safety.init_tests()
@parameterized_class(LDA_BUTTON)
class TestHyundaiSafetyAltLimits2(TestHyundaiSafety):
SAFETY_PARAM = HyundaiSafetyFlags.ALT_LIMITS_2
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE_LOOKUP = [0], [170]
@@ -259,15 +252,12 @@ class TestHyundaiSafetyAltLimits2(TestHyundaiSafety):
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.ALT_LIMITS_2)
self.safety.init_tests()
@parameterized_class(LDA_BUTTON)
class TestHyundaiSafetyCameraSCC(TestHyundaiSafety):
SAFETY_PARAM = HyundaiSafetyFlags.CAMERA_SCC
BUTTONS_TX_BUS = 2 # tx on 2, rx on 0
SCC_BUS = 2 # rx on 2
@@ -278,11 +268,8 @@ class TestHyundaiSafetyCameraSCC(TestHyundaiSafety):
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.CAMERA_SCC)
self.safety.init_tests()
def test_pcm_main_cruise_state_availability(self):
"""
@@ -294,10 +281,10 @@ class TestHyundaiSafetyCameraSCC(TestHyundaiSafety):
with self.subTest("acc_main_on", should_turn_acc_main_on=should_turn_acc_main_on):
self._rx(self._acc_state_msg(should_turn_acc_main_on))
self.assertEqual(should_turn_acc_main_on, self.safety.get_acc_main_on())
@parameterized_class(LDA_BUTTON)
class TestHyundaiSafetyFCEV(TestHyundaiSafety):
SAFETY_PARAM = HyundaiSafetyFlags.FCEV_GAS
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestHyundaiSafetyFCEV":
@@ -305,51 +292,32 @@ class TestHyundaiSafetyFCEV(TestHyundaiSafety):
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.FCEV_GAS)
self.safety.init_tests()
def _user_gas_msg(self, gas):
values = {"ACCELERATOR_PEDAL": gas}
return self.packer.make_can_msg_safety("FCEV_ACCELERATOR", 0, values)
class TestHyundaiLegacySafety(TestHyundaiSafety):
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, 0)
self.safety.init_tests()
SAFETY_MODEL = CarParams.SafetyModel.hyundaiLegacy
class TestHyundaiLegacySafetyEV(TestHyundaiSafety):
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, HyundaiSafetyFlags.EV_GAS)
self.safety.init_tests()
SAFETY_MODEL = CarParams.SafetyModel.hyundaiLegacy
SAFETY_PARAM = HyundaiSafetyFlags.EV_GAS
def _user_gas_msg(self, gas):
values = {"Accel_Pedal_Pos": gas}
return self.packer.make_can_msg_safety("E_EMS11", 0, values, fix_checksum=checksum)
class TestHyundaiLegacySafetyHEV(TestHyundaiSafety):
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, HyundaiSafetyFlags.HYBRID_GAS)
self.safety.init_tests()
SAFETY_MODEL = CarParams.SafetyModel.hyundaiLegacy
SAFETY_PARAM = HyundaiSafetyFlags.HYBRID_GAS
def _user_gas_msg(self, gas):
values = {"CR_Vcu_AccPedDep_Pos": gas}
return self.packer.make_can_msg_safety("E_EMS11", 0, values, fix_checksum=checksum)
@parameterized_class(LDA_BUTTON)
class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
SAFETY_PARAM = HyundaiSafetyFlags.LONG
TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0], [0x4A2, 0], [0x38D, 0], [0x483, 0], [0x7D0, 0]]
FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485, 0x421, 0x420, 0x50A, 0x389]}
@@ -366,11 +334,8 @@ class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG)
self.safety.init_tests()
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
values = {
@@ -408,17 +373,16 @@ class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
class TestHyundaiLongitudinalSafetyCameraSCC(HyundaiLongitudinalBase, TestHyundaiSafety):
SAFETY_PARAM = HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CAMERA_SCC
TX_MSGS = [[0x340, 0], [0x4F1, 2], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0], [0x4A2, 0]]
FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485, 0x420, 0x421, 0x50A, 0x389]}
RELAY_MALFUNCTION_ADDRS = {0: (0x340, 0x485, 0x421, 0x420, 0x50A, 0x389)} # LKAS11, LFAHDA_MFC, SCC12, SCC11, SCC13, SCC14
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(HyundaiSafetyFlagsSP.HAS_LDA_BUTTON)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CAMERA_SCC)
self.safety.init_tests()
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
values = {
@@ -443,10 +407,10 @@ class TestHyundaiLongitudinalSafetyCameraSCC(HyundaiLongitudinalBase, TestHyunda
def test_disabled_ecu_alive(self):
pass
@parameterized_class(LDA_BUTTON)
class TestHyundaiSafetyFCEVLong(TestHyundaiLongitudinalSafety, TestHyundaiSafetyFCEV):
SAFETY_PARAM = HyundaiSafetyFlags.FCEV_GAS | HyundaiSafetyFlags.LONG
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestHyundaiSafetyFCEVLong":
@@ -454,13 +418,8 @@ class TestHyundaiSafetyFCEVLong(TestHyundaiLongitudinalSafety, TestHyundaiSafety
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_can_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.FCEV_GAS | HyundaiSafetyFlags.LONG)
self.safety.init_tests()
@parameterized_class(LDA_BUTTON)
class TestHyundaiLongitudinalESCCSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0]]
@@ -497,8 +456,6 @@ class TestHyundaiLongitudinalESCCSafety(HyundaiLongitudinalBase, TestHyundaiSafe
def test_disabled_ecu_alive(self):
pass
@parameterized_class(LDA_BUTTON)
class TestHyundaiNonSCCSafety(TestHyundaiSafety):
@@ -548,8 +505,6 @@ class TestHyundaiNonSCCSafety(TestHyundaiSafety):
# Make sure we can re-gain longitudinal actuation
self._rx(self._user_gas_msg(0, self.safety.get_controls_allowed()))
self.assertTrue(self.safety.get_longitudinal_allowed())
@parameterized_class(ALL_NON_SCC_HEV_EV_COMBOS)
class TestHyundaiNonSCCSafety_HEV_EV(TestHyundaiSafety):
@@ -582,7 +537,5 @@ class TestHyundaiNonSCCSafety_HEV_EV(TestHyundaiSafety):
def _user_gas_msg(self, gas):
values = {self.GAS_MSG[1]: gas}
return self.packer.make_can_msg_safety(self.GAS_MSG[0], 0, values, fix_checksum=checksum)
if __name__ == "__main__":
unittest.main()
@@ -4,26 +4,25 @@ import unittest
from opendbc.car.hyundai.values import HyundaiSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
from opendbc.safety.tests.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase
# All combinations of radar/camera-SCC and gas/hybrid/EV cars
ALL_GAS_EV_HYBRID_COMBOS = [
# Radar SCC
{"GAS_MSG": ("ACCELERATOR_BRAKE_ALT", "ACCELERATOR_PEDAL_PRESSED"), "SCC_BUS": 0, "SAFETY_PARAM": 0},
{"GAS_MSG": ("ACCELERATOR", "ACCELERATOR_PEDAL"), "SCC_BUS": 0, "SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS},
{"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 0, "SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS},
{"GAS_MSG": ("ACCELERATOR_BRAKE_ALT", "ACCELERATOR_PEDAL_PRESSED"), "SCC_BUS": 0, "EXTRA_SAFETY_PARAM": 0},
{"GAS_MSG": ("ACCELERATOR", "ACCELERATOR_PEDAL"), "SCC_BUS": 0, "EXTRA_SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS},
{"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 0, "EXTRA_SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS},
# Camera SCC
{"GAS_MSG": ("ACCELERATOR_BRAKE_ALT", "ACCELERATOR_PEDAL_PRESSED"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.CAMERA_SCC},
{"GAS_MSG": ("ACCELERATOR", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS | HyundaiSafetyFlags.CAMERA_SCC},
{"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.CAMERA_SCC},
{"GAS_MSG": ("ACCELERATOR_BRAKE_ALT", "ACCELERATOR_PEDAL_PRESSED"), "SCC_BUS": 2, "EXTRA_SAFETY_PARAM": HyundaiSafetyFlags.CAMERA_SCC},
{"GAS_MSG": ("ACCELERATOR", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "EXTRA_SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS | HyundaiSafetyFlags.CAMERA_SCC},
{"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "EXTRA_SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.CAMERA_SCC},
]
class TestHyundaiCanfdBase(HyundaiButtonBase, common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest):
DBC = "hyundai_canfd_generated"
SAFETY_MODEL = CarParams.SafetyModel.hyundaiCanfd
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
STANDSTILL_THRESHOLD = 12 # 0.375 kph
FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]}
@@ -91,8 +90,6 @@ class TestHyundaiCanfdBase(HyundaiButtonBase, common.CarSafetyTest, common.Drive
def _main_cruise_button_msg(self, enabled):
return self._button_msg(0, enabled)
class TestHyundaiCanfdLFASteeringBase(TestHyundaiCanfdBase):
TX_MSGS = [[0x12A, 0], [0x1A0, 1], [0x1CF, 0], [0x1E0, 0]]
@@ -101,37 +98,28 @@ class TestHyundaiCanfdLFASteeringBase(TestHyundaiCanfdBase):
STEER_MSG = "LFA"
BUTTONS_TX_BUS = 2
SAFETY_PARAM: int
EXTRA_SAFETY_PARAM: int
@classmethod
def setUpClass(cls):
super().setUpClass()
if cls.__name__ in ("TestHyundaiCanfdLFASteering", "TestHyundaiCanfdLFASteeringAltButtons"):
cls.packer = None
cls.safety = None
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, self.SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return self.EXTRA_SAFETY_PARAM
@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
class TestHyundaiCanfdLFASteering(TestHyundaiCanfdLFASteeringBase):
pass
class TestHyundaiCanfdLFASteeringAltButtonsBase(TestHyundaiCanfdLFASteeringBase):
SAFETY_PARAM: int
EXTRA_SAFETY_PARAM: int
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.EXTRA_SAFETY_PARAM
def _button_msg(self, buttons, main_button=0, bus=1):
values = {
@@ -164,15 +152,13 @@ class TestHyundaiCanfdLFASteeringAltButtonsBase(TestHyundaiCanfdLFASteeringBase)
self.assertTrue(self._tx(self._acc_cancel_msg(True)))
self.assertFalse(self._tx(self._acc_cancel_msg(True, accel=1)))
self.assertFalse(self._tx(self._acc_cancel_msg(False)))
@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
class TestHyundaiCanfdLFASteeringAltButtons(TestHyundaiCanfdLFASteeringAltButtonsBase):
pass
class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.EV_GAS
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0x50, 0x2a4)} # LKAS, CAM_0x2A4
FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]}
@@ -181,17 +167,11 @@ class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
SCC_BUS = 1
STEER_MSG = "LKAS"
GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.EV_GAS)
self.safety.init_tests()
# TODO: Handle ICE and HEV configurations once we see cars that use the new messages
class TestHyundaiCanfdLKASteeringAltEV(TestHyundaiCanfdBase):
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.EV_GAS | HyundaiSafetyFlags.CANFD_LKA_STEER_MSG_ALT
TX_MSGS = [[0x110, 0], [0x1CF, 1], [0x362, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0x110, 0x362)} # LKAS_ALT, CAM_0x362
FWD_BLACKLISTED_ADDRS = {2: [0x110, 0x362]}
@@ -200,17 +180,10 @@ class TestHyundaiCanfdLKASteeringAltEV(TestHyundaiCanfdBase):
SCC_BUS = 1
STEER_MSG = "LKAS_ALT"
GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.EV_GAS |
HyundaiSafetyFlags.CANFD_LKA_STEER_MSG_ALT)
self.safety.init_tests()
class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanfdLKASteeringEV):
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEER_MSG | HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0], [0x51, 0], [0x730, 1], [0x12a, 1], [0x160, 1],
[0x1e0, 1], [0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]]
@@ -223,13 +196,6 @@ class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanf
GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
STEER_BUS = 1
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEER_MSG |
HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS)
self.safety.init_tests()
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
values = {
"aReqRaw": accel,
@@ -240,8 +206,6 @@ class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanf
def _tx_acc_state_msg(self, enable):
values = {"MainMode_ACC": enable}
return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
# Tests longitudinal for ICE, hybrid, EV cars with LFA steering
class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCanfdLFASteeringBase):
@@ -252,17 +216,9 @@ class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCa
DISABLED_ECU_UDS_MSG = (0x7D0, 0)
DISABLED_ECU_ACTUATION_MSG = (0x1a0, 0)
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestHyundaiCanfdLFASteeringLongBase":
cls.safety = None
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.LONG | self.SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return HyundaiSafetyFlags.LONG | self.EXTRA_SAFETY_PARAM
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
values = {
@@ -275,38 +231,29 @@ class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCa
values = {"MainMode_ACC": enable}
return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
# no knockout
def test_tester_present_allowed(self):
pass
def test_tester_present_allowed(self, ecu_disable: bool = True):
super().test_tester_present_allowed(ecu_disable=not self.EXTRA_SAFETY_PARAM & HyundaiSafetyFlags.CAMERA_SCC)
@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
class TestHyundaiCanfdLFASteeringLong(TestHyundaiCanfdLFASteeringLongBase):
@classmethod
def setUpClass(cls):
super().setUpClass()
if cls.__name__ == "TestHyundaiCanfdLFASteeringLong":
cls.safety = None
raise unittest.SkipTest
@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
class TestHyundaiCanfdLFASteeringLongAltButtons(TestHyundaiCanfdLFASteeringLongBase, TestHyundaiCanfdLFASteeringAltButtonsBase):
@classmethod
def setUpClass(cls):
super().setUpClass()
if cls.__name__ == "TestHyundaiCanfdLFASteeringLongAltButtons":
cls.safety = None
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.SAFETY_PARAM)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.EXTRA_SAFETY_PARAM
def test_acc_cancel(self):
# Alt buttons does not use SCC_CONTROL to cancel if longitudinal
pass
if __name__ == "__main__":
unittest.main()
@@ -2,13 +2,13 @@
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety, make_msg
from opendbc.safety.tests.common import make_msg
class TestMazdaSafety(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest):
DBC = "mazda_2017"
SAFETY_MODEL = CarParams.SafetyModel.mazda
TX_MSGS = [[0x243, 0], [0x09d, 0], [0x440, 0]]
STANDSTILL_THRESHOLD = .1
RELAY_MALFUNCTION_ADDRS = {0: (0x243, 0x440)}
@@ -26,12 +26,6 @@ class TestMazdaSafety(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTes
# Mazda actually does not set any bit when requesting torque
NO_STEER_REQ_BIT = True
def setUp(self):
self.packer = CANPackerSafety("mazda_2017")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.mazda, 0)
self.safety.init_tests()
def _torque_meas_msg(self, torque):
values = {"STEER_TORQUE_MOTOR": torque}
return self.packer.make_can_msg_safety("STEER_TORQUE", 0, values)
@@ -79,15 +73,11 @@ class TestMazdaSafety(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTes
self.safety.set_controls_allowed(1)
self.assertTrue(self._tx(self._button_msg(cancel=True)))
self.assertTrue(self._tx(self._button_msg(resume=True)))
class TestMazdaIgnition(common.SafetyTestBase):
SAFETY_MODEL = None
class TestMazdaIgnition(unittest.TestCase):
TX_MSGS: list = []
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.init_tests()
def _msg(self, byte0):
return make_msg(0, 0x9E, dat=bytes([byte0]) + b"\x00" * 7)
@@ -101,7 +91,5 @@ class TestMazdaIgnition(unittest.TestCase):
self.assertTrue(self.safety.get_ignition_can())
self.safety.ignition_can_hook(self._msg(0x20))
self.assertFalse(self.safety.get_ignition_can())
if __name__ == "__main__":
unittest.main()
@@ -4,14 +4,15 @@ import unittest
from opendbc.car.nissan.values import NissanSafetyFlags
from opendbc.sunnypilot.car.nissan.values import NissanSafetyFlagsSP
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.common import CANPackerSafety
class TestNissanSafety(common.CarSafetyTest, common.AngleSteeringSafetyTest):
TX_MSGS = [[0x169, 0], [0x2b1, 0], [0x4cc, 0], [0x20b, 2]]
DBC = "nissan_x_trail_2017_generated"
SAFETY_MODEL = CarParams.SafetyModel.nissan
TX_MSGS = [[0x169, 0], [0x2b1, 0], [0x4cc, 0], [0x20b, 2], [0x280, 2]]
GAS_PRESSED_THRESHOLD = 3
RELAY_MALFUNCTION_ADDRS = {0: (0x169, 0x2b1, 0x4cc), 2: (0x20b,)}
FWD_BLACKLISTED_ADDRS = {0: [0x20b], 2: [0x169, 0x2b1, 0x4cc]}
@@ -28,12 +29,6 @@ class TestNissanSafety(common.CarSafetyTest, common.AngleSteeringSafetyTest):
ANGLE_RATE_UP = [5., .8, .15] # windup limit
ANGLE_RATE_DOWN = [5., 3.5, .4] # unwind limit
def setUp(self):
self.packer = CANPackerSafety("nissan_x_trail_2017_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.nissan, 0)
self.safety.init_tests()
def _angle_cmd_msg(self, angle: float, enabled: bool):
values = {"DESIRED_ANGLE": angle, "LKA_ACTIVE": 1 if enabled else 0}
return self.packer.make_can_msg_safety("LKAS", 0, values)
@@ -84,10 +79,9 @@ class TestNissanSafety(common.CarSafetyTest, common.AngleSteeringSafetyTest):
args = {} if btn is None else {btn: 1}
tx = self._tx(self._acc_button_cmd(**args))
self.assertEqual(tx, should_tx)
class TestNissanSafetyAltEpsBus(TestNissanSafety):
"""Altima uses different buses"""
SAFETY_PARAM = NissanSafetyFlags.ALT_EPS_BUS
TX_MSGS = [[0x169, 0], [0x2b1, 0], [0x4cc, 0], [0x20b, 1]]
RELAY_MALFUNCTION_ADDRS = {0: (0x169, 0x2b1, 0x4cc)}
@@ -97,15 +91,10 @@ class TestNissanSafetyAltEpsBus(TestNissanSafety):
CRUISE_BUS = 1
ACC_MAIN_BUS = 2
def setUp(self):
self.packer = CANPackerSafety("nissan_x_trail_2017_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.nissan, NissanSafetyFlags.ALT_EPS_BUS)
self.safety.init_tests()
class TestNissanLeafSafety(TestNissanSafety):
DBC = "nissan_leaf_2018_generated"
TX_MSGS = [[0x169, 0], [0x2b1, 0], [0x4cc, 0], [0x239, 2]]
RELAY_MALFUNCTION_ADDRS = {0: (0x169, 0x2b1, 0x4cc), 2: (0x239,)}
FWD_BLACKLISTED_ADDRS = {0: [0x239], 2: [0x169, 0x2b1, 0x4cc]}
@@ -146,7 +135,5 @@ class TestNissanLeafSafety(TestNissanSafety):
args = {} if btn is None else {btn: 1}
tx = self._tx(self._acc_button_cmd(**args))
self.assertEqual(tx, should_tx)
if __name__ == "__main__":
unittest.main()
+4 -20
View File
@@ -2,14 +2,13 @@
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
LANE_KEEP_ASSIST = 0x3F2
class TestPsaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest):
DBC = "psa_aee2010_r3"
SAFETY_MODEL = CarParams.SafetyModel.psa
RELAY_MALFUNCTION_ADDRS = {0: (LANE_KEEP_ASSIST,)}
FWD_BLACKLISTED_ADDRS = {2: [LANE_KEEP_ASSIST]}
TX_MSGS = [[1010, 0]]
@@ -25,12 +24,6 @@ class TestPsaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest):
ANGLE_RATE_UP = [2.5, 1.5, .2]
ANGLE_RATE_DOWN = [5., 2., .3]
def setUp(self):
self.packer = CANPackerSafety("psa_aee2010_r3")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.psa, 0)
self.safety.init_tests()
def _angle_cmd_msg(self, angle: float, enabled: bool):
values = {"SET_ANGLE": angle, "TORQUE_FACTOR": 100 if enabled else 0}
return self.packer.make_can_msg_safety("LANE_KEEP_ASSIST", self.MAIN_BUS, values)
@@ -75,16 +68,7 @@ class TestPsaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest):
# write to unused payload byte
msg[0].data[6] = 0xAB
self.assertTrue(self._rx(msg))
class TestPsaStockSafety(TestPsaSafetyBase):
def setUp(self):
self.packer = CANPackerSafety("psa_aee2010_r3")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.psa, 0)
self.safety.init_tests()
pass
if __name__ == "__main__":
unittest.main()
@@ -2,15 +2,11 @@
import unittest
from opendbc.safety.tests.libsafety.libsafety_py import _build_libsafety
class TestBuild(unittest.TestCase):
def test_development_build(self):
_build_libsafety(release=False)
def test_release_build(self):
_build_libsafety(release=True)
if __name__ == "__main__":
unittest.main()
@@ -2,29 +2,14 @@
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
from opendbc.car.rivian.values import RivianSafetyFlags
from opendbc.car.rivian.riviancan import checksum as _checksum
def checksum(msg):
addr, dat, bus = msg
ret = bytearray(dat)
# ESP_Status
if addr == 0x208:
ret[0] = _checksum(ret[1:], 0x1D, 0xB1)
elif addr == 0x150:
ret[0] = _checksum(ret[1:], 0x1D, 0x9A)
return addr, ret, bus
class TestRivianSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.LongitudinalAccelSafetyTest,
common.VehicleSpeedSafetyTest):
DBC = "rivian_primary_actuator"
SAFETY_MODEL = CarParams.SafetyModel.rivian
TX_MSGS = [[0x120, 0], [0x321, 2], [0x162, 2]]
RELAY_MALFUNCTION_ADDRS = {0: (0x120,), 2: (0x321, 0x162)}
FWD_BLACKLISTED_ADDRS = {0: [0x321, 0x162], 2: [0x120]}
@@ -41,9 +26,13 @@ class TestRivianSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafe
cnt_speed = 0
cnt_speed_2 = 0
cnt_torque = 0
cnt_brake = 0
cnt_pcm = 0
def _torque_driver_msg(self, torque):
values = {"EPAS_TorsionBarTorque": torque / 100.0}
values = {"EPAS_TorsionBarTorque": torque / 100.0, "EPAS_SystemStatus_Counter": self.cnt_torque % 15}
self.__class__.cnt_torque += 1
return self.packer.make_can_msg_safety("EPAS_SystemStatus", 0, values)
def _torque_cmd_msg(self, torque, steer_req=1):
@@ -54,24 +43,27 @@ class TestRivianSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafe
values = {"ESP_Vehicle_Speed": speed * 3.6, "ESP_Status_Counter": self.cnt_speed % 15,
"ESP_Vehicle_Speed_Q": 1 if quality_flag else 0}
self.__class__.cnt_speed += 1
return self.packer.make_can_msg_safety("ESP_Status", 0, values, fix_checksum=checksum)
return self.packer.make_can_msg_safety("ESP_Status", 0, values)
def _speed_msg_2(self, speed, quality_flag=True):
# Rivian has a dynamic max torque limit based on speed, so it checks two sources
return self._user_gas_msg(0, speed, quality_flag)
def _user_brake_msg(self, brake):
values = {"iBESP2_BrakePedalApplied": brake}
def _user_brake_msg(self, brake, quality_flag=True):
values = {"iBESP2_BrakePedalApplied": brake, "iBESP2_BrakePedalApplied_Q": 1 if quality_flag else 2,
"iBESP2_AliveCounter": self.cnt_brake % 15}
self.__class__.cnt_brake += 1
return self.packer.make_can_msg_safety("iBESP2", 0, values)
def _user_gas_msg(self, gas, speed=0, quality_flag=True):
values = {"VDM_AcceleratorPedalPosition": gas, "VDM_VehicleSpeed": speed * 3.6,
"VDM_PropStatus_Counter": self.cnt_speed_2 % 15, "VDM_VehicleSpeedQ": 1 if quality_flag else 0}
self.__class__.cnt_speed_2 += 1
return self.packer.make_can_msg_safety("VDM_PropStatus", 0, values, fix_checksum=checksum)
return self.packer.make_can_msg_safety("VDM_PropStatus", 0, values)
def _pcm_status_msg(self, enable):
values = {"ACM_FeatureStatus": enable, "ACM_Unkown1": 1}
values = {"ACM_FeatureStatus": enable, "ACM_Unkown1": 1, "ACM_Status_Counter": self.cnt_pcm % 15}
self.__class__.cnt_pcm += 1
return self.packer.make_can_msg_safety("ACM_Status", 2, values)
def _accel_msg(self, accel: float):
@@ -109,17 +101,37 @@ class TestRivianSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafe
self.assertFalse(self._rx(msg))
self.assertFalse(self.safety.get_controls_allowed())
# The DBC defines counters for the remaining monitored RX messages too.
for make_msg in (self._torque_driver_msg, self._user_brake_msg, self._pcm_status_msg):
self._reset_safety_hooks()
self.safety.set_controls_allowed(True)
for _ in range(10):
self.assertTrue(self._rx(make_msg(0) if make_msg == self._torque_driver_msg else make_msg(False)))
msg = make_msg(0) if make_msg == self._torque_driver_msg else make_msg(False)
msg[0].data[0] ^= 0xff
self.assertFalse(self._rx(msg))
self.assertFalse(self.safety.get_controls_allowed())
if make_msg == self._user_brake_msg:
self._reset_safety_hooks()
self.safety.set_controls_allowed(True)
self.assertFalse(self._rx(self._user_brake_msg(False, quality_flag=False)))
self.assertFalse(self.safety.get_controls_allowed())
# A single bad counter is tolerated, but repeated bad counters must disengage.
self._reset_safety_hooks()
self.safety.set_controls_allowed(True)
for _ in range(7):
msg = make_msg(0) if make_msg == self._torque_driver_msg else make_msg(False)
msg[0].data[1] &= 0xf0
valid = self._rx(msg)
self.assertFalse(valid)
self.assertFalse(self.safety.get_controls_allowed())
class TestRivianStockSafety(TestRivianSafetyBase):
LONGITUDINAL = False
def setUp(self):
self.packer = CANPackerSafety("rivian_primary_actuator")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.rivian, 0)
self.safety.init_tests()
def test_adas_status(self):
# For canceling stock ACC
for controls_allowed in (True, False):
@@ -127,29 +139,19 @@ class TestRivianStockSafety(TestRivianSafetyBase):
for interface_status in range(4):
values = {"VDM_AdasInterfaceStatus": interface_status}
self.assertTrue(self._tx(self.packer.make_can_msg_safety("VDM_AdasSts", 2, values)))
class TestRivianLongitudinalSafety(TestRivianSafetyBase):
SAFETY_PARAM = RivianSafetyFlags.LONG_CONTROL
TX_MSGS = [[0x120, 0], [0x321, 2], [0x160, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0x120, 0x160), 2: (0x321,)}
FWD_BLACKLISTED_ADDRS = {0: [0x321], 2: [0x120, 0x160]}
class TestRivianIgnition(common.SafetyTestBase):
DBC = "rivian_primary_actuator"
SAFETY_MODEL = None
def setUp(self):
self.packer = CANPackerSafety("rivian_primary_actuator")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.rivian, RivianSafetyFlags.LONG_CONTROL)
self.safety.init_tests()
class TestRivianIgnition(unittest.TestCase):
TX_MSGS: list = []
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.init_tests()
self.packer = CANPackerSafety("rivian_primary_actuator")
def _msg(self, counter, mode):
return self.packer.make_can_msg_safety("VDM_OutputSignals", 0,
{"VDM_OutputSigs_Counter": counter,
@@ -171,7 +173,5 @@ class TestRivianIgnition(unittest.TestCase):
self.safety.ignition_can_hook(self._msg(2, 0))
self.safety.ignition_can_hook(self._msg(3, 0))
self.assertFalse(self.safety.get_ignition_can())
if __name__ == "__main__":
unittest.main()
@@ -4,12 +4,8 @@ import unittest
from opendbc.car.subaru.values import SubaruSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
from functools import partial
class SubaruMsg(enum.IntEnum):
Brake_Status = 0x13c
CruiseControl = 0x240
@@ -33,8 +29,6 @@ class SubaruMsg(enum.IntEnum):
SUBARU_MAIN_BUS = 0
SUBARU_ALT_BUS = 1
SUBARU_CAM_BUS = 2
def lkas_tx_msgs(alt_bus, lkas_msg=SubaruMsg.ES_LKAS):
return [[lkas_msg, SUBARU_MAIN_BUS],
[SubaruMsg.ES_Distance, alt_bus],
@@ -57,10 +51,10 @@ def gen2_long_additional_tx_msgs():
def fwd_blacklisted_addr(lkas_msg=SubaruMsg.ES_LKAS):
return {SUBARU_CAM_BUS: [lkas_msg, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State, SubaruMsg.ES_Infotainment]}
class TestSubaruSafetyBase(common.CarSafetyTest):
FLAGS = 0
DBC = "subaru_global_2017_generated"
SAFETY_MODEL = CarParams.SafetyModel.subaru
RELAY_MALFUNCTION_ADDRS = {SUBARU_MAIN_BUS: (SubaruMsg.ES_LKAS, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State,
SubaruMsg.ES_Infotainment)}
FWD_BLACKLISTED_ADDRS = fwd_blacklisted_addr()
@@ -77,12 +71,6 @@ class TestSubaruSafetyBase(common.CarSafetyTest):
INACTIVE_GAS = 1818
def setUp(self):
self.packer = CANPackerSafety("subaru_global_2017_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.subaru, self.FLAGS)
self.safety.init_tests()
def _set_prev_torque(self, t):
self.safety.set_desired_torque_last(t)
self.safety.set_rt_torque_last(t)
@@ -121,8 +109,6 @@ class TestSubaruSafetyBase(common.CarSafetyTest):
self._rx(self._lkas_button_msg(False, mads_button_press))
self.assertEqual(enable_mads and mads_button_press in range(1, 4),
self.safety.get_controls_allowed_lateral())
class TestSubaruStockLongitudinalSafetyBase(TestSubaruSafetyBase):
def _cancel_msg(self, cancel, cruise_throttle=0):
values = {"Cruise_Cancel": cancel, "Cruise_Throttle": cruise_throttle}
@@ -181,13 +167,8 @@ class TestSubaruTorqueSafetyBase(TestSubaruSafetyBase, common.DriverTorqueSteeri
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"LKAS_Output": torque, "LKAS_Request": steer_req}
return self.packer.make_can_msg_safety("ES_LKAS", SUBARU_MAIN_BUS, values)
class TestSubaruGen1TorqueStockLongitudinalSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruTorqueSafetyBase):
FLAGS = 0
TX_MSGS = lkas_tx_msgs(SUBARU_MAIN_BUS)
class TestSubaruGen2TorqueSafetyBase(TestSubaruTorqueSafetyBase):
ALT_MAIN_BUS = SUBARU_ALT_BUS
ALT_CAM_BUS = SUBARU_ALT_BUS
@@ -195,10 +176,9 @@ class TestSubaruGen2TorqueSafetyBase(TestSubaruTorqueSafetyBase):
MAX_RATE_UP = 35
MAX_RATE_DOWN = 50
MAX_TORQUE_LOOKUP = [0], [1500]
class TestSubaruGen2TorqueStockLongitudinalSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruGen2TorqueSafetyBase):
FLAGS = SubaruSafetyFlags.GEN2
SAFETY_PARAM = SubaruSafetyFlags.GEN2
TX_MSGS = lkas_tx_msgs(SUBARU_ALT_BUS)
@@ -3,13 +3,10 @@ import unittest
from opendbc.car.structs import CarParams
from opendbc.car.subaru.values import SubaruSafetyFlags
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
class TestSubaruPreglobalSafety(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest):
FLAGS = 0
SAFETY_MODEL = CarParams.SafetyModel.subaruPreglobal
DBC = "subaru_outback_2015_generated"
TX_MSGS = [[0x161, 0], [0x164, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0x164, 0x161)}
@@ -24,12 +21,6 @@ class TestSubaruPreglobalSafety(common.CarSafetyTest, common.DriverTorqueSteerin
DRIVER_TORQUE_ALLOWANCE = 75
DRIVER_TORQUE_FACTOR = 10
def setUp(self):
self.packer = CANPackerSafety(self.DBC)
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.subaruPreglobal, self.FLAGS)
self.safety.init_tests()
def _set_prev_torque(self, t):
self.safety.set_desired_torque_last(t)
self.safety.set_rt_torque_last(t)
@@ -58,12 +49,9 @@ class TestSubaruPreglobalSafety(common.CarSafetyTest, common.DriverTorqueSteerin
def _pcm_status_msg(self, enable):
values = {"Cruise_Activated": enable}
return self.packer.make_can_msg_safety("CruiseControl", 0, values)
class TestSubaruPreglobalReversedDriverTorqueSafety(TestSubaruPreglobalSafety):
FLAGS = SubaruSafetyFlags.PREGLOBAL_REVERSED_DRIVER_TORQUE
SAFETY_PARAM = SubaruSafetyFlags.PREGLOBAL_REVERSED_DRIVER_TORQUE
DBC = "subaru_outback_2019_generated"
if __name__ == "__main__":
unittest.main()
+33 -31
View File
@@ -10,8 +10,8 @@ from opendbc.car.tesla.carcontroller import get_safety_CP
from opendbc.car.structs import CarParams
from opendbc.car.vehicle_model import VehicleModel
from opendbc.can import CANDefine
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.common import CANPackerSafety, MAX_SPEED_DELTA, MAX_WRONG_COUNTERS, away_round, round_speed
from opendbc.sunnypilot.car.tesla.values import TeslaSafetyFlagsSP
@@ -19,17 +19,15 @@ from opendbc.sunnypilot.car.tesla.values import TeslaSafetyFlagsSP
MSG_DAS_steeringControl = 0x488
MSG_APS_eacMonitor = 0x27d
MSG_DAS_Control = 0x2b9
def round_angle(apply_angle, can_offset=0):
apply_angle_can = (apply_angle + 1638.35) / 0.1 + can_offset
# 0.49999_ == 0.5
rnd_offset = 1e-5 if apply_angle >= 0 else -1e-5
return away_round(apply_angle_can + rnd_offset) * 0.1 - 1638.35
class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest, common.LongitudinalAccelSafetyTest):
SAFETY_PARAM = 0
DBC = "tesla_model3_party"
SAFETY_MODEL = CarParams.SafetyModel.tesla
RELAY_MALFUNCTION_ADDRS = {0: (MSG_DAS_steeringControl, MSG_APS_eacMonitor)}
FWD_BLACKLISTED_ADDRS = {2: [MSG_DAS_steeringControl, MSG_APS_eacMonitor]}
@@ -56,34 +54,27 @@ class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest,
MIN_ACCEL = -3.48
INACTIVE_ACCEL = 0.0
cnt_epas = 0
cnt_angle_cmd = 0
packer: CANPackerSafety
def _get_steer_cmd_angle_max(self, speed):
return get_max_angle_vm(max(speed, 1), self.VM, CarControllerParams)
def setUp(self):
super().setUp()
self.VM = VehicleModel(get_safety_CP())
self.packer = CANPackerSafety("tesla_model3_party")
self.define = CANDefine("tesla_model3_party")
self.define = CANDefine(self.DBC)
self.acc_states = {d: v for v, d in self.define.dv["DAS_control"]["DAS_accState"].items()}
self.autopark_states = {d: v for v, d in self.define.dv["DI_state"]["DI_autoparkState"].items()}
self.active_autopark_states = [self.autopark_states[s] for s in ('ACTIVE', 'COMPLETE', 'SELFPARK_STARTED')]
self.steer_control_types = {d: v for v, d in self.define.dv["DAS_steeringControl"]["DAS_steeringControlType"].items()}
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.tesla, self.SAFETY_PARAM)
self.safety.init_tests()
def _angle_cmd_msg(self, angle: float, state: bool | int, increment_timer: bool = True, bus: int = 0):
# If FSD 14, translate steer control type to new flipped definition
if self.safety.get_current_safety_param() & TeslaSafetyFlags.FSD_14:
state = get_steer_ctrl_type(TeslaFlags.FSD_14, int(state))
values = {"DAS_steeringAngleRequest": angle, "DAS_steeringControlType": state}
values = {"DAS_steeringAngleRequest": angle, "DAS_steeringControlType": int(state)}
if increment_timer:
self.safety.set_timer(self.cnt_angle_cmd * int(1e6 / self.LATERAL_FREQUENCY))
self.__class__.cnt_angle_cmd += 1
@@ -91,9 +82,7 @@ class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest,
def _angle_meas_msg(self, angle: float, hands_on_level: int = 0, eac_status: int = 1, eac_error_code: int = 0):
values = {"EPAS3S_internalSAS": angle, "EPAS3S_handsOnLevel": hands_on_level,
"EPAS3S_eacStatus": eac_status, "EPAS3S_eacErrorCode": eac_error_code,
"EPAS3S_sysStatusCounter": self.cnt_epas % 16}
self.__class__.cnt_epas += 1
"EPAS3S_eacStatus": eac_status, "EPAS3S_eacErrorCode": eac_error_code}
return self.packer.make_can_msg_safety("EPAS3S_sysStatus", 0, values)
def _user_brake_msg(self, brake, quality_flag: bool = True):
@@ -272,9 +261,9 @@ class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest,
self.assertEqual(self.LONGITUDINAL, self._tx(self._long_control_msg(0, acc_state=self.acc_states["ACC_ON"])))
def test_steering_control_type(self):
# Only angle control is allowed (no LANE_KEEP_ASSIST or EMERGENCY_LANE_KEEP)
# Only angle control is allowed (no LANE_KEEP_ASSIST, EMERGENCY_LANE_KEEP, or FSD)
self.safety.set_controls_allowed(True)
for steer_control_type in range(4):
for steer_control_type in range(8):
should_tx = steer_control_type in (self.steer_control_types["NONE"],
self.steer_control_types["ANGLE_CONTROL"],
self.steer_control_types["LANE_KEEP_ASSIST"])
@@ -366,8 +355,6 @@ class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest,
# Recover
self.assertTrue(self._tx(self._angle_cmd_msg(0, True)))
class TestTeslaStockSafety(TestTeslaSafetyBase):
LONGITUDINAL = False
@@ -459,13 +446,11 @@ class TestTeslaFSD14LongitudinalSafety(TestTeslaLongitudinalSafety):
SAFETY_PARAM = TeslaSafetyFlags.LONG_CONTROL | TeslaSafetyFlags.FSD_14
class TestTeslaIgnition(unittest.TestCase):
TX_MSGS: list = []
class TestTeslaIgnition(common.SafetyTestBase):
DBC = "tesla_model3_party"
SAFETY_MODEL = None
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.init_tests()
self.packer = CANPackerSafety("tesla_model3_party")
TX_MSGS: list = []
def _msg(self, counter, state):
return self.packer.make_can_msg_safety("VCFRONT_LVPowerState", 0,
@@ -488,8 +473,6 @@ class TestTeslaIgnition(unittest.TestCase):
self.safety.ignition_can_hook(self._msg(2, 2))
self.safety.ignition_can_hook(self._msg(3, 2))
self.assertFalse(self.safety.get_ignition_can())
class TestTeslaVehicleBusSafety(TestTeslaSafetyBase):
LONGITUDINAL = False
@@ -540,6 +523,25 @@ class TestTeslaVehicleBusSafety(TestTeslaSafetyBase):
self._rx(self._touch_points_msg(actual))
self.assertEqual(-1, self.safety.get_mads_button_press()) # UNAVAILABLE
def test_vehicle_bus_rx_checks_valid(self):
"""The 2 Hz 0x3DF VEHICLE bus check must not flag the RX checks invalid."""
# keep every message on the same fake clock, the shared safety lib carries time across tests
self.safety.set_timer(0)
# feed every message of the VEHICLE bus config so each RX check has been seen
self._rx(self._speed_msg(0))
self._rx(self._speed_msg_2(0))
self._rx(self._user_gas_msg(0))
self._rx(self._user_brake_msg(False))
self._rx(self._pcm_status_msg(False))
self._rx(self._angle_meas_msg(0))
self._rx(self.packer.make_can_msg_safety("UI_warning", 0, {}))
self._rx(self._long_control_msg(0, bus=2))
self._rx(self._angle_cmd_msg(0, 0, increment_timer=False, bus=2))
self._rx(self._touch_points_msg(0))
self.safety.safety_tick()
self.assertFalse(self.safety.get_safety_rx_checks_invalid())
if __name__ == "__main__":
unittest.main()
@@ -25,10 +25,11 @@ UNSUPPORTED_DSU = [
{"SAFETY_PARAM_SP": ToyotaSafetyFlagsSP.DEFAULT},
{"SAFETY_PARAM_SP": ToyotaSafetyFlagsSP.UNSUPPORTED_DSU},
]
class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyTest):
DBC = "toyota_nodsu_pt_generated"
SAFETY_MODEL = CarParams.SafetyModel.toyota
TX_MSGS = TOYOTA_COMMON_TX_MSGS + TOYOTA_COMMON_LONG_TX_MSGS
RELAY_MALFUNCTION_ADDRS = {0: (0x2E4, 0x191, 0x412, 0x343)}
FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x412, 0x191, 0x343]}
@@ -151,8 +152,6 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
# OVERRIDDEN: 72.22_ is the max speed in m/s
self._common_measurement_test(self._speed_msg, 0, 259 / 3.6, 1,
self.safety.get_vehicle_speed_min, self.safety.get_vehicle_speed_max)
class TestToyotaSafetyGasInterceptorBase(GasInterceptorSafetyTest, TestToyotaSafetyBase):
TX_MSGS = TOYOTA_COMMON_TX_MSGS + TOYOTA_COMMON_LONG_TX_MSGS + GAS_INTERCEPTOR_TX_MSGS
@@ -179,8 +178,6 @@ class TestToyotaSafetyGasInterceptorBase(GasInterceptorSafetyTest, TestToyotaSaf
with self.subTest(test=test.__name__):
with self.assertRaises(AssertionError):
test()
@parameterized_class(UNSUPPORTED_DSU)
class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest):
@@ -195,6 +192,10 @@ class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSaf
MIN_VALID_STEERING_FRAMES = 17
MAX_INVALID_STEERING_FRAMES = 1
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestToyotaSafetyTorque":
@@ -202,13 +203,8 @@ class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSaf
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE)
self.safety.init_tests()
@parameterized_class(UNSUPPORTED_DSU)
class TestToyotaSafetyTorqueGasInterceptor(TestToyotaSafetyGasInterceptorBase, TestToyotaSafetyTorque):
@@ -217,8 +213,6 @@ class TestToyotaSafetyTorqueGasInterceptor(TestToyotaSafetyGasInterceptorBase, T
if cls.__name__ == "TestToyotaSafetyTorqueGasInterceptor":
cls.safety = None
raise unittest.SkipTest
class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest):
# Angle control limits
@@ -233,11 +227,9 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest
MAX_MEAS_TORQUE = 1500 # max allowed measured EPS torque before wind down
MAX_LTA_DRIVER_TORQUE = 150 # max allowed driver torque before wind down
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.LTA)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE | ToyotaSafetyFlags.LTA
# Only allow LKA msgs with no actuation
def test_lka_steer_cmd(self):
@@ -328,15 +320,17 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest
self._rx(self._angle_meas_msg(0))
self.assertEqual(self.safety.get_angle_meas_min(), 0)
self.assertEqual(self.safety.get_angle_meas_max(), 0)
class TestToyotaSafetyAngleGasInterceptor(TestToyotaSafetyGasInterceptorBase, TestToyotaSafetyAngle):
pass
@parameterized_class(UNSUPPORTED_DSU)
class TestToyotaAltBrakeSafety(TestToyotaSafetyTorque):
DBC = "toyota_new_mc_pt_generated"
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE | ToyotaSafetyFlags.ALT_BRAKE
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestToyotaAltBrakeSafety":
@@ -344,11 +338,8 @@ class TestToyotaAltBrakeSafety(TestToyotaSafetyTorque):
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("toyota_new_mc_pt_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.ALT_BRAKE)
self.safety.init_tests()
def _user_brake_msg(self, brake):
values = {"BRAKE_PRESSED": brake}
@@ -357,8 +348,6 @@ class TestToyotaAltBrakeSafety(TestToyotaSafetyTorque):
# No LTA message in the DBC
def test_lta_steer_cmd(self):
pass
@parameterized_class(UNSUPPORTED_DSU)
class TestToyotaAltBrakeSafetyGasInterceptor(TestToyotaSafetyGasInterceptorBase, TestToyotaAltBrakeSafety):
@@ -371,8 +360,6 @@ class TestToyotaAltBrakeSafetyGasInterceptor(TestToyotaSafetyGasInterceptorBase,
# No LTA message in the DBC
def test_lta_steer_cmd(self):
pass
class TestToyotaStockLongitudinalBase(TestToyotaSafetyBase):
TX_MSGS = TOYOTA_COMMON_TX_MSGS
@@ -398,11 +385,13 @@ class TestToyotaStockLongitudinalBase(TestToyotaSafetyBase):
self.assertFalse(self._tx(self._accel_msg_343(accel)))
should_tx = np.isclose(accel, self.INACTIVE_ACCEL, atol=0.0001)
self.assertEqual(should_tx, self._tx(self._accel_msg_343(accel, cancel_req=1)))
@parameterized_class(UNSUPPORTED_DSU)
class TestToyotaStockLongitudinalTorque(TestToyotaStockLongitudinalBase, TestToyotaSafetyTorque):
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestToyotaStockLongitudinalTorque":
@@ -410,35 +399,24 @@ class TestToyotaStockLongitudinalTorque(TestToyotaStockLongitudinalBase, TestToy
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
super().setUp()
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL)
self.safety.init_tests()
class TestToyotaStockLongitudinalAngle(TestToyotaStockLongitudinalBase, TestToyotaSafetyAngle):
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.LTA)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.LTA
class TestToyotaSecOcSafetyBase(TestToyotaSafetyBase):
DBC = "toyota_secoc_pt_generated"
TX_MSGS = TOYOTA_SECOC_TX_MSGS
RELAY_MALFUNCTION_ADDRS = {0: (0x2E4, 0x191, 0x412, 0x131)}
FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x191, 0x412, 0x131]}
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE | ToyotaSafetyFlags.SECOC
def test_diagnostics(self, ecu_disabled: bool = False):
super().test_diagnostics(ecu_disabled=ecu_disabled)
@@ -469,29 +447,16 @@ class TestToyotaSecOcSafetyBase(TestToyotaSafetyBase):
def _accel_msg(self, accel, cancel_req=0):
return self._accel_msg_183(accel)
class TestToyotaSecOcSafetyStockLongitudinal(TestToyotaSecOcSafetyBase, TestToyotaStockLongitudinalBase):
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@property
def SAFETY_PARAM(self):
return self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.SECOC
class TestToyotaSecOcSafety(TestToyotaSecOcSafetyBase):
RELAY_MALFUNCTION_ADDRS = {0: (0x2E4, 0x191, 0x412, 0x131, 0x343, 0x183)}
FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x191, 0x412, 0x131, 0x343, 0x183]}
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@unittest.skip("test not applicable for cars without a DSU")
def test_block_aeb(self, stock_longitudinal: bool = False):
pass
@@ -507,7 +472,5 @@ class TestToyotaSecOcSafety(TestToyotaSecOcSafetyBase):
should_tx = np.isclose(accel, self.INACTIVE_ACCEL, atol=0.0001)
self.assertEqual(should_tx, self._tx(self._accel_msg_343(accel)))
self.assertEqual(should_tx, self._tx(self._accel_msg_343(accel, cancel_req=1)))
if __name__ == "__main__":
unittest.main()
@@ -4,9 +4,7 @@ import unittest
from opendbc.car.structs import CarParams
from opendbc.car.volkswagen.values import VolkswagenSafetyFlags
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
MAX_ACCEL = 2.0
MIN_ACCEL = -3.5
@@ -28,8 +26,6 @@ MSG_TA_01 = 0x26B
MSG_ACC_19 = 0x300
MSG_HCA_03 = 0x303
MSG_LDW_02 = 0x397
class TestVolkswagenMebSafetyBase(common.CarSafetyTest, common.CurvatureSteeringSafetyTest):
STANDSTILL_THRESHOLD = 0
@@ -193,19 +189,19 @@ class TestVolkswagenMebSafetyBase(common.CarSafetyTest, common.CurvatureSteering
for name in ("LH_EPS_03", "Motor_14", "GRA_ACC_01", "QFK_01", "ESP_21", "Motor_51", "ESC_51"):
with self.subTest(msg=name):
# an expected counter sequence is always accepted, and clears the wrong counter count
next_counter = common.MAX_WRONG_COUNTERS + 1
for counter in range(next_counter):
self.assertTrue(self._rx(self.packer.make_can_msg_safety(name, 0, {"COUNTER": counter})))
for _ in range(common.MAX_WRONG_COUNTERS + 1):
self.assertTrue(self._rx(self.packer.make_can_msg_safety(name, 0, {})))
# mess with the checksum to make it fail, it's the first byte of every MEB message
msg = self.packer.make_can_msg_safety(name, 0, {"COUNTER": next_counter})
msg = self.packer.make_can_msg_safety(name, 0, {})
msg[0].data[0] ^= 0xFF
self.assertFalse(self._rx(msg))
# a stuck counter fails as well, its checksum is still correct
msg[0].data[0] ^= 0xFF
for i in range(common.MAX_WRONG_COUNTERS):
should_rx = i < common.MAX_WRONG_COUNTERS - 1
self.assertEqual(should_rx, self._rx(self.packer.make_can_msg_safety(name, 0, {"COUNTER": next_counter})))
self.assertEqual(should_rx, self._rx(msg))
def test_main_switch_off_disables_controls(self):
self.safety.set_controls_allowed(True)
@@ -258,9 +254,10 @@ class TestVolkswagenMebSafetyBase(common.CarSafetyTest, common.CurvatureSteering
# controls_allowed is checked if actuation bit is 1, else the curvature must be zero (inactive)
should_tx = controls_allowed if steer_req else round(curvature_cmd * self.CURVATURE_TO_CAN) == 0
self.assertEqual(should_tx, self._tx(self._curvature_cmd_msg(curvature_cmd, steer_req=steer_req, power=50 if steer_req else 0)))
class TestVolkswagenMebSafety(TestVolkswagenMebSafetyBase):
DBC = "vw_meb_generated"
SAFETY_MODEL = CarParams.SafetyModel.volkswagenMeb
TX_MSGS = [[MSG_HCA_03, 0], [MSG_LDW_02, 0], [MSG_ACC_19, 0], [MSG_ACC_18, 0],
[MSG_TA_01, 0], [MSG_KLR_01, 0], [MSG_KLR_01, 2]]
FWD_BLACKLISTED_ADDRS = {0: [MSG_KLR_01],
@@ -271,12 +268,6 @@ class TestVolkswagenMebSafety(TestVolkswagenMebSafetyBase):
ACCEL_OVERRIDE = 0
INACTIVE_ACCEL = 3.01
def setUp(self):
self.packer = CANPackerSafety("vw_meb_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenMeb, 0)
self.safety.init_tests()
# stock cruise controls are entirely bypassed under openpilot longitudinal control
def test_disable_control_allowed_from_cruise(self):
pass
@@ -357,24 +348,16 @@ class TestVolkswagenMebSafety(TestVolkswagenMebSafetyBase):
self.safety.set_controls_allowed(controls_allowed)
send = controls_allowed or acc_status not in (ACC_AKTIV_REGELT, ACC_OVERRIDE)
self.assertEqual(send, self._tx(self._accel_msg(self.INACTIVE_ACCEL, acc_status=acc_status)))
class TestVolkswagenMebGen2Safety(TestVolkswagenMebSafety):
def setUp(self):
self.packer = CANPackerSafety("vw_meb_2024_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenMeb, VolkswagenSafetyFlags.MEB_ALT_CRC)
self.safety.init_tests()
DBC = "vw_meb_2024_generated"
SAFETY_PARAM = VolkswagenSafetyFlags.MEB_ALT_CRC
# ZAS_Kl_15=1
class TestVolkswagenMebIgnition(unittest.TestCase):
TX_MSGS: list = []
class TestVolkswagenMebIgnition(common.SafetyTestBase):
DBC = "vw_meb_generated"
SAFETY_MODEL = None
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety.init_tests()
self.packer = CANPackerSafety("vw_meb_generated")
TX_MSGS: list = []
def _msg(self, counter, ign):
return self.packer.make_can_msg_safety("Klemmen_Status_01", 0,
@@ -396,7 +379,5 @@ class TestVolkswagenMebIgnition(unittest.TestCase):
self.safety.ignition_can_hook(self._msg(2, 0))
self.safety.ignition_can_hook(self._msg(3, 0))
self.assertFalse(self.safety.get_ignition_can())
if __name__ == "__main__":
unittest.main()
@@ -1,15 +1,11 @@
#!/usr/bin/env python3
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
MSG_LS_01 = 0x10B # TX by OP, ACC control buttons for cancel/resume
MSG_HCA_01 = 0x126 # TX by OP, Heading Control Assist steering torque
MSG_LDW_02 = 0x397 # TX by OP, Lane line recognition and text alerts
class TestVolkswagenMlbSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest):
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_01, MSG_LDW_02)}
@@ -82,39 +78,14 @@ class TestVolkswagenMlbSafetyBase(common.CarSafetyTest, common.DriverTorqueSteer
self._rx(self._esp_05_msg(esp_05_signal))
self.assertEqual(brake_pressed, self.safety.get_brake_pressed_prev(),
f"expected {brake_pressed=} with {motor_03_signal=} and {esp_05_signal=}")
def test_torque_measurements(self):
# TODO: make this test work with all cars
self._rx(self._torque_driver_msg(50))
self._rx(self._torque_driver_msg(-50))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self.assertEqual(-50, self.safety.get_torque_driver_min())
self.assertEqual(50, self.safety.get_torque_driver_max())
self._rx(self._torque_driver_msg(0))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(-50, self.safety.get_torque_driver_min())
self._rx(self._torque_driver_msg(0))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(0, self.safety.get_torque_driver_min())
class TestVolkswagenMlbStockSafety(TestVolkswagenMlbSafetyBase):
DBC = "vw_mlb"
SAFETY_MODEL = CarParams.SafetyModel.volkswagenMlb
TX_MSGS = [[MSG_HCA_01, 0], [MSG_LDW_02, 0], [MSG_LS_01, 0], [MSG_LS_01, 2]]
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_01, MSG_LDW_02]}
FWD_BUS_LOOKUP = {0: 2, 2: 0}
def setUp(self):
self.packer = CANPackerSafety("vw_mlb")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenMlb, 0)
self.safety.init_tests()
def test_spam_cancel_safety_check(self):
self.safety.set_controls_allowed(0)
self.assertTrue(self._tx(self._ls_01_msg(cancel=1)))
@@ -130,7 +101,5 @@ class TestVolkswagenMlbStockSafety(TestVolkswagenMlbSafetyBase):
self.safety.set_controls_allowed(1)
self._rx(self._ls_01_msg(cancel=True, bus=0))
self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after cancel")
if __name__ == "__main__":
unittest.main()
@@ -2,9 +2,7 @@
import unittest
import numpy as np
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
from opendbc.car.volkswagen.values import VolkswagenSafetyFlags
MAX_ACCEL = 2.0
@@ -17,9 +15,8 @@ MSG_GRA_ACC_01 = 0x12B # TX by OP, ACC control buttons for cancel/resume
MSG_ACC_07 = 0x12E # TX by OP, ACC control instructions to the drivetrain coordinator
MSG_ACC_02 = 0x30C # TX by OP, ACC HUD data to the instrument cluster
MSG_LDW_02 = 0x397 # TX by OP, Lane line recognition and text alerts
class TestVolkswagenMqbSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest):
DBC = "vw_mqb"
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_01, MSG_LDW_02), 2: (MSG_LH_EPS_03,)}
MAX_RATE_UP = 4
@@ -101,38 +98,12 @@ class TestVolkswagenMqbSafetyBase(common.CarSafetyTest, common.DriverTorqueSteer
self._rx(self._esp_05_msg(esp_05_signal))
self.assertEqual(brake_pressed, self.safety.get_brake_pressed_prev(),
f"expected {brake_pressed=} with {motor_14_signal=} and {esp_05_signal=}")
def test_torque_measurements(self):
# TODO: make this test work with all cars
self._rx(self._torque_driver_msg(50))
self._rx(self._torque_driver_msg(-50))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self.assertEqual(-50, self.safety.get_torque_driver_min())
self.assertEqual(50, self.safety.get_torque_driver_max())
self._rx(self._torque_driver_msg(0))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(-50, self.safety.get_torque_driver_min())
self._rx(self._torque_driver_msg(0))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(0, self.safety.get_torque_driver_min())
class TestVolkswagenMqbStockSafety(TestVolkswagenMqbSafetyBase):
SAFETY_MODEL = CarParams.SafetyModel.volkswagen
TX_MSGS = [[MSG_HCA_01, 0], [MSG_LDW_02, 0], [MSG_LH_EPS_03, 2], [MSG_GRA_ACC_01, 0], [MSG_GRA_ACC_01, 2]]
FWD_BLACKLISTED_ADDRS = {0: [MSG_LH_EPS_03], 2: [MSG_HCA_01, MSG_LDW_02]}
def setUp(self):
self.packer = CANPackerSafety("vw_mqb")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagen, 0)
self.safety.init_tests()
def test_spam_cancel_safety_check(self):
self.safety.set_controls_allowed(0)
self.assertTrue(self._tx(self._gra_acc_01_msg(cancel=1)))
@@ -141,20 +112,15 @@ class TestVolkswagenMqbStockSafety(TestVolkswagenMqbSafetyBase):
# do not block resume if we are engaged already
self.safety.set_controls_allowed(1)
self.assertTrue(self._tx(self._gra_acc_01_msg(resume=1)))
class TestVolkswagenMqbLongSafety(TestVolkswagenMqbSafetyBase):
SAFETY_MODEL = CarParams.SafetyModel.volkswagen
SAFETY_PARAM = VolkswagenSafetyFlags.LONG_CONTROL
TX_MSGS = [[MSG_HCA_01, 0], [MSG_LDW_02, 0], [MSG_LH_EPS_03, 2], [MSG_ACC_02, 0], [MSG_ACC_06, 0], [MSG_ACC_07, 0]]
FWD_BLACKLISTED_ADDRS = {0: [MSG_LH_EPS_03], 2: [MSG_HCA_01, MSG_LDW_02, MSG_ACC_02, MSG_ACC_06, MSG_ACC_07]}
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_01, MSG_LDW_02, MSG_ACC_02, MSG_ACC_06, MSG_ACC_07), 2: (MSG_LH_EPS_03,)}
INACTIVE_ACCEL = 3.01
def setUp(self):
self.packer = CANPackerSafety("vw_mqb")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagen, VolkswagenSafetyFlags.LONG_CONTROL)
self.safety.init_tests()
# stock cruise controls are entirely bypassed under openpilot longitudinal control
def test_disable_control_allowed_from_cruise(self):
pass
@@ -206,7 +172,5 @@ class TestVolkswagenMqbLongSafety(TestVolkswagenMqbSafetyBase):
self.assertEqual(send, self._tx(self._acc_07_msg(accel)), (controls_allowed, accel))
# ensure the optional secondary accel field remains inactive for now
self.assertEqual(is_inactive_accel, self._tx(self._acc_07_msg(accel, secondary_accel=accel)), (controls_allowed, accel))
if __name__ == "__main__":
unittest.main()
@@ -3,18 +3,15 @@ import unittest
from opendbc.car.volkswagen.values import VolkswagenSafetyFlags
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
MSG_HCA_1 = 0x0D2 # TX by OP, Heading Control Assist steering torque
MSG_ACC_SYSTEM = 0x368 # TX by OP, longitudinal acceleration controls
MSG_GRA_NEU = 0x38A # TX by OP, ACC control buttons for cancel/resume
MSG_ACC_GRA_ANZEIGE = 0x56A # TX by OP, ACC HUD
MSG_LDW_1 = 0x5BE # TX by OP, Lane line recognition and text alerts
class TestVolkswagenPqSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest):
DBC = "vw_pq"
cruise_engaged = False
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_1, MSG_LDW_1)}
@@ -82,39 +79,13 @@ class TestVolkswagenPqSafetyBase(common.CarSafetyTest, common.DriverTorqueSteeri
def _button_msg(self, _set=False, resume=False, cancel=False, bus=2):
values = {"GRA_Neu_Setzen": _set, "GRA_Recall": resume, "GRA_Abbrechen": cancel}
return self.packer.make_can_msg_safety("GRA_Neu", bus, values)
def test_torque_measurements(self):
# TODO: make this test work with all cars
self._rx(self._torque_driver_msg(50))
self._rx(self._torque_driver_msg(-50))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self._rx(self._torque_driver_msg(0))
self.assertEqual(-50, self.safety.get_torque_driver_min())
self.assertEqual(50, self.safety.get_torque_driver_max())
self._rx(self._torque_driver_msg(0))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(-50, self.safety.get_torque_driver_min())
self._rx(self._torque_driver_msg(0))
self.assertEqual(0, self.safety.get_torque_driver_max())
self.assertEqual(0, self.safety.get_torque_driver_min())
class TestVolkswagenPqStockSafety(TestVolkswagenPqSafetyBase):
# Transmit of GRA_Neu is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
SAFETY_MODEL = CarParams.SafetyModel.volkswagenPq
TX_MSGS = [[MSG_HCA_1, 0], [MSG_GRA_NEU, 0], [MSG_GRA_NEU, 2], [MSG_LDW_1, 0]]
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_1, MSG_LDW_1]}
def setUp(self):
self.packer = CANPackerSafety("vw_pq")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenPq, 0)
self.safety.init_tests()
def test_spam_cancel_safety_check(self):
self.safety.set_controls_allowed(0)
self.assertTrue(self._tx(self._button_msg(cancel=True)))
@@ -123,20 +94,15 @@ class TestVolkswagenPqStockSafety(TestVolkswagenPqSafetyBase):
# do not block resume if we are engaged already
self.safety.set_controls_allowed(1)
self.assertTrue(self._tx(self._button_msg(resume=True)))
class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.LongitudinalAccelSafetyTest):
SAFETY_MODEL = CarParams.SafetyModel.volkswagenPq
SAFETY_PARAM = VolkswagenSafetyFlags.LONG_CONTROL
TX_MSGS = [[MSG_HCA_1, 0], [MSG_LDW_1, 0], [MSG_ACC_SYSTEM, 0], [MSG_ACC_GRA_ANZEIGE, 0]]
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_1, MSG_LDW_1, MSG_ACC_SYSTEM, MSG_ACC_GRA_ANZEIGE]}
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_1, MSG_LDW_1, MSG_ACC_SYSTEM, MSG_ACC_GRA_ANZEIGE)}
INACTIVE_ACCEL = 3.01
def setUp(self):
self.packer = CANPackerSafety("vw_pq")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenPq, VolkswagenSafetyFlags.LONG_CONTROL)
self.safety.init_tests()
# stock cruise controls are entirely bypassed under openpilot longitudinal control
def test_disable_control_allowed_from_cruise(self):
pass
@@ -181,7 +147,5 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal
for enabled_status in (5, 7):
self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP, steer_req=1, hca_status=enabled_status)),
f"torque cmd rejected with {enabled_status=}")
if __name__ == "__main__":
unittest.main()