mirror of
https://github.com/infiniteCable2/panda.git
synced 2026-02-18 09:13:52 +08:00
* alternative experience * safety init * fix * more update * not really * misra * Add Custom MIT License (#38) * brake check was not handled * revert * alt -> lkas * explicit checks * support toyota and ford * rename * hyundai can-fd support * only allow lkas if enabled * hyundai: main button handling * revert * hyundai: main button heartbeat * add logging for controls allowed lateral * fix panda safety * ford btn * toyota btn * fca btn * honda btn * mads safety tests * more tests * safety misra * safety mutation * misra * mutation experiment * fix * ford test main button * ford test lkas button * more ford test * hyundai lkas and main * more ford * hyundai canfd * rename * rename * cleaner * more fixes * more hyundai tests * no longer needed * thanks for tests! * more tests for lat * more explicit * make sure to reset * try this out * probably needed * move * misra * not needed * move to safety_mads * not really needed * remove * MADS: Refactor MADS safety with improved state management (pull request #46) Refactor MADS safety with improved state management This commit introduces a major refactoring of the MADS safety module, improving state management and control flow. Key changes include: Core Changes: - Introduced a MADSState struct to centralize state management - Removed global state variables in favor of structured state - Implemented button transition handling with explicit state tracking (PRESSED/RELEASED/NO_CHANGE) - Added state flags for button availability detection - Simplified lateral control permission logic Button Handling: - Separated main button and LKAS button state tracking - Added independent engagement states for each button - Improved button press detection across multiple platforms - Added support for main and LKAS buttons on Hyundai platforms - Modified ACC main state handling Testing: - Added comprehensive test coverage for MADS state transitions - Added new MADS-specific test base class for consistent testing across platforms - Added mutation testing for state management - Extended timeout for mutation tests from 5 to 8 minutes - Added extensive button press validation tests - Enhanced debugging output in replay drive tests The refactored code provides a more organized implementation of MADS safety features while maintaining compatibility with existing safety checks. * adding note * adding ford (WIP) * adding honda (WIP) * adding toyota (WIP) * adding chrysler (WIP) * Standardize Button State Handling Across Platforms Refactor button state handling by replacing integer constants with an enumerated `ButtonState` type and updating logic to improve readability and maintainability. This change affects button press detection in Ford, Honda, Hyundai, and Toyota safety modules and aligns them with a unified MADS button state approach. Enums provide a clearer understanding of button states and transitions, facilitating easier maintenance and future enhancements. * Disable LKAS button press logic in Honda and Toyota safety. The code for processing LKAS button presses has been commented out in both Honda and Toyota safety implementations. This change aims to investigate or temporarily halt the button press effects without removing the logic altogether. It will be important to test for any impacts this may have on vehicle control functionality. * Remove commented out code in toyota_rx_hook function This commit cleans up the toyota_rx_hook function by removing unnecessary commented-out code that checks for LKAS button presses on bus 2. This helps improve code readability and maintainability without altering the existing functionality. * GM, mazda, nissan, subaru (global & preglobal) * Honda LKAS * Revert "Remove commented out code in toyota_rx_hook function" This reverts commit d6b012c01a08118d91fad56c9f6ac2f92b671968. * Toyota, Subaru Global LKAS * nissan fix * gm fix * use speed msg to force rx * im bored * misra * subaru/toyota/honda * nope * attempt * go through all buttons * try nissan * more nissan * nissan tests passed! * subaru lkas test (not sure why it's not passing 2 and 3 values) * Improved code organization in safety_subaru.h and test_subaru.py This commit includes a minor restructuring in safety_subaru.h and test_subaru.py for better readability and flow. The condition check in safety_subaru.h for lkas_hud now has explicit parentheses. With regard to test_subaru.py, an unnecessary import was removed, and the sequence of steps in the test was reordered - now enabling mads and cleaning up mads_states happens before each subtest. * Refactor tests to use _speed_msg instead of _user_brake_msg. Updated the MADS safety tests to utilize the _speed_msg(0) function call in place of _user_brake_msg(False). * Reworking the tests a little for clarity * disabling lkas again on toyota temporarily * fix mads condition to engage * hyundai and honda good with new tests * Redoing more tests * update for safety tick ensuring mads control is exited while lagging * Updating tests for toyota * cleaning up tests on hkg * commenting out temp_debug for future use * revert * constants * cleanup * format! * match yota * Apply suggestions from code review * force * explicit checks * revert --------- Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
401 lines
13 KiB
C
401 lines
13 KiB
C
extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used
|
|
|
|
// Prototypes
|
|
void set_safety_mode(uint16_t mode, uint16_t param);
|
|
bool is_car_safety_mode(uint16_t mode);
|
|
|
|
static int get_health_pkt(void *dat) {
|
|
COMPILE_TIME_ASSERT(sizeof(struct health_t) <= USBPACKET_MAX_SIZE);
|
|
struct health_t * health = (struct health_t*)dat;
|
|
|
|
health->uptime_pkt = uptime_cnt;
|
|
health->voltage_pkt = current_board->read_voltage_mV();
|
|
health->current_pkt = current_board->read_current_mA();
|
|
|
|
// Use the GPIO pin to determine ignition or use a CAN based logic
|
|
health->ignition_line_pkt = (uint8_t)(current_board->check_ignition());
|
|
health->ignition_can_pkt = ignition_can;
|
|
|
|
health->controls_allowed_pkt = controls_allowed;
|
|
health->controls_allowed_lat_pkt = mads_is_lateral_control_allowed_by_mads();
|
|
health->safety_tx_blocked_pkt = safety_tx_blocked;
|
|
health->safety_rx_invalid_pkt = safety_rx_invalid;
|
|
health->tx_buffer_overflow_pkt = tx_buffer_overflow;
|
|
health->rx_buffer_overflow_pkt = rx_buffer_overflow;
|
|
health->car_harness_status_pkt = harness.status;
|
|
health->safety_mode_pkt = (uint8_t)(current_safety_mode);
|
|
health->safety_param_pkt = current_safety_param;
|
|
health->alternative_experience_pkt = alternative_experience;
|
|
health->power_save_enabled_pkt = power_save_status == POWER_SAVE_STATUS_ENABLED;
|
|
health->heartbeat_lost_pkt = heartbeat_lost;
|
|
health->safety_rx_checks_invalid_pkt = safety_rx_checks_invalid;
|
|
|
|
health->spi_checksum_error_count_pkt = spi_checksum_error_count;
|
|
|
|
health->fault_status_pkt = fault_status;
|
|
health->faults_pkt = faults;
|
|
|
|
health->interrupt_load_pkt = interrupt_load;
|
|
|
|
health->fan_power = fan_state.power;
|
|
health->fan_stall_count = fan_state.total_stall_count;
|
|
|
|
health->sbu1_voltage_mV = harness.sbu1_voltage_mV;
|
|
health->sbu2_voltage_mV = harness.sbu2_voltage_mV;
|
|
|
|
health->som_reset_triggered = bootkick_reset_triggered;
|
|
|
|
return sizeof(*health);
|
|
}
|
|
|
|
// send on serial, first byte to select the ring
|
|
void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
|
|
uart_ring *ur = get_ring_by_number(data[0]);
|
|
if ((len != 0U) && (ur != NULL)) {
|
|
if ((data[0] < 2U) || (data[0] >= 4U)) {
|
|
for (uint32_t i = 1; i < len; i++) {
|
|
while (!put_char(ur, data[i])) {
|
|
// wait
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
|
unsigned int resp_len = 0;
|
|
uart_ring *ur = NULL;
|
|
uint32_t time;
|
|
|
|
#ifdef DEBUG_COMMS
|
|
print("raw control request: "); hexdump(req, sizeof(ControlPacket_t)); print("\n");
|
|
print("- request "); puth(req->request); print("\n");
|
|
print("- param1 "); puth(req->param1); print("\n");
|
|
print("- param2 "); puth(req->param2); print("\n");
|
|
#endif
|
|
|
|
switch (req->request) {
|
|
// **** 0xa8: get microsecond timer
|
|
case 0xa8:
|
|
time = microsecond_timer_get();
|
|
resp[0] = (time & 0x000000FFU);
|
|
resp[1] = ((time & 0x0000FF00U) >> 8U);
|
|
resp[2] = ((time & 0x00FF0000U) >> 16U);
|
|
resp[3] = ((time & 0xFF000000U) >> 24U);
|
|
resp_len = 4U;
|
|
break;
|
|
// **** 0xb0: set IR power
|
|
case 0xb0:
|
|
current_board->set_ir_power(req->param1);
|
|
break;
|
|
// **** 0xb1: set fan power
|
|
case 0xb1:
|
|
fan_set_power(req->param1);
|
|
break;
|
|
// **** 0xb2: get fan rpm
|
|
case 0xb2:
|
|
resp[0] = (fan_state.rpm & 0x00FFU);
|
|
resp[1] = ((fan_state.rpm & 0xFF00U) >> 8U);
|
|
resp_len = 2;
|
|
break;
|
|
// **** 0xc0: reset communications
|
|
case 0xc0:
|
|
comms_can_reset();
|
|
break;
|
|
// **** 0xc1: get hardware type
|
|
case 0xc1:
|
|
resp[0] = hw_type;
|
|
resp_len = 1;
|
|
break;
|
|
// **** 0xc2: CAN health stats
|
|
case 0xc2:
|
|
COMPILE_TIME_ASSERT(sizeof(can_health_t) <= USBPACKET_MAX_SIZE);
|
|
if (req->param1 < 3U) {
|
|
update_can_health_pkt(req->param1, 0U);
|
|
can_health[req->param1].can_speed = (bus_config[req->param1].can_speed / 10U);
|
|
can_health[req->param1].can_data_speed = (bus_config[req->param1].can_data_speed / 10U);
|
|
can_health[req->param1].canfd_enabled = bus_config[req->param1].canfd_enabled;
|
|
can_health[req->param1].brs_enabled = bus_config[req->param1].brs_enabled;
|
|
can_health[req->param1].canfd_non_iso = bus_config[req->param1].canfd_non_iso;
|
|
resp_len = sizeof(can_health[req->param1]);
|
|
(void)memcpy(resp, (uint8_t*)(&can_health[req->param1]), resp_len);
|
|
}
|
|
break;
|
|
// **** 0xc3: fetch MCU UID
|
|
case 0xc3:
|
|
(void)memcpy(resp, ((uint8_t *)UID_BASE), 12);
|
|
resp_len = 12;
|
|
break;
|
|
// **** 0xc4: get interrupt call rate
|
|
case 0xc4:
|
|
if (req->param1 < NUM_INTERRUPTS) {
|
|
uint32_t load = interrupts[req->param1].call_rate;
|
|
resp[0] = (load & 0x000000FFU);
|
|
resp[1] = ((load & 0x0000FF00U) >> 8U);
|
|
resp[2] = ((load & 0x00FF0000U) >> 16U);
|
|
resp[3] = ((load & 0xFF000000U) >> 24U);
|
|
resp_len = 4U;
|
|
}
|
|
break;
|
|
// **** 0xc5: DEBUG: drive relay
|
|
case 0xc5:
|
|
set_intercept_relay((req->param1 & 0x1U), (req->param1 & 0x2U));
|
|
break;
|
|
// **** 0xc6: DEBUG: read SOM GPIO
|
|
case 0xc6:
|
|
resp[0] = current_board->read_som_gpio();
|
|
resp_len = 1;
|
|
break;
|
|
// **** 0xd0: fetch serial (aka the provisioned dongle ID)
|
|
case 0xd0:
|
|
// addresses are OTP
|
|
if (req->param1 == 1U) {
|
|
(void)memcpy(resp, (uint8_t *)DEVICE_SERIAL_NUMBER_ADDRESS, 0x10);
|
|
resp_len = 0x10;
|
|
} else {
|
|
get_provision_chunk(resp);
|
|
resp_len = PROVISION_CHUNK_LEN;
|
|
}
|
|
break;
|
|
// **** 0xd1: enter bootloader mode
|
|
case 0xd1:
|
|
// this allows reflashing of the bootstub
|
|
switch (req->param1) {
|
|
case 0:
|
|
// only allow bootloader entry on debug builds
|
|
#ifdef ALLOW_DEBUG
|
|
print("-> entering bootloader\n");
|
|
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
|
|
NVIC_SystemReset();
|
|
#endif
|
|
break;
|
|
case 1:
|
|
print("-> entering softloader\n");
|
|
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
|
|
NVIC_SystemReset();
|
|
break;
|
|
default:
|
|
print("Bootloader mode invalid\n");
|
|
break;
|
|
}
|
|
break;
|
|
// **** 0xd2: get health packet
|
|
case 0xd2:
|
|
resp_len = get_health_pkt(resp);
|
|
break;
|
|
// **** 0xd3: get first 64 bytes of signature
|
|
case 0xd3:
|
|
{
|
|
resp_len = 64;
|
|
char * code = (char*)_app_start;
|
|
int code_len = _app_start[0];
|
|
(void)memcpy(resp, &code[code_len], resp_len);
|
|
}
|
|
break;
|
|
// **** 0xd4: get second 64 bytes of signature
|
|
case 0xd4:
|
|
{
|
|
resp_len = 64;
|
|
char * code = (char*)_app_start;
|
|
int code_len = _app_start[0];
|
|
(void)memcpy(resp, &code[code_len + 64], resp_len);
|
|
}
|
|
break;
|
|
// **** 0xd6: get version
|
|
case 0xd6:
|
|
COMPILE_TIME_ASSERT(sizeof(gitversion) <= USBPACKET_MAX_SIZE);
|
|
(void)memcpy(resp, gitversion, sizeof(gitversion));
|
|
resp_len = sizeof(gitversion) - 1U;
|
|
break;
|
|
// **** 0xd8: reset ST
|
|
case 0xd8:
|
|
NVIC_SystemReset();
|
|
break;
|
|
// **** 0xdb: set OBD CAN multiplexing mode
|
|
case 0xdb:
|
|
if (current_board->has_obd) {
|
|
if (req->param1 == 1U) {
|
|
// Enable OBD CAN
|
|
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
|
|
} else {
|
|
// Disable OBD CAN
|
|
current_board->set_can_mode(CAN_MODE_NORMAL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// **** 0xdc: set safety mode
|
|
case 0xdc:
|
|
set_safety_mode(req->param1, (uint16_t)req->param2);
|
|
break;
|
|
// **** 0xdd: get healthpacket and CANPacket versions
|
|
case 0xdd:
|
|
resp[0] = HEALTH_PACKET_VERSION;
|
|
resp[1] = CAN_PACKET_VERSION;
|
|
resp[2] = CAN_HEALTH_PACKET_VERSION;
|
|
resp_len = 3;
|
|
break;
|
|
// **** 0xde: set can bitrate
|
|
case 0xde:
|
|
if ((req->param1 < PANDA_BUS_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) {
|
|
bus_config[req->param1].can_speed = req->param2;
|
|
bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1));
|
|
UNUSED(ret);
|
|
}
|
|
break;
|
|
// **** 0xdf: set alternative experience
|
|
case 0xdf:
|
|
// you can only set this if you are in a non car safety mode
|
|
if (!is_car_safety_mode(current_safety_mode)) {
|
|
alternative_experience = req->param1;
|
|
bool mads_enabled = (alternative_experience & ALT_EXP_ENABLE_MADS) != 0;
|
|
bool disengage_lateral_on_brake = !(alternative_experience & ALT_EXP_DISABLE_DISENGAGE_LATERAL_ON_BRAKE);
|
|
mads_set_system_state(mads_enabled, disengage_lateral_on_brake);
|
|
}
|
|
break;
|
|
// **** 0xe0: uart read
|
|
case 0xe0:
|
|
ur = get_ring_by_number(req->param1);
|
|
if (!ur) {
|
|
break;
|
|
}
|
|
|
|
// read
|
|
uint16_t req_length = MIN(req->length, USBPACKET_MAX_SIZE);
|
|
while ((resp_len < req_length) &&
|
|
get_char(ur, (char*)&resp[resp_len])) {
|
|
++resp_len;
|
|
}
|
|
break;
|
|
// **** 0xe1: uart set baud rate
|
|
case 0xe1:
|
|
ur = get_ring_by_number(req->param1);
|
|
if (!ur) {
|
|
break;
|
|
}
|
|
uart_set_baud(ur->uart, req->param2);
|
|
break;
|
|
// **** 0xe2: uart set parity
|
|
case 0xe2:
|
|
ur = get_ring_by_number(req->param1);
|
|
if (!ur) {
|
|
break;
|
|
}
|
|
switch (req->param2) {
|
|
case 0:
|
|
// disable parity, 8-bit
|
|
ur->uart->CR1 &= ~(USART_CR1_PCE | USART_CR1_M);
|
|
break;
|
|
case 1:
|
|
// even parity, 9-bit
|
|
ur->uart->CR1 &= ~USART_CR1_PS;
|
|
ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M;
|
|
break;
|
|
case 2:
|
|
// odd parity, 9-bit
|
|
ur->uart->CR1 |= USART_CR1_PS;
|
|
ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
// **** 0xe4: uart set baud rate extended
|
|
case 0xe4:
|
|
ur = get_ring_by_number(req->param1);
|
|
if (!ur) {
|
|
break;
|
|
}
|
|
uart_set_baud(ur->uart, (int)req->param2*300);
|
|
break;
|
|
// **** 0xe5: set CAN loopback (for testing)
|
|
case 0xe5:
|
|
can_loopback = req->param1 > 0U;
|
|
can_init_all();
|
|
break;
|
|
// **** 0xe6: set custom clock source period
|
|
case 0xe6:
|
|
clock_source_set_period(req->param1);
|
|
break;
|
|
// **** 0xe7: set power save state
|
|
case 0xe7:
|
|
set_power_save_state(req->param1);
|
|
break;
|
|
// **** 0xe8: set can-fd auto swithing mode
|
|
case 0xe8:
|
|
bus_config[req->param1].canfd_auto = req->param2 > 0U;
|
|
break;
|
|
// **** 0xf1: Clear CAN ring buffer.
|
|
case 0xf1:
|
|
if (req->param1 == 0xFFFFU) {
|
|
print("Clearing CAN Rx queue\n");
|
|
can_clear(&can_rx_q);
|
|
} else if (req->param1 < PANDA_BUS_CNT) {
|
|
print("Clearing CAN Tx queue\n");
|
|
can_clear(can_queues[req->param1]);
|
|
} else {
|
|
print("Clearing CAN CAN ring buffer failed: wrong bus number\n");
|
|
}
|
|
break;
|
|
// **** 0xf2: Clear UART ring buffer.
|
|
case 0xf2:
|
|
{
|
|
uart_ring * rb = get_ring_by_number(req->param1);
|
|
if (rb != NULL) {
|
|
print("Clearing UART queue.\n");
|
|
clear_uart_buff(rb);
|
|
}
|
|
break;
|
|
}
|
|
// **** 0xf3: Heartbeat. Resets heartbeat counter.
|
|
case 0xf3:
|
|
{
|
|
heartbeat_counter = 0U;
|
|
heartbeat_lost = false;
|
|
heartbeat_disabled = false;
|
|
heartbeat_engaged = (req->param1 == 1U);
|
|
break;
|
|
}
|
|
// **** 0xf6: set siren enabled
|
|
case 0xf6:
|
|
siren_enabled = (req->param1 != 0U);
|
|
break;
|
|
// **** 0xf7: set green led enabled
|
|
case 0xf7:
|
|
green_led_enabled = (req->param1 != 0U);
|
|
break;
|
|
// **** 0xf8: disable heartbeat checks
|
|
case 0xf8:
|
|
if (!is_car_safety_mode(current_safety_mode)) {
|
|
heartbeat_disabled = true;
|
|
}
|
|
break;
|
|
// **** 0xf9: set CAN FD data bitrate
|
|
case 0xf9:
|
|
if ((req->param1 < PANDA_CAN_CNT) &&
|
|
current_board->has_canfd &&
|
|
is_speed_valid(req->param2, data_speeds, sizeof(data_speeds)/sizeof(data_speeds[0]))) {
|
|
bus_config[req->param1].can_data_speed = req->param2;
|
|
bus_config[req->param1].canfd_enabled = (req->param2 >= bus_config[req->param1].can_speed);
|
|
bus_config[req->param1].brs_enabled = (req->param2 > bus_config[req->param1].can_speed);
|
|
bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1));
|
|
UNUSED(ret);
|
|
}
|
|
break;
|
|
// **** 0xfc: set CAN FD non-ISO mode
|
|
case 0xfc:
|
|
if ((req->param1 < PANDA_CAN_CNT) && current_board->has_canfd) {
|
|
bus_config[req->param1].canfd_non_iso = (req->param2 != 0U);
|
|
bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1));
|
|
UNUSED(ret);
|
|
}
|
|
break;
|
|
default:
|
|
print("NO HANDLER ");
|
|
puth(req->request);
|
|
print("\n");
|
|
break;
|
|
}
|
|
return resp_len;
|
|
}
|