Share banked Hyundai CAN-FD RX workspace to recover Panda RAM

This commit is contained in:
Dom
2026-10-30 09:07:01 -05:00
parent 18432adb3d
commit b64d7cf9e9
39 changed files with 204 additions and 35 deletions
@@ -1880,183 +1880,220 @@ static safety_config hyundai_canfd_init_validated(uint16_t supplied_param) {
}
}
// Only one banked profile is active; keep its mutable RX status in RAM,
// while the alternative configuration templates remain in flash.
static RxCheck banked_rx_workspace[7];
if (ioniq6_stock_aol_requested && (param != 0x0811U) && (param != 0x0891U)) {
RxCheck *selected = NULL;
const RxCheck *selected = NULL;
if (hyundai_canfd_lka_steer_msg) {
if (hyundai_hybrid_gas_signal) {
static RxCheck torque_hda2_hybrid_alt[] = {
static const RxCheck torque_hda2_hybrid_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(1, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
static RxCheck torque_hda2_hybrid_std[] = {
_Static_assert((sizeof(torque_hda2_hybrid_alt) / sizeof(torque_hda2_hybrid_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_hda2_hybrid_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(1, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
_Static_assert((sizeof(torque_hda2_hybrid_std) / sizeof(torque_hda2_hybrid_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_hda2_hybrid_alt : torque_hda2_hybrid_std;
} else {
static RxCheck torque_hda2_ice_alt[] = {
static const RxCheck torque_hda2_ice_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(1, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
static RxCheck torque_hda2_ice_std[] = {
_Static_assert((sizeof(torque_hda2_ice_alt) / sizeof(torque_hda2_ice_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_hda2_ice_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(1, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
_Static_assert((sizeof(torque_hda2_ice_std) / sizeof(torque_hda2_ice_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_hda2_ice_alt : torque_hda2_ice_std;
}
} else if (hyundai_camera_scc) {
if (hyundai_ev_gas_signal) {
static RxCheck torque_camera_ev_alt[] = {
static const RxCheck torque_camera_ev_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
static RxCheck torque_camera_ev_std[] = {
_Static_assert((sizeof(torque_camera_ev_alt) / sizeof(torque_camera_ev_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_camera_ev_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
_Static_assert((sizeof(torque_camera_ev_std) / sizeof(torque_camera_ev_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_camera_ev_alt : torque_camera_ev_std;
} else if (hyundai_hybrid_gas_signal) {
static RxCheck torque_camera_hybrid_alt[] = {
static const RxCheck torque_camera_hybrid_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
static RxCheck torque_camera_hybrid_std[] = {
_Static_assert((sizeof(torque_camera_hybrid_alt) / sizeof(torque_camera_hybrid_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_camera_hybrid_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
_Static_assert((sizeof(torque_camera_hybrid_std) / sizeof(torque_camera_hybrid_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_camera_hybrid_alt : torque_camera_hybrid_std;
} else {
static RxCheck torque_camera_ice_alt[] = {
static const RxCheck torque_camera_ice_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
static RxCheck torque_camera_ice_std[] = {
_Static_assert((sizeof(torque_camera_ice_alt) / sizeof(torque_camera_ice_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_camera_ice_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
_Static_assert((sizeof(torque_camera_ice_std) / sizeof(torque_camera_ice_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_camera_ice_alt : torque_camera_ice_std;
}
} else {
if (hyundai_ev_gas_signal) {
static RxCheck torque_radar_ev_alt[] = {
static const RxCheck torque_radar_ev_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
static RxCheck torque_radar_ev_std[] = {
_Static_assert((sizeof(torque_radar_ev_alt) / sizeof(torque_radar_ev_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_radar_ev_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
_Static_assert((sizeof(torque_radar_ev_std) / sizeof(torque_radar_ev_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_radar_ev_alt : torque_radar_ev_std;
} else if (hyundai_hybrid_gas_signal) {
static RxCheck torque_radar_hybrid_alt[] = {
static const RxCheck torque_radar_hybrid_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
static RxCheck torque_radar_hybrid_std[] = {
_Static_assert((sizeof(torque_radar_hybrid_alt) / sizeof(torque_radar_hybrid_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_radar_hybrid_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
_Static_assert((sizeof(torque_radar_hybrid_std) / sizeof(torque_radar_hybrid_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_radar_hybrid_alt : torque_radar_hybrid_std;
} else {
static RxCheck torque_radar_ice_alt[] = {
static const RxCheck torque_radar_ice_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
static RxCheck torque_radar_ice_std[] = {
_Static_assert((sizeof(torque_radar_ice_alt) / sizeof(torque_radar_ice_alt[0])) == 6U, "Banked RX template size");
static const RxCheck torque_radar_ice_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
_Static_assert((sizeof(torque_radar_ice_std) / sizeof(torque_radar_ice_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? torque_radar_ice_alt : torque_radar_ice_std;
}
}
ret.rx_checks = selected;
ret.rx_checks_len = 6;
for (int i = 0; i < ret.rx_checks_len; i++) {
banked_rx_workspace[i] = selected[i];
}
ret.rx_checks = banked_rx_workspace;
}
if (angle_aol_requested && hyundai_canfd_angle_steering && !hyundai_longitudinal) {
static CanMsg independent_tx_msgs[64];
const bool bounded = hyundai_canfd_angle_aol_capacity(&ret);
if (bounded) {
RxCheck *selected = NULL;
const RxCheck *selected = NULL;
if (hyundai_canfd_lka_steer_msg) {
if (hyundai_ev_gas_signal) {
static RxCheck angle_hda2_ev_alt[] = {
static const RxCheck angle_hda2_ev_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(1, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
static RxCheck angle_hda2_ev_std[] = {
_Static_assert((sizeof(angle_hda2_ev_alt) / sizeof(angle_hda2_ev_alt[0])) == 6U, "Banked RX template size");
static const RxCheck angle_hda2_ev_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(1, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
_Static_assert((sizeof(angle_hda2_ev_std) / sizeof(angle_hda2_ev_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? angle_hda2_ev_alt : angle_hda2_ev_std;
}
else if (hyundai_hybrid_gas_signal) {
static RxCheck angle_hda2_hybrid_alt[] = {
static const RxCheck angle_hda2_hybrid_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(1, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
{.msg = {{0x70, 1, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
static RxCheck angle_hda2_hybrid_std[] = {
_Static_assert((sizeof(angle_hda2_hybrid_alt) / sizeof(angle_hda2_hybrid_alt[0])) == 7U, "Banked RX template size");
static const RxCheck angle_hda2_hybrid_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(1, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
{.msg = {{0x70, 1, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
_Static_assert((sizeof(angle_hda2_hybrid_std) / sizeof(angle_hda2_hybrid_std[0])) == 7U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? angle_hda2_hybrid_alt : angle_hda2_hybrid_std;
}
else {
static RxCheck angle_hda2_ice_alt[] = {
static const RxCheck angle_hda2_ice_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(1, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
{.msg = {{0x70, 1, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
static RxCheck angle_hda2_ice_std[] = {
_Static_assert((sizeof(angle_hda2_ice_alt) / sizeof(angle_hda2_ice_alt[0])) == 7U, "Banked RX template size");
static const RxCheck angle_hda2_ice_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(1, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
{.msg = {{0x70, 1, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
_Static_assert((sizeof(angle_hda2_ice_std) / sizeof(angle_hda2_ice_std[0])) == 7U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? angle_hda2_ice_alt : angle_hda2_ice_std;
}
}
else {
if (hyundai_ev_gas_signal) {
static RxCheck angle_camera_ev_alt[] = {
static const RxCheck angle_camera_ev_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
static RxCheck angle_camera_ev_std[] = {
_Static_assert((sizeof(angle_camera_ev_alt) / sizeof(angle_camera_ev_alt[0])) == 6U, "Banked RX template size");
static const RxCheck angle_camera_ev_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x35)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
_Static_assert((sizeof(angle_camera_ev_std) / sizeof(angle_camera_ev_std[0])) == 6U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? angle_camera_ev_alt : angle_camera_ev_std;
}
else if (hyundai_hybrid_gas_signal) {
static RxCheck angle_camera_hybrid_alt[] = {
static const RxCheck angle_camera_hybrid_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
{.msg = {{0x70, 0, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
static RxCheck angle_camera_hybrid_std[] = {
_Static_assert((sizeof(angle_camera_hybrid_alt) / sizeof(angle_camera_hybrid_alt[0])) == 7U, "Banked RX template size");
static const RxCheck angle_camera_hybrid_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x105)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
{.msg = {{0x70, 0, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
_Static_assert((sizeof(angle_camera_hybrid_std) / sizeof(angle_camera_hybrid_std[0])) == 7U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? angle_camera_hybrid_alt : angle_camera_hybrid_std;
}
else {
static RxCheck angle_camera_ice_alt[] = {
static const RxCheck angle_camera_ice_alt[] = {
HYUNDAI_CANFD_BANKED_ANGLE_ALT_RX_CHECKS(0, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
{.msg = {{0x70, 0, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
static RxCheck angle_camera_ice_std[] = {
_Static_assert((sizeof(angle_camera_ice_alt) / sizeof(angle_camera_ice_alt[0])) == 7U, "Banked RX template size");
static const RxCheck angle_camera_ice_std[] = {
HYUNDAI_CANFD_BANKED_ANGLE_STD_RX_CHECKS(0, 0x100)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
{.msg = {{0x70, 0, 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, {0}, {0}}},
};
_Static_assert((sizeof(angle_camera_ice_std) / sizeof(angle_camera_ice_std[0])) == 7U, "Banked RX template size");
selected = hyundai_canfd_alt_buttons ? angle_camera_ice_alt : angle_camera_ice_std;
}
}
ret.rx_checks = selected;
ret.rx_checks_len = hyundai_ev_gas_signal ? 6 : 7;
for (int i = 0; i < ret.rx_checks_len; i++) {
banked_rx_workspace[i] = selected[i];
}
ret.rx_checks = banked_rx_workspace;
for (int i = 0; i < ret.tx_msgs_len; i++) {
independent_tx_msgs[i] = ret.tx_msgs[i];
const unsigned int addr = independent_tx_msgs[i].addr;
@@ -0,0 +1,132 @@
"""Banked CAN-FD RX definitions and status must survive warm profile switches."""
import unittest
from opendbc.safety.tests.libsafety import libsafety_py
libsafety_py.ffi.cdef('extern safety_config current_safety_config;', override=True)
# word, powertrain bus, fuel address, SCC bus, alternate buttons, separate gear
PROFILES = (
(0x0810, 1, 0x100, 1, False, False),
(0x0812, 1, 0x105, 1, False, False),
(0x2830, 1, 0x100, 1, True, False),
(0x2832, 1, 0x105, 1, True, False),
(0x0808, 0, 0x100, 2, False, False),
(0x0809, 0, 0x035, 2, False, False),
(0x080A, 0, 0x105, 2, False, False),
(0x0828, 0, 0x100, 2, True, False),
(0x0829, 0, 0x035, 2, True, False),
(0x082A, 0, 0x105, 2, True, False),
(0x0800, 0, 0x100, 0, False, False),
(0x0801, 0, 0x035, 0, False, False),
(0x0802, 0, 0x105, 0, False, False),
(0x0820, 0, 0x100, 0, True, False),
(0x0821, 0, 0x035, 0, True, False),
(0x0822, 0, 0x105, 0, True, False),
(0x4010, 1, 0x100, 1, False, True),
(0x4412, 1, 0x105, 1, False, True),
(0x4811, 1, 0x035, 1, False, False),
(0x4008, 0, 0x100, 2, False, True),
(0x440A, 0, 0x105, 2, False, True),
(0x4809, 0, 0x035, 2, False, False),
(0x4028, 0, 0x100, 2, True, True),
(0x442A, 0, 0x105, 2, True, True),
(0x4829, 0, 0x035, 2, True, False),
)
PROFILE_BY_WORD = {profile[0]: profile for profile in PROFILES}
def _message(msg):
return (msg.addr, msg.bus, msg.len, msg.frequency, msg.ignore_checksum,
msg.ignore_counter, msg.max_counter, msg.ignore_quality_flag)
def _status(status):
return (status.msg_seen, status.index, status.valid_checksum, status.wrong_counters,
status.valid_quality_flag, status.last_counter, status.last_timestamp, status.lagging)
def _assert_profile(safety, profile):
_, bus, fuel, scc_bus, alternate, gear = profile
expected = [
(fuel, bus, 32, 100, False, False, 255, True),
(0x175, bus, 24, 50, False, False, 255, True),
(0x0A0, bus, 24, 100, False, False, 255, True),
(0x0EA, bus, 24, 100, False, False, 255, True),
(0x1AA, bus, 16, 50, True, False, 255, True) if alternate else
(0x1CF, bus, 8, 50, True, False, 15, True),
(0x1A0, scc_bus, 32, 50, False, False, 255, True),
]
if gear:
expected.append((0x70, bus, 32, 100, False, False, 255, True))
config = safety.current_safety_config
assert config.rx_checks_len == len(expected)
assert config.rx_checks != libsafety_py.ffi.NULL
for index, message in enumerate(expected):
check = config.rx_checks[index]
assert _message(check.msg[0]) == message
assert _message(check.msg[1]) == (0, 0, 0, 0, False, False, 0, False)
assert _message(check.msg[2]) == (0, 0, 0, 0, False, False, 0, False)
assert _status(check.status) == (False, 0, False, 0, False, 0, 0, False)
def _dirty_status(safety):
config = safety.current_safety_config
for index in range(config.rx_checks_len):
status = config.rx_checks[index].status
# Valid C values dirty every field, without relying on structure padding.
status.msg_seen = True
status.index = 2
status.valid_checksum = True
status.wrong_counters = 5
status.valid_quality_flag = True
status.last_counter = 7
status.last_timestamp = 123_456 + index
status.lagging = True
assert _status(status) == (True, 2, True, 5, True, 7, 123_456 + index, True)
def _select(safety, word):
safety.set_alternative_experience(32)
assert safety.set_safety_hooks(safety.SAFETY_HYUNDAI_CANFD, word) == 0
# Do not call init_tests: the production mode-init path must reset the status.
_assert_profile(safety, PROFILE_BY_WORD[word])
class TestHyundaiBankedRxWorkspace(unittest.TestCase):
RELEASE = False
@classmethod
def setUpClass(cls):
# Separate real native libraries exercise both build policies.
cls.safety = libsafety_py.ffi.dlopen(libsafety_py._build_libsafety(release=cls.RELEASE))
@classmethod
def tearDownClass(cls):
cls.safety.set_alternative_experience(0)
assert cls.safety.set_safety_hooks(cls.safety.SAFETY_SILENT, 0) == 0
def test_same_mode_reinitialization_restores_every_status_field(self):
for profile in PROFILES:
with self.subTest(word=hex(profile[0])):
_select(self.safety, profile[0])
_dirty_status(self.safety)
_select(self.safety, profile[0])
def test_seven_six_seven_switches_replace_definitions_and_status(self):
for words in ((0x4412, 0x4829, 0x4008, 0x0810, 0x442A),
(0x4028, 0x2832, 0x4010, 0x0801, 0x440A),
(0x4412, 0x0820, 0x442A, 0x4811, 0x4010)):
with self.subTest(words=tuple(hex(word) for word in words)):
for word in words:
_select(self.safety, word)
_dirty_status(self.safety)
class TestHyundaiBankedRxWorkspaceRelease(TestHyundaiBankedRxWorkspace):
RELEASE = True
if __name__ == '__main__':
unittest.main()
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-fae3f5cc-Pa5919516-DEBUG";
const uint8_t gitversion[29] = "DEV-b3b96ade-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 @@
DEV-fae3f5cc-Pa5919516-DEBUG
DEV-b3b96ade-Pa5919516-DEBUG
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "f1566fdd59080d87bfd9d41359e007a06fc87b2794d44baf38797707aa07aae4", "schema_version": 1}
{"protected_inventory_sha256": "ec0401c5357c5677794ac4bfa02c5e1460253602b010d91d177b7df180cd6c24", "schema_version": 1}