Restore Honda Nidec pedal lateral ownership

This commit is contained in:
firestar5683
2026-10-22 14:59:39 -05:00
parent 744032b961
commit 456c1955a1
50 changed files with 289 additions and 101 deletions
@@ -36,7 +36,10 @@ def qualified(cp):
cp.openpilotLongitudinalControl and not cp.pcmCruise and
not cp.passive and not cp.dashcamOnly and not cp.notCar and len(configs) == 1 and
configs[0].safetyModel == structs.CarParams.SafetyModel.hondaNidec and
configs[0].safetyParam == (36 if cp.flags & HondaFlags.NIDEC_ALT_SCM_MESSAGES else 32))
(configs[0].safetyParam == (36 if cp.flags & HondaFlags.NIDEC_ALT_SCM_MESSAGES else 32) or
(len(cp.safetyConfigs) == 1 and cp.alternativeExperience == 32 and
configs[0].safetyParam == ((36 if cp.flags & HondaFlags.NIDEC_ALT_SCM_MESSAGES else 32) | 512 |
(256 if cp.carFingerprint == CAR.HONDA_ODYSSEY_TWN else 0)))))
def create_command(packer, gas_amount, counter):
+11 -3
View File
@@ -31,12 +31,13 @@ CANFD_STOCK = frozenset((CAR.HONDA_CRV_6G, CAR.HONDA_PILOT_4G,
ALT_RADAR_STOCK = frozenset((CAR.ACURA_RDX_3G_MMR, CAR.HONDA_ODYSSEY_5G_MMR,
CAR.ACURA_TLX_2G, CAR.ACURA_MDX_4G))
BOSCH_WORDS = frozenset((0, 1, 8, 9, 10, 11, 16, 17, 80, 81, 512, 513, 1058, 1059, 1570, 1571))
NIDEC_WORDS = frozenset((0, 4, 260))
NIDEC_WORDS = frozenset((0, 4, 260, 544, 548, 804))
# qualified() runs several times per 100 Hz frame in card and selfdrived, so
# everything that depends only on this module is computed once, and its flag
# tests use plain ints: IntFlag operators cost microseconds each in Python.
_DETECTED = int(HondaFlags.BOSCH_EXT_HUD | HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.HAS_BSM | HondaFlags.EPS_MODIFIED | HondaFlags.HYBRID)
_DETECTED = int(HondaFlags.BOSCH_EXT_HUD | HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.HAS_BSM |
HondaFlags.EPS_MODIFIED | HondaFlags.HYBRID | HondaFlags.GAS_INTERCEPTOR)
_ALLOWED_FLAGS = {str(car): int(car.config.flags) | _DETECTED
for car in CLASSIC_BOSCH | NIDEC | RADARLESS | CANFD_STOCK | ALT_RADAR_STOCK | {CAR.HONDA_ACCORD_11G}}
_BOSCH, _BOSCH_RADARLESS, _BOSCH_ALT_BRAKE = int(HondaFlags.BOSCH), int(HondaFlags.BOSCH_RADARLESS), int(HondaFlags.BOSCH_ALT_BRAKE)
@@ -60,6 +61,8 @@ def qualified(cp, *, marked_only=False):
flags = int(cp.flags)
if flags & ~allowed:
return False
if flags & int(HondaFlags.GAS_INTERCEPTOR) and fingerprint not in NIDEC:
return False
if fingerprint in ALT_RADAR_STOCK:
expected = int(bool(flags & _BOSCH_ALT_BRAKE))
if cp.openpilotLongitudinalControl:
@@ -85,9 +88,14 @@ def qualified(cp, *, marked_only=False):
return False
if fingerprint in NIDEC and flags & _NIDEC and not flags & _BOSCH:
expected = 4 if flags & _NIDEC_ALT_SCM_MESSAGES else 0
pedal = bool(flags & int(HondaFlags.GAS_INTERCEPTOR))
if pedal:
expected |= int(HondaSafetyFlags.GAS_INTERCEPTOR)
if cp.alternativeExperience == 32:
expected |= int(HondaSafetyFlags.NIDEC_PEDAL_AOL)
if fingerprint == CAR.HONDA_ODYSSEY_TWN and cp.alternativeExperience == 32:
expected |= 256
return (cp.pcmCruise and cp.openpilotLongitudinalControl and
return (bool(cp.pcmCruise) == (not pedal) and cp.openpilotLongitudinalControl and
safety.safetyModel == _HONDA_NIDEC and safety.safetyParam == expected)
if fingerprint in CLASSIC_BOSCH and flags & _BOSCH and not flags & _BOSCH_RADARLESS:
expected = int(bool(flags & _BOSCH_ALT_BRAKE))
@@ -0,0 +1,119 @@
"""Nidec pedal AOL preserves the actual selected sender and current sensor gate."""
import os
from unittest.mock import patch
import pytest
from opendbc.car import structs
from opendbc.car.honda.interface import CarInterface
from opendbc.car.honda.radar_interface import RadarInterface
from opendbc.car.honda.tests.test_nidec_interceptor import IDENTITIES, factory
from opendbc.car.honda.values import CAR
from openpilot.common.params import Params
from openpilot.common.prefix import OpenpilotPrefix
@pytest.mark.parametrize('identity', IDENTITIES)
def test_actual_pedal_factory_card_and_reconstructed_controller_keep_the_sender(identity):
from opendbc.car.honda.stock_aol import qualified
from opendbc.car.honda.nidec_interceptor import qualified as pedal_qualified
from openpilot.selfdrive.car.card import Car
from openpilot.starpilot.car.honda.aol import native_accepts_cp
original = factory(identity)
assert pedal_qualified(original) and qualified(original)
base = original.safetyConfigs[0].safetyParam
for enabled in (False, True):
with OpenpilotPrefix(), patch.dict(os.environ, {'SIMULATION':'1', 'AOL_REPLAY_RUNTIME':'1'}):
saved = Params()
saved.put_bool('OpenpilotEnabledToggle', True, block=True)
saved.put_bool('AlwaysOnLateral', enabled, block=True)
cp = original.as_reader().as_builder()
card = Car(CI=CarInterface(cp), RI=RadarInterface(cp))
expected = base | ((512 | (256 if identity == CAR.HONDA_ODYSSEY_TWN else 0)) if enabled else 0)
assert card.CP.safetyConfigs[0].safetyParam == expected
assert card.CP.alternativeExperience == (32 if enabled else 0)
assert card.aol_qualified == enabled
assert not card.CP.pcmCruise and card.CP.openpilotLongitudinalControl
with structs.CarParams.from_bytes(saved.get('CarParams')) as published:
assert published.to_dict() == card.CP.to_dict()
restored = published.as_builder()
# Construct from FINAL published params, not merely the pre-marker object.
rebuilt = CarInterface(restored)
assert rebuilt.CC.nidec_interceptor is not None
assert pedal_qualified(restored)
assert native_accepts_cp(restored, 1, expected) == enabled
bad = restored.as_reader().as_builder()
bad.safetyConfigs[0].safetyParam |= 0x4000
assert not qualified(bad) and not pedal_qualified(bad)
CASES = (
('pedal', 1, 544, 0, 'honda_civic_touring_2016_can_generated', False, 'GEARBOX_CVT', 4),
('pedal-alt', 1, 548, 0, 'acura_ilx_2016_can_generated', True, 'GEARBOX_AUTO', 4),
('pedal-twn', 1, 804, 0, 'honda_odyssey_twn_2018_generated', True, 'GEARBOX_AUTO', 4),
)
@pytest.mark.parametrize('profile', CASES)
@pytest.mark.parametrize('loss', ('sensor_fault', 'sensor_expired', 'wrong_bus', 'bad_tx_crc'))
def test_actual_pedal_native_brake_sensor_and_transmitted_crc_contract(profile, loss):
from opendbc.car.honda.nidec_interceptor import create_command
from opendbc.safety.tests.test_honda_stock_aol import TestHondaStockAol
from opendbc.safety.tests.libsafety import libsafety_py
native = TestHondaStockAol(methodName='runTest')
try:
native.configure(profile)
native.stream()
native.normal_engage()
native.safety.aol_set_host_request(3)
assert native.safety.get_controls_allowed()
assert native.safety.aol_get_permission_mask() == 3
active = create_command(native.packer, .5, 0)
# CANPackerSafety inherits the actual packer; use its real message encoding.
def packet(msg):
return libsafety_py.make_CANPacket(msg[0], msg[2], msg[1])
assert native.safety.safety_tx_hook(packet(active))
native.press_brake()
assert not native.safety.get_controls_allowed()
assert native.safety.aol_get_permission_mask() == 1
assert not native.safety.safety_tx_hook(packet(active))
neutral = create_command(native.packer, 0., 1)
assert native.safety.safety_tx_hook(packet(neutral))
native.stream()
assert not native.safety.get_controls_allowed() # No longitudinal auto-resume.
if loss == 'sensor_fault':
assert native.safety.safety_rx_hook(native.packet('GAS_SENSOR', {'STATE':1}))
assert native.safety.aol_get_permission_mask() == 0
elif loss in ('sensor_expired', 'wrong_bus'):
native.safety.set_timer(1_200_001)
native.stream(omit='GAS_SENSOR')
if loss == 'wrong_bus':
assert native.safety.safety_rx_hook(native.packet('GAS_SENSOR', {'STATE':0}, 1))
assert native.safety.aol_get_permission_mask() == 0
else:
data = bytearray(neutral[1])
data[5] ^= 1
assert not native.safety.safety_tx_hook(libsafety_py.make_CANPacket(neutral[0], neutral[2], data))
if loss != 'bad_tx_crc':
native.stream()
assert native.safety.aol_get_permission_mask() == 0
finally:
libsafety_py.libsafety.set_alternative_experience(0)
@pytest.mark.parametrize('identity', (CAR.HONDA_CIVIC, CAR.ACURA_ILX, CAR.HONDA_ODYSSEY_TWN))
def test_actual_pedal_card_sd_controls_lat_only_preserves_long_pause(identity):
from openpilot.starpilot.aol.tests.stock_lateral_test_helpers import honda_family_case
with OpenpilotPrefix():
case = honda_family_case('honda', True)
case.family_cp = factory(identity).as_reader()
try:
sd, _, drive, card, receive = case.family_callers(False)
assert card.CI.CC.nidec_interceptor is not None
axis, _, command = drive(2, native_request_long=False, panda_controls_allowed=False)
assert axis.lateralActive and command.latActive
assert not axis.longitudinalActive and not command.longActive
assert receive(10_020_000_000, axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
finally:
case.doCleanups()
+1
View File
@@ -93,6 +93,7 @@ class HondaSafetyFlags(IntFlag):
BOSCH_CANFD = 16
BOSCH_CANFD_MVL = 64
ALT_RADAR_AOL = 1024 # Exact marked DEBUG alpha owner; physical EPS/gear token.
NIDEC_PEDAL_AOL = 512 # Model1 only; distinct from model20 STOCK_TJA.
STOCK_TJA = 512 # Marked MDX4G AOL; EPS status1 is healthy TJA lockout.
+5 -2
View File
@@ -38,7 +38,9 @@ static bool honda_mvl_stock = false;
static uint8_t honda_mvl_buttons_fresh = 0U;
static bool honda_rdx_high_gas = false;
static bool aol_honda_bosch_long = false;
static uint32_t aol_honda_main_ts = 0U;
// Legacy and source-bound Honda owners are mutually exclusive. Both require
// the same physical MAIN timestamp, so retain a single storage location.
#define aol_honda_main_ts honda_stock_aol_main_ts
#define AOL_HONDA_MAIN_TIMEOUT_US 300000U
typedef enum {HONDA_NIDEC, HONDA_BOSCH} HondaHw;
static HondaHw honda_hw = HONDA_NIDEC;
@@ -369,7 +371,8 @@ static safety_config honda_nidec_init(uint16_t param) {
.msg = {{0x201, 0, 6, 50U, .ignore_checksum = true,
.ignore_counter = true, .ignore_quality_flag = true}, {0}, {0}},
};
honda_interceptor_reset((param == 32U) || (param == 36U));
honda_interceptor_reset((param == 32U) || (param == 36U) ||
((alternative_experience == 32) && ((param == 544U) || (param == 548U) || (param == 804U))));
const uint16_t HONDA_PARAM_NIDEC_ALT = 4;
honda_hw = HONDA_NIDEC;
@@ -1,70 +1,94 @@
#pragma once
static bool honda_stock_aol_enabled = false;
static bool honda_stock_aol_token = false;
static bool honda_stock_aol_pending = false;
// Keep each flag update atomic across CAN/USB interrupts while compacting
// private storage. No policy, source checks, or deadlines change.
static uint16_t honda_stock_aol_flags = 0U;
_Static_assert(__atomic_always_lock_free(sizeof(honda_stock_aol_flags), &honda_stock_aol_flags), "Honda flag atomicity");
enum {
HONDA_STOCK_ENABLED = 1U << 0U,
HONDA_STOCK_TOKEN = 1U << 1U,
HONDA_STOCK_PENDING = 1U << 2U,
HONDA_STOCK_MAIN_NEUTRAL = 1U << 3U,
HONDA_STOCK_LKAS_NEUTRAL = 1U << 4U,
HONDA_STOCK_LKAS_PREVIOUS = 1U << 5U,
HONDA_STOCK_SESSION = 1U << 6U,
HONDA_STOCK_REQUEST_SEEN = 1U << 7U,
HONDA_STOCK_ALT_MAIN = 1U << 8U,
HONDA_STOCK_DRIVE = 1U << 9U,
HONDA_STOCK_TWN = 1U << 10U,
HONDA_STOCK_TJA = 1U << 11U,
HONDA_STOCK_ALT_LONG = 1U << 12U,
};
static bool honda_stock_aol_flag(uint16_t bit) {
return (__atomic_load_n(&honda_stock_aol_flags, __ATOMIC_RELAXED) & bit) != 0U;
}
static void honda_stock_aol_set_flag(uint16_t bit, bool value) {
if (value) {
__atomic_fetch_or(&honda_stock_aol_flags, bit, __ATOMIC_RELAXED);
} else {
__atomic_fetch_and(&honda_stock_aol_flags, (uint16_t)~bit, __ATOMIC_RELAXED);
}
}
static uint32_t honda_stock_aol_grant_ts = 0U;
static bool honda_stock_aol_main_neutral = false;
static bool honda_stock_aol_lkas_neutral = false;
static bool honda_stock_aol_lkas_previous = false;
static bool honda_stock_aol_session = false;
static bool honda_stock_aol_request_seen = false;
static bool honda_stock_aol_alt_main = false;
static bool honda_stock_aol_drive = false;
static bool honda_stock_aol_twn = false;
static bool honda_stock_aol_tja = false;
static bool honda_stock_aol_alt_long = false;
static uint8_t honda_stock_aol_eps = 0U;
static uint32_t honda_stock_aol_main_ts = 0U;
static RxCheck *honda_stock_aol_eps_check = NULL;
static RxCheck *honda_stock_aol_gear_check = NULL;
static RxCheck honda_rx_workspace[7];
static RxCheck honda_rx_workspace[8];
// EPS and gear entries are always adjacent; derive the second pointer.
static RxCheck *honda_stock_aol_gear_check(void) {
return (honda_stock_aol_eps_check != NULL) ? honda_stock_aol_eps_check + 1 : NULL;
}
static void honda_stock_aol_clear(void) {
honda_stock_aol_token = false;
honda_stock_aol_pending = false;
honda_stock_aol_main_neutral = false;
honda_stock_aol_lkas_neutral = false;
honda_stock_aol_set_flag(HONDA_STOCK_TOKEN, false);
honda_stock_aol_set_flag(HONDA_STOCK_PENDING, false);
honda_stock_aol_set_flag(HONDA_STOCK_MAIN_NEUTRAL, false);
honda_stock_aol_set_flag(HONDA_STOCK_LKAS_NEUTRAL, false);
}
// A new physical grant may precede the host engagement heartbeat. It grants no output
// until an engaged heartbeat and a fresh host request acknowledge this gesture.
static void honda_stock_aol_grant(void) {
honda_stock_aol_token = true;
honda_stock_aol_pending = !heartbeat_engaged;
honda_stock_aol_set_flag(HONDA_STOCK_TOKEN, true);
honda_stock_aol_set_flag(HONDA_STOCK_PENDING, !heartbeat_engaged);
honda_stock_aol_grant_ts = microsecond_timer_get();
honda_stock_aol_session = heartbeat_engaged;
honda_stock_aol_set_flag(HONDA_STOCK_SESSION, heartbeat_engaged);
}
static void honda_stock_aol_reset(void) {
honda_stock_aol_clear();
honda_stock_aol_enabled = false;
honda_stock_aol_session = false;
honda_stock_aol_request_seen = false;
honda_stock_aol_alt_main = false;
honda_stock_aol_lkas_previous = false;
honda_stock_aol_drive = false;
honda_stock_aol_twn = false;
honda_stock_aol_tja = false;
honda_stock_aol_alt_long = false;
honda_stock_aol_set_flag(HONDA_STOCK_ENABLED, false);
honda_stock_aol_set_flag(HONDA_STOCK_SESSION, false);
honda_stock_aol_set_flag(HONDA_STOCK_REQUEST_SEEN, false);
honda_stock_aol_set_flag(HONDA_STOCK_ALT_MAIN, false);
honda_stock_aol_set_flag(HONDA_STOCK_LKAS_PREVIOUS, false);
honda_stock_aol_set_flag(HONDA_STOCK_DRIVE, false);
honda_stock_aol_set_flag(HONDA_STOCK_TWN, false);
honda_stock_aol_set_flag(HONDA_STOCK_TJA, false);
honda_stock_aol_set_flag(HONDA_STOCK_ALT_LONG, false);
honda_stock_aol_eps = 0U;
honda_stock_aol_main_ts = 0U;
honda_stock_aol_eps_check = NULL;
honda_stock_aol_gear_check = NULL;
}
static void honda_stock_aol_host_request(uint8_t mask) {
honda_stock_aol_request_seen |= mask != 0U;
if (mask != 0U) { honda_stock_aol_set_flag(HONDA_STOCK_REQUEST_SEEN, true); }
}
static bool honda_stock_aol_sources_current(void) {
bool current = false;
if ((honda_stock_aol_eps_check != NULL) && (honda_stock_aol_gear_check != NULL)) {
if ((honda_stock_aol_eps_check != NULL) && (honda_stock_aol_gear_check() != NULL)) {
const uint32_t now = microsecond_timer_get();
current = honda_stock_aol_eps_check->status.msg_seen && honda_stock_aol_gear_check->status.msg_seen &&
current = honda_stock_aol_eps_check->status.msg_seen && honda_stock_aol_gear_check()->status.msg_seen &&
(safety_get_ts_elapsed(now, honda_stock_aol_eps_check->status.last_timestamp) <= 300000U) &&
(safety_get_ts_elapsed(now, honda_stock_aol_gear_check->status.last_timestamp) <= 300000U) &&
(safety_get_ts_elapsed(now, honda_stock_aol_main_ts) <= 300000U);
(safety_get_ts_elapsed(now, honda_stock_aol_gear_check()->status.last_timestamp) <= 300000U) &&
(safety_get_ts_elapsed(now, honda_stock_aol_main_ts) <= 300000U) &&
(!honda_interceptor || (honda_interceptor_sensor_seen && honda_interceptor_sensor_valid &&
(safety_get_ts_elapsed(now, honda_interceptor_sensor_us) <= 200000U)));
}
return current;
}
@@ -73,21 +97,21 @@ static uint8_t honda_stock_aol_request_mask(void) {
uint8_t request = 0U;
const uint32_t now = microsecond_timer_get();
const uint32_t grant_age = safety_get_ts_elapsed(now, honda_stock_aol_grant_ts);
const bool pending_expired = honda_stock_aol_pending && (grant_age > AOL_HOST_REQUEST_TIMEOUT_US);
const bool expired = honda_stock_aol_request_seen &&
const bool pending_expired = honda_stock_aol_flag(HONDA_STOCK_PENDING) && (grant_age > AOL_HOST_REQUEST_TIMEOUT_US);
const bool expired = honda_stock_aol_flag(HONDA_STOCK_REQUEST_SEEN) &&
(safety_get_ts_elapsed(now, aol_host_request_ts) > AOL_HOST_REQUEST_TIMEOUT_US);
if (relay_malfunction || expired || pending_expired || safety_rx_checks_invalid ||
(honda_stock_aol_session && !heartbeat_engaged) ||
((honda_stock_aol_session || honda_stock_aol_pending) &&
(honda_stock_aol_flag(HONDA_STOCK_SESSION) && !heartbeat_engaged) ||
((honda_stock_aol_flag(HONDA_STOCK_SESSION) || honda_stock_aol_flag(HONDA_STOCK_PENDING)) &&
(!aol_rx_healthy() || !honda_stock_aol_sources_current()))) {
honda_stock_aol_clear();
honda_stock_aol_session = false;
honda_stock_aol_set_flag(HONDA_STOCK_SESSION, false);
} else if (heartbeat_engaged && aol_rx_healthy() && honda_stock_aol_sources_current()) {
const bool pending_ack = !honda_stock_aol_pending || ((aol_host_axis_mask != 0U) &&
const bool pending_ack = !honda_stock_aol_flag(HONDA_STOCK_PENDING) || ((aol_host_axis_mask != 0U) &&
(safety_get_ts_elapsed(now, aol_host_request_ts) <= grant_age));
if (pending_ack) {
honda_stock_aol_pending = false;
honda_stock_aol_session = true;
honda_stock_aol_set_flag(HONDA_STOCK_PENDING, false);
honda_stock_aol_set_flag(HONDA_STOCK_SESSION, true);
request = aol_host_axis_mask;
}
} else {
@@ -101,10 +125,10 @@ static uint8_t honda_stock_aol_permission_mask(void) {
// A temporary EPS fault (2/6, e.g. a hard driver override) withdraws lateral only;
// longitudinal stays with controls_allowed as in stock openpilot.
const bool eps_lateral = (honda_stock_aol_eps == 0U) || (honda_stock_aol_eps == 3U) || (honda_stock_aol_eps == 4U) ||
(honda_stock_aol_tja && (honda_stock_aol_eps == 1U));
(honda_stock_aol_flag(HONDA_STOCK_TJA) && (honda_stock_aol_eps == 1U));
const bool eps_known = eps_lateral || (honda_stock_aol_eps == 2U) || (honda_stock_aol_eps == 6U);
if (acc_main_on && honda_stock_aol_drive && eps_known) {
if (eps_lateral && (controls_allowed || honda_stock_aol_token)) {
if (acc_main_on && honda_stock_aol_flag(HONDA_STOCK_DRIVE) && eps_known) {
if (eps_lateral && (controls_allowed || honda_stock_aol_flag(HONDA_STOCK_TOKEN))) {
permission = request & 1U;
}
if (controls_allowed) {
@@ -124,53 +148,53 @@ static bool honda_stock_aol_selected(const CANPacket_t *msg, const RxCheck *chec
}
static void honda_stock_aol_rx(const CANPacket_t *msg, unsigned int pt_bus, bool normal_engagement) {
if (honda_stock_aol_enabled) {
if (honda_stock_aol_flag(HONDA_STOCK_ENABLED)) {
// Retire the old session before interpreting a new validated physical edge.
// The following gesture may create a bounded pending grant; a status read
// must not mistake that new grant for the retired session.
if (honda_stock_aol_session && !heartbeat_engaged) {
if (honda_stock_aol_flag(HONDA_STOCK_SESSION) && !heartbeat_engaged) {
honda_stock_aol_clear();
honda_stock_aol_session = false;
honda_stock_aol_set_flag(HONDA_STOCK_SESSION, false);
}
const unsigned int main_addr = honda_stock_aol_alt_main ? 0x1A6U : 0x326U;
const unsigned int buttons_addr = honda_stock_aol_alt_main ? 0x1A6U : 0x296U;
const unsigned int buttons_len = honda_stock_aol_alt_main ? 8U : 4U;
const unsigned int main_addr = honda_stock_aol_flag(HONDA_STOCK_ALT_MAIN) ? 0x1A6U : 0x326U;
const unsigned int buttons_addr = honda_stock_aol_flag(HONDA_STOCK_ALT_MAIN) ? 0x1A6U : 0x296U;
const unsigned int buttons_len = honda_stock_aol_flag(HONDA_STOCK_ALT_MAIN) ? 8U : 4U;
if (msg_matches(msg, main_addr, pt_bus, 8U)) {
const bool main_on = GET_BIT(msg, honda_stock_aol_alt_main ? 47U : 28U);
const bool main_on = GET_BIT(msg, honda_stock_aol_flag(HONDA_STOCK_ALT_MAIN) ? 47U : 28U);
honda_stock_aol_main_ts = microsecond_timer_get();
if (!main_on) {
honda_stock_aol_clear();
honda_stock_aol_main_neutral = true;
} else if (honda_stock_aol_main_neutral) {
honda_stock_aol_set_flag(HONDA_STOCK_MAIN_NEUTRAL, true);
} else if (honda_stock_aol_flag(HONDA_STOCK_MAIN_NEUTRAL)) {
honda_stock_aol_grant();
honda_stock_aol_main_neutral = false;
honda_stock_aol_set_flag(HONDA_STOCK_MAIN_NEUTRAL, false);
} else {
}
}
if (msg_matches(msg, buttons_addr, pt_bus, buttons_len)) {
const uint8_t setting = honda_stock_aol_alt_main ? ((msg->data[5] >> 2U) & 3U) : ((msg->data[0] >> 2U) & 3U);
const uint8_t setting = honda_stock_aol_flag(HONDA_STOCK_ALT_MAIN) ? ((msg->data[5] >> 2U) & 3U) : ((msg->data[0] >> 2U) & 3U);
const bool lkas = setting == 1U;
if (!lkas) {
honda_stock_aol_lkas_neutral = true;
} else if (honda_stock_aol_lkas_neutral && !honda_stock_aol_lkas_previous && acc_main_on) {
honda_stock_aol_set_flag(HONDA_STOCK_LKAS_NEUTRAL, true);
} else if (honda_stock_aol_flag(HONDA_STOCK_LKAS_NEUTRAL) && !honda_stock_aol_flag(HONDA_STOCK_LKAS_PREVIOUS) && acc_main_on) {
honda_stock_aol_grant();
honda_stock_aol_lkas_neutral = false;
honda_stock_aol_set_flag(HONDA_STOCK_LKAS_NEUTRAL, false);
} else {
}
honda_stock_aol_lkas_previous = lkas;
honda_stock_aol_set_flag(HONDA_STOCK_LKAS_PREVIOUS, lkas);
}
if (honda_stock_aol_selected(msg, honda_stock_aol_eps_check)) {
honda_stock_aol_eps = (msg->addr == 0x18FU) ?
(honda_stock_aol_twn ? (msg->data[5] & 15U) :
(honda_stock_aol_flag(HONDA_STOCK_TWN) ? (msg->data[5] & 15U) :
((GET_LEN(msg) == 6U) ? (msg->data[4] & 15U) : ((msg->data[4] >> 4U) & 15U))) :
((msg->data[1] >> 4U) & 15U);
if ((honda_stock_aol_eps != 0U) && (honda_stock_aol_eps != 2U) && (honda_stock_aol_eps != 3U) &&
(honda_stock_aol_eps != 4U) && (honda_stock_aol_eps != 6U) &&
!(honda_stock_aol_tja && (honda_stock_aol_eps == 1U))) {
!(honda_stock_aol_flag(HONDA_STOCK_TJA) && (honda_stock_aol_eps == 1U))) {
honda_stock_aol_clear();
}
}
if (honda_stock_aol_selected(msg, honda_stock_aol_gear_check)) {
if (honda_stock_aol_selected(msg, honda_stock_aol_gear_check())) {
uint8_t gear = msg->data[4] & 15U;
if (msg->addr == 0x191U) {
gear = msg->data[5] & 31U;
@@ -178,19 +202,19 @@ static void honda_stock_aol_rx(const CANPacket_t *msg, unsigned int pt_bus, bool
gear = msg->data[3] & 15U;
} else {
}
honda_stock_aol_drive = (msg->addr == 0x188U) ? ((gear == 8U) || (gear == 0U)) :
((gear == 4U) || (gear == 7U) || (gear == 10U) || (gear == 11U));
honda_stock_aol_set_flag(HONDA_STOCK_DRIVE, (msg->addr == 0x188U) ? ((gear == 8U) || (gear == 0U)) :
((gear == 4U) || (gear == 7U) || (gear == 10U) || (gear == 11U)));
}
// Only a newly accepted physical cruise grant can restore an independent token.
// Qualify after parsing this frame's brake/main state, before generic pedal checks.
const bool engagement_source = msg_matches(msg, 0x17CU, pt_bus, 8U) ||
msg_matches(msg, buttons_addr, pt_bus, buttons_len);
const bool request_current = !honda_stock_aol_request_seen ||
const bool request_current = !honda_stock_aol_flag(HONDA_STOCK_REQUEST_SEEN) ||
(safety_get_ts_elapsed(microsecond_timer_get(), aol_host_request_ts) <= AOL_HOST_REQUEST_TIMEOUT_US);
const bool eps_known = (honda_stock_aol_eps == 0U) || (honda_stock_aol_eps == 2U) ||
(honda_stock_aol_eps == 3U) || (honda_stock_aol_eps == 4U) || (honda_stock_aol_eps == 6U) ||
(honda_stock_aol_tja && (honda_stock_aol_eps == 1U));
if (normal_engagement && engagement_source && controls_allowed && acc_main_on && honda_stock_aol_drive &&
(honda_stock_aol_flag(HONDA_STOCK_TJA) && (honda_stock_aol_eps == 1U));
if (normal_engagement && engagement_source && controls_allowed && acc_main_on && honda_stock_aol_flag(HONDA_STOCK_DRIVE) &&
eps_known && !brake_pressed && !regen_braking && !steering_disengage &&
!relay_malfunction && !safety_rx_checks_invalid && request_current &&
aol_rx_healthy() && honda_stock_aol_sources_current()) {
@@ -200,8 +224,8 @@ static void honda_stock_aol_rx(const CANPacket_t *msg, unsigned int pt_bus, bool
}
static safety_config honda_copy_rx(const RxCheck *source, unsigned int count, safety_config ret) {
const unsigned int selected_count = (count <= 7U) ? count : 0U;
for (unsigned int i = 0U; i < 7U; i++) {
const unsigned int selected_count = (count <= 8U) ? count : 0U;
for (unsigned int i = 0U; i < 8U; i++) {
honda_rx_workspace[i] = (i < selected_count) ? source[i] : (RxCheck){0};
}
ret.rx_checks = honda_rx_workspace;
@@ -211,18 +235,18 @@ static safety_config honda_copy_rx(const RxCheck *source, unsigned int count, sa
static safety_config honda_stock_aol_configure(uint16_t param, bool nidec, bool alt_main, unsigned int pt_bus, safety_config ret) {
honda_stock_aol_reset();
bool valid = nidec ? ((param == 0U) || (param == 4U) || (param == 260U)) :
bool valid = nidec ? ((param == 0U) || (param == 4U) || (param == 260U) || (param == 544U) || (param == 548U) || (param == 804U)) :
((param == 0U) || (param == 1U) || (param == 8U) || (param == 9U) || (param == 16U) || (param == 17U) || (param == 80U) || (param == 81U) || (param == 512U) || (param == 513U));
#ifdef ALLOW_DEBUG
valid = valid || (!nidec && ((param == 10U) || (param == 11U) || (param == 1058U) || (param == 1059U) || (param == 1570U) || (param == 1571U)));
#endif
honda_stock_aol_enabled = valid && ((unsigned int)alternative_experience == 32U) &&
(ret.rx_checks_len >= 3) && (ret.rx_checks_len <= 5) && (pt_bus <= 1U);
honda_stock_aol_alt_main = alt_main;
honda_stock_aol_twn = nidec && (param == 260U);
honda_stock_aol_tja = !nidec && ((param == 512U) || (param == 513U) || (param == 1570U) || (param == 1571U));
honda_stock_aol_alt_long = !nidec && ((param == 1058U) || (param == 1059U) || (param == 1570U) || (param == 1571U));
if (honda_stock_aol_enabled && (ret.rx_checks_len <= 5) && (pt_bus <= 1U)) {
honda_stock_aol_set_flag(HONDA_STOCK_ENABLED, valid && ((unsigned int)alternative_experience == 32U) &&
(ret.rx_checks_len >= 3) && (ret.rx_checks_len <= 6) && (pt_bus <= 1U));
honda_stock_aol_set_flag(HONDA_STOCK_ALT_MAIN, alt_main);
honda_stock_aol_set_flag(HONDA_STOCK_TWN, nidec && ((param == 260U) || (param == 804U)));
honda_stock_aol_set_flag(HONDA_STOCK_TJA, !nidec && ((param == 512U) || (param == 513U) || (param == 1570U) || (param == 1571U)));
honda_stock_aol_set_flag(HONDA_STOCK_ALT_LONG, !nidec && ((param == 1058U) || (param == 1059U) || (param == 1570U) || (param == 1571U)));
if (honda_stock_aol_flag(HONDA_STOCK_ENABLED) && (ret.rx_checks_len <= 6) && (pt_bus <= 1U)) {
const unsigned int count = ret.rx_checks_len;
static const RxCheck eps[] = {
{.msg = {{0x18F, 0U, 7, 10U, .max_counter = 3U, .ignore_quality_flag = true},
@@ -247,16 +271,15 @@ static safety_config honda_stock_aol_configure(uint16_t param, bool nidec, bool
};
honda_rx_workspace[0] = buttons[alt_main ? 2U : pt_bus];
honda_rx_workspace[count] = eps[pt_bus];
if (honda_stock_aol_twn || honda_stock_aol_tja || honda_stock_aol_alt_long || (!nidec && ((param == 16U) || (param == 17U) || (param == 80U) || (param == 81U)))) {
if (honda_stock_aol_flag(HONDA_STOCK_TWN) || honda_stock_aol_flag(HONDA_STOCK_TJA) || honda_stock_aol_flag(HONDA_STOCK_ALT_LONG) || (!nidec && ((param == 16U) || (param == 17U) || (param == 80U) || (param == 81U)))) {
honda_rx_workspace[count].msg[1] = (CanMsgCheck){0};
honda_rx_workspace[count].msg[2] = (CanMsgCheck){0};
}
honda_rx_workspace[count + 1U] = gear[pt_bus];
if (honda_stock_aol_tja || honda_stock_aol_alt_long || (!nidec && ((param == 16U) || (param == 17U) || (param == 80U) || (param == 81U)))) {
if (honda_stock_aol_flag(HONDA_STOCK_TJA) || honda_stock_aol_flag(HONDA_STOCK_ALT_LONG) || (!nidec && ((param == 16U) || (param == 17U) || (param == 80U) || (param == 81U)))) {
honda_rx_workspace[count + 1U].msg[2] = (CanMsgCheck){0};
}
honda_stock_aol_eps_check = &honda_rx_workspace[count];
honda_stock_aol_gear_check = &honda_rx_workspace[count + 1U];
ret.rx_checks_len = count + 2U;
static const AolSafetyPolicy policy = {
.reset = honda_stock_aol_reset,
@@ -7,6 +7,9 @@ from opendbc.safety.tests.libsafety import libsafety_py
CASES = (
("nidec-pedal", 1, 544, 0, "honda_civic_touring_2016_can_generated", False, "GEARBOX_CVT", 4),
("nidec-pedal-alt", 1, 548, 0, "acura_ilx_2016_can_generated", True, "GEARBOX_AUTO", 4),
("nidec-pedal-twn", 1, 804, 0, "honda_odyssey_twn_2018_generated", True, "GEARBOX_AUTO", 4),
("accord-mvl-stock", 20, 80, 0, "honda_common_canfd_generated", False, "GEARBOX_AUTO", 4),
("accord-mvl-stock-alt-brake", 20, 81, 0, "honda_common_canfd_generated", False, "GEARBOX_AUTO", 4),
("alt-radar-alpha", 20, 1058, 1, "honda_civic_hatchback_ex_2017_can_generated", False, "GEARBOX_AUTO", 4),
@@ -50,6 +53,7 @@ class TestHondaStockAol(unittest.TestCase):
self.safety.set_aol_test_heartbeat(True)
self.packer = CANPackerSafety(dbc)
self.dbc = DBC(dbc)
self.pedal = model == 1 and word in (544, 548, 804)
self.scoped = experience == 32 and (word not in (10, 11, 1058, 1059, 1570, 1571) or self.debug)
def packet(self, name, values, bus=None):
@@ -74,6 +78,8 @@ class TestHondaStockAol(unittest.TestCase):
frames.append(("BRAKE_COMMAND", self.packet("BRAKE_COMMAND", {}, 2)))
elif self.case[2] & 1:
frames.append(("BRAKE_MODULE", self.packet("BRAKE_MODULE", {"BRAKE_PRESSED": brake})))
if self.pedal:
frames.append(("GAS_SENSOR", self.packet("GAS_SENSOR", {"INTERCEPTOR_GAS": 0, "INTERCEPTOR_GAS2": 0, "STATE": 0})))
for name, frame in frames:
if name != omit:
self.assertTrue(self.safety.safety_rx_hook(frame), name)
@@ -81,9 +87,11 @@ class TestHondaStockAol(unittest.TestCase):
self.safety.aol_set_host_request(1)
def normal_engage(self, *, button=3, gas=0, brake=0):
if self.debug and self.case[2] in (10, 11, 1058, 1059, 1570, 1571):
if self.pedal or (self.debug and self.case[2] in (10, 11, 1058, 1059, 1570, 1571)):
for value in (button, 0):
scm = {"CRUISE_BUTTONS": value, "CRUISE_SETTING": 0}
if self.alt:
scm["MAIN_ON"] = 1
self.assertTrue(self.safety.safety_rx_hook(self.packet("SCM_BUTTONS", scm)))
else:
self.assertTrue(self.safety.safety_rx_hook(self.packet("POWERTRAIN_DATA", {
@@ -100,7 +108,7 @@ class TestHondaStockAol(unittest.TestCase):
def test_normal_engagement_then_brake_without_main_or_lkas_gesture(self):
for case in CASES:
for button in ((3, 4) if case[2] in (10, 11, 1058, 1059, 1570, 1571) else (3,)):
for button in ((3, 4) if case[2] in (10, 11, 544, 548, 804, 1058, 1059, 1570, 1571) else (3,)):
for gas in (0, 1):
with self.subTest(case=case[0], button=button, gas=gas):
self.configure(case)
@@ -270,7 +278,7 @@ class TestHondaStockAol(unittest.TestCase):
def test_ae0_remains_without_independent_permission(self):
for case in CASES:
if case[2] == 260:
if case[2] in (260, 804):
continue
with self.subTest(case=case[0]):
self.configure(case, experience=0)
@@ -280,7 +288,7 @@ class TestHondaStockAol(unittest.TestCase):
def test_cold_valid_normal_grant_precedes_engaged_heartbeat(self):
for case in CASES:
for button in ((3, 4) if case[2] in (10, 11, 1058, 1059, 1570, 1571) else (3,)):
for button in ((3, 4) if case[2] in (10, 11, 544, 548, 804, 1058, 1059, 1570, 1571) else (3,)):
with self.subTest(case=case[0], button=button):
self.configure(case)
self.safety.set_aol_test_heartbeat(False)
Binary file not shown.
@@ -535,7 +535,7 @@ int main() {
assert(aol_capable(stock_honda, 20U, VEHICLE_REGISTRY) == (classic || stock));
assert(aol_runtime_enabled(false, stock_honda, VEHICLE_REGISTRY) == stock);
stock_honda.safety_mode = 1U;
const bool nidec = word == 0U || word == 4U || word == 260U;
const bool nidec = word == 0U || word == 4U || word == 260U || word == 544U || word == 548U || word == 804U;
assert(aol_capable(stock_honda, 1U, VEHICLE_REGISTRY) == nidec);
assert(aol_runtime_enabled(false, stock_honda, VEHICLE_REGISTRY) == nidec);
stock_honda.capability_flags = 0U;
@@ -0,0 +1,16 @@
"""Nidec pedal actual acquisition/parser/Card/Controls/native recovery."""
import pytest
from opendbc.car.honda.values import CAR
from openpilot.starpilot.aol.tests.test_honda_recovery_lifecycle import TestHondaCurrentCaller as CurrentCaller
from openpilot.starpilot.aol.tests.honda_native_fixture import honda_native_pair as honda_native_pair
@pytest.mark.usefixtures('honda_native_pair')
class TestHondaPedal(CurrentCaller):
def test_pedal_0_eps_reverse_recovery(self):
self.run_current_caller(candidate=CAR.HONDA_CIVIC, word=544, pedal=True)
def test_pedal_1_eps_reverse_recovery(self):
self.run_current_caller(candidate=CAR.ACURA_ILX, word=548, pedal=True)
def test_pedal_2_eps_reverse_recovery(self):
self.run_current_caller(candidate=CAR.HONDA_ODYSSEY_TWN, word=804, pedal=True)
@@ -56,7 +56,7 @@ class TestHondaCurrentCaller(unittest.TestCase):
def test_relay_fault_during_recovered_reverse(self):
self.run_current_caller(candidate=CAR.HONDA_CIVIC_BOSCH, word=0, fault='relay')
def run_current_caller(self, *, candidate, word, fault=None, alternate_brake=False, alpha=False, speed_mps=12.5):
def run_current_caller(self, *, candidate, word, fault=None, alternate_brake=False, alpha=False, speed_mps=12.5, pedal=False):
safety = libsafety_py.libsafety
with (
OpenpilotPrefix(),
@@ -81,6 +81,8 @@ class TestHondaCurrentCaller(unittest.TestCase):
pt_bus = 0 if nidec or candidate.config.flags & (HondaFlags.BOSCH_RADARLESS | HondaFlags.BOSCH_CANFD) else 1
gear_msg = CANDBC(DBC[candidate][Bus.pt]).name_to_msg['GEARBOX_AUTO']
fp[pt_bus][gear_msg.address] = gear_msg.size
if pedal:
fp[pt_bus][0x201] = 6
if alternate_brake:
fp[pt_bus][0x1BE] = 3
fw = [
@@ -108,7 +110,7 @@ class TestHondaCurrentCaller(unittest.TestCase):
self.assertEqual([record.to_dict() for record in cp.carFw], [record.to_dict() for record in fw])
self.assertEqual(cp.carFingerprint, candidate)
self.assertEqual((cp.safetyConfigs[0].safetyParam, cp.alternativeExperience), (word, 32))
self.assertEqual(cp.pcmCruise, not alpha)
self.assertEqual(cp.pcmCruise, not (alpha or pedal))
self.assertEqual(cp.openpilotLongitudinalControl, nidec or alpha)
self.assertEqual((ci.CC.CAN.pt, ci.CC.CAN.lkas), (pt_bus, pt_bus if alpha else 0))
alt_brake = bool(cp.flags & HondaFlags.BOSCH_ALT_BRAKE)
@@ -344,7 +346,7 @@ class TestHondaCurrentCaller(unittest.TestCase):
if not previous.latActive:
self.assertEqual((tx['torque'], tx['request']), (0, False), row)
else:
if alpha and address == 0x1DF and tick == 50:
if (alpha and address == 0x1DF or pedal and address == 0x200) and tick == 50:
# Card applies the prior Controls envelope. Physical brake has
# already revoked LONG; the native hook must reject this one
# in-flight positive command before the new envelope arrives.
+4
View File
@@ -37,6 +37,8 @@ def qualified_honda(CP) -> bool:
def policy_for(CP) -> AolVehiclePolicy:
if qualified_stock(CP):
safety_addition = 256 if CP.carFingerprint == CAR.HONDA_ODYSSEY_TWN else 0
if CP.flags & HondaFlags.GAS_INTERCEPTOR:
safety_addition |= int(HondaSafetyFlags.NIDEC_PEDAL_AOL)
if CP.carFingerprint in ALT_RADAR_STOCK:
if CP.carFingerprint == CAR.ACURA_MDX_4G:
safety_addition |= int(HondaSafetyFlags.STOCK_TJA)
@@ -82,6 +84,8 @@ def retain_on_native_denial(CP, native, state):
def create_intent(CP, settings):
if qualified_stock(CP):
safety_addition = 256 if CP.carFingerprint == CAR.HONDA_ODYSSEY_TWN else 0
if CP.flags & HondaFlags.GAS_INTERCEPTOR:
safety_addition |= int(HondaSafetyFlags.NIDEC_PEDAL_AOL)
if CP.carFingerprint in ALT_RADAR_STOCK:
if CP.carFingerprint == CAR.ACURA_MDX_4G:
safety_addition |= int(HondaSafetyFlags.STOCK_TJA)
+1 -1
View File
@@ -15,7 +15,7 @@ inline bool honda_stock_aol_param(uint16_t param) {
}
inline bool honda_nidec_aol_param(uint16_t param) {
return (param == 0U) || (param == 4U) || (param == 260U);
return (param == 0U) || (param == 4U) || (param == 260U) || (param == 544U) || (param == 548U) || (param == 804U);
}
inline constexpr AolSafetyProfile HONDA_STOCK_AOL_PROFILE{20U, honda_stock_aol_param, true};
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
extern const uint8_t gitversion[29];
const uint8_t gitversion[29] = "DEV-8462a39b-Pa5919516-DEBUG";
const uint8_t gitversion[29] = "DEV-6a773e7d-Pa5919516-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "5bbe44b1ca5388e4b8229fad9be7a8a1995c8b9e0ef9b132be58d7c0886e0c5f", "schema_version": 1}
{"protected_inventory_sha256": "2f31714d64735ea8ce197636014e315a1d6bd9b849b855cc9a12f0f8b30560f5", "schema_version": 1}
+1
View File
@@ -39,6 +39,7 @@ AOL_LIFECYCLE_TARGETS = (
"openpilot/starpilot/aol/tests/test_stock_lateral_honda.py",
"openpilot/starpilot/aol/tests/test_honda_reverse_join.py",
"openpilot/starpilot/aol/tests/test_honda_recovery_lifecycle.py",
"openpilot/starpilot/aol/tests/test_honda_pedal_lifecycle.py",
"openpilot/starpilot/aol/tests/test_honda_canfd_lifecycle.py",
"openpilot/starpilot/aol/tests/test_honda_alt_radar_lifecycle.py",
"openpilot/starpilot/aol/tests/test_fresh_inactive_transport.py",