mirror of
https://jihulab.com/mr-one/openpilot.git
synced 2026-10-26 20:43:49 +08:00
test: sync opendbc safety models (stage 2b)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 }}},
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 }}},
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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(¤t_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':
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user