diff --git a/board/drivers/gmlan_alt.h b/board/drivers/gmlan_alt.h index 6d4ba12b8c1069..2f2e568055b02f 100644 --- a/board/drivers/gmlan_alt.h +++ b/board/drivers/gmlan_alt.h @@ -122,7 +122,12 @@ int get_bit_message(char *out, CAN_FIFOMailBox_TypeDef *to_bang) { return len; } +void TIM4_IRQ_Handler(void); + void setup_timer4(void) { + // register interrupt + REGISTER_INTERRUPT(TIM4_IRQn, TIM4_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN) + // setup register_set(&(TIM4->PSC), (48-1), 0xFFFFU); // Tick on 1 us register_set(&(TIM4->CR1), TIM_CR1_CEN, 0x3FU); // Enable @@ -236,7 +241,6 @@ void TIM4_IRQ_Handler(void) { gmlan_sendmax = -1; // exit } } - TIM4->SR = 0; } else if (gmlan_alt_mode == GPIO_SWITCH) { if ((TIM4->SR & TIM_SR_UIF) && (gmlan_switch_below_timeout != -1)) { if ((can_timeout_counter == 0) && gmlan_switch_timeout_enable) { @@ -259,10 +263,10 @@ void TIM4_IRQ_Handler(void) { } } } - TIM4->SR = 0; } else { - puts("invalid gmlan_alt_mode\n"); + // Invalid GMLAN mode. Do not put a print statement here, way too fast to keep up with } + TIM4->SR = 0; } bool bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) { @@ -280,7 +284,6 @@ bool bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) { set_gpio_mode(GPIOB, 13, MODE_OUTPUT); // 33kbps - REGISTER_INTERRUPT(TIM4_IRQn, TIM4_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN) setup_timer4(); } return gmlan_send_ok; diff --git a/board/main.c b/board/main.c index a758bf70520be8..8bc4ac78f1b43b 100644 --- a/board/main.c +++ b/board/main.c @@ -294,19 +294,11 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) break; // **** 0xb0: set IR power case 0xb0: - if(power_save_status == POWER_SAVE_STATUS_DISABLED){ - current_board->set_ir_power(setup->b.wValue.w); - } else { - puts("Setting IR power not allowed in power saving mode\n"); - } + current_board->set_ir_power(setup->b.wValue.w); break; // **** 0xb1: set fan power case 0xb1: - if(power_save_status == POWER_SAVE_STATUS_DISABLED){ - current_board->set_fan_power(setup->b.wValue.w); - } else { - puts("Setting fan power not allowed in power saving mode\n"); - } + current_board->set_fan_power(setup->b.wValue.w); break; // **** 0xb2: get fan rpm case 0xb2: @@ -716,6 +708,10 @@ void TIM1_BRK_TIM9_IRQ_Handler(void) { if (power_save_status != POWER_SAVE_STATUS_ENABLED) { set_power_save_state(POWER_SAVE_STATUS_ENABLED); } + + // Also disable fan and IR when the heartbeat goes missing + current_board->set_fan_power(0U); + current_board->set_ir_power(0U); } // enter CDP mode when car starts to ensure we are charging a turned off EON diff --git a/board/power_saving.h b/board/power_saving.h index 3ee2170d71cf6a..f7e42371aa2188 100644 --- a/board/power_saving.h +++ b/board/power_saving.h @@ -49,10 +49,9 @@ void set_power_save_state(int state) { set_gpio_output(GPIOA, 14, enable); } - // Switch off IR and fan when in power saving + // Switch off IR when in power saving if(!enable){ current_board->set_ir_power(0U); - current_board->set_fan_power(0U); } power_save_status = state; diff --git a/board/safety.h b/board/safety.h index 4588eece653b03..7fd057b5249837 100644 --- a/board/safety.h +++ b/board/safety.h @@ -148,20 +148,20 @@ bool addr_safety_check(CAN_FIFOMailBox_TypeDef *to_push, if (index != -1) { // checksum check - if ((get_checksum != NULL) && (compute_checksum != NULL)) { - if (rx_checks[index].check_checksum) { - uint8_t checksum = get_checksum(to_push); - uint8_t checksum_comp = compute_checksum(to_push); - rx_checks[index].valid_checksum = checksum_comp == checksum; - } + if ((get_checksum != NULL) && (compute_checksum != NULL) && rx_checks[index].check_checksum) { + uint8_t checksum = get_checksum(to_push); + uint8_t checksum_comp = compute_checksum(to_push); + rx_checks[index].valid_checksum = checksum_comp == checksum; + } else { + rx_checks[index].valid_checksum = true; } - // counter check - if (get_counter != NULL) { - if (rx_checks[index].max_counter > 0U) { - uint8_t counter = get_counter(to_push); - update_counter(rx_checks, index, counter); - } + // counter check (max_counter == 0 means skip check) + if ((get_counter != NULL) && (rx_checks[index].max_counter > 0U)) { + uint8_t counter = get_counter(to_push); + update_counter(rx_checks, index, counter); + } else { + rx_checks[index].wrong_counters = 0U; } } return is_msg_valid(rx_checks, index); diff --git a/board/safety/safety_chrysler.h b/board/safety/safety_chrysler.h index 8c201a3bb40cad..293839b7f62d98 100644 --- a/board/safety/safety_chrysler.h +++ b/board/safety/safety_chrysler.h @@ -20,36 +20,42 @@ uint32_t chrysler_ts_last = 0; struct sample_t chrysler_torque_meas; // last few torques measured static int chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - // Measured eps torque - if (addr == 544) { - int torque_meas_new = ((GET_BYTE(to_push, 4) & 0x7U) << 8) + GET_BYTE(to_push, 5) - 1024U; + bool valid = addr_safety_check(to_push, chrysler_rx_checks, CHRYSLER_RX_CHECK_LEN, + NULL, NULL, NULL); - // update array of samples - update_sample(&chrysler_torque_meas, torque_meas_new); - } + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); + + // Measured eps torque + if (addr == 544) { + int torque_meas_new = ((GET_BYTE(to_push, 4) & 0x7U) << 8) + GET_BYTE(to_push, 5) - 1024U; - // enter controls on rising edge of ACC, exit controls on ACC off - if (addr == 0x1F4) { - int cruise_engaged = ((GET_BYTE(to_push, 2) & 0x38) >> 3) == 7; - if (cruise_engaged && !chrysler_cruise_engaged_last) { - controls_allowed = 1; + // update array of samples + update_sample(&chrysler_torque_meas, torque_meas_new); } - if (!cruise_engaged) { - controls_allowed = 0; + + // enter controls on rising edge of ACC, exit controls on ACC off + if (addr == 0x1F4) { + int cruise_engaged = ((GET_BYTE(to_push, 2) & 0x38) >> 3) == 7; + if (cruise_engaged && !chrysler_cruise_engaged_last) { + controls_allowed = 1; + } + if (!cruise_engaged) { + controls_allowed = 0; + } + chrysler_cruise_engaged_last = cruise_engaged; } - chrysler_cruise_engaged_last = cruise_engaged; - } - // TODO: add gas pressed check + // TODO: add gas pressed check - // check if stock camera ECU is on bus 0 - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x292)) { - relay_malfunction = true; + // check if stock camera ECU is on bus 0 + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x292)) { + relay_malfunction = true; + } } - return 1; + return valid; } static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { diff --git a/board/safety/safety_gm.h b/board/safety/safety_gm.h index 5356a113f68baa..81512908488528 100644 --- a/board/safety/safety_gm.h +++ b/board/safety/safety_gm.h @@ -42,78 +42,84 @@ uint32_t gm_ts_last = 0; struct sample_t gm_torque_driver; // last few driver torques measured static int gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if (addr == 388) { - int torque_driver_new = ((GET_BYTE(to_push, 6) & 0x7) << 8) | GET_BYTE(to_push, 7); - torque_driver_new = to_signed(torque_driver_new, 11); - // update array of samples - update_sample(&gm_torque_driver, torque_driver_new); - } - // sample speed, really only care if car is moving or not - // rear left wheel speed - if (addr == 842) { - gm_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1); - } + bool valid = addr_safety_check(to_push, gm_rx_checks, GM_RX_CHECK_LEN, + NULL, NULL, NULL); - // ACC steering wheel buttons - if (addr == 481) { - int button = (GET_BYTE(to_push, 5) & 0x70) >> 4; - switch (button) { - case 2: // resume - case 3: // set - controls_allowed = 1; - break; - case 6: // cancel - controls_allowed = 0; - break; - default: - break; // any other button is irrelevant + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); + + if (addr == 388) { + int torque_driver_new = ((GET_BYTE(to_push, 6) & 0x7) << 8) | GET_BYTE(to_push, 7); + torque_driver_new = to_signed(torque_driver_new, 11); + // update array of samples + update_sample(&gm_torque_driver, torque_driver_new); } - } - // exit controls on rising edge of brake press or on brake press when - // speed > 0 - if (addr == 241) { - int brake = GET_BYTE(to_push, 1); - // Brake pedal's potentiometer returns near-zero reading - // even when pedal is not pressed - if (brake < 10) { - brake = 0; + // sample speed, really only care if car is moving or not + // rear left wheel speed + if (addr == 842) { + gm_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1); } - if (brake && (!gm_brake_prev || gm_moving)) { - controls_allowed = 0; + + // ACC steering wheel buttons + if (addr == 481) { + int button = (GET_BYTE(to_push, 5) & 0x70) >> 4; + switch (button) { + case 2: // resume + case 3: // set + controls_allowed = 1; + break; + case 6: // cancel + controls_allowed = 0; + break; + default: + break; // any other button is irrelevant + } } - gm_brake_prev = brake; - } - // exit controls on rising edge of gas press - if (addr == 417) { - int gas = GET_BYTE(to_push, 6); - if (gas && !gm_gas_prev) { - controls_allowed = 0; + // exit controls on rising edge of brake press or on brake press when + // speed > 0 + if (addr == 241) { + int brake = GET_BYTE(to_push, 1); + // Brake pedal's potentiometer returns near-zero reading + // even when pedal is not pressed + if (brake < 10) { + brake = 0; + } + if (brake && (!gm_brake_prev || gm_moving)) { + controls_allowed = 0; + } + gm_brake_prev = brake; } - gm_gas_prev = gas; - } - // exit controls on regen paddle - if (addr == 189) { - bool regen = GET_BYTE(to_push, 0) & 0x20; - if (regen) { - controls_allowed = 0; + // exit controls on rising edge of gas press + if (addr == 417) { + int gas = GET_BYTE(to_push, 6); + if (gas && !gm_gas_prev) { + controls_allowed = 0; + } + gm_gas_prev = gas; } - } - // Check if ASCM or LKA camera are online - // on powertrain bus. - // 384 = ASCMLKASteeringCmd - // 715 = ASCMGasRegenCmd - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 384) || (addr == 715))) { - relay_malfunction = true; + // exit controls on regen paddle + if (addr == 189) { + bool regen = GET_BYTE(to_push, 0) & 0x20; + if (regen) { + controls_allowed = 0; + } + } + + // Check if ASCM or LKA camera are online + // on powertrain bus. + // 384 = ASCMLKASteeringCmd + // 715 = ASCMGasRegenCmd + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 384) || (addr == 715))) { + relay_malfunction = true; + } } - return 1; + return valid; } // all commands: gas/regen, friction brake and steering diff --git a/board/safety/safety_hyundai.h b/board/safety/safety_hyundai.h index fcf112a96467e7..33a670f299b08e 100644 --- a/board/safety/safety_hyundai.h +++ b/board/safety/safety_hyundai.h @@ -21,35 +21,41 @@ uint32_t hyundai_ts_last = 0; struct sample_t hyundai_torque_driver; // last few driver torques measured static int hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - if (addr == 897) { - int torque_driver_new = ((GET_BYTES_04(to_push) >> 11) & 0xfff) - 2048; - // update array of samples - update_sample(&hyundai_torque_driver, torque_driver_new); - } + bool valid = addr_safety_check(to_push, hyundai_rx_checks, HYUNDAI_RX_CHECK_LEN, + NULL, NULL, NULL); + + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); - // enter controls on rising edge of ACC, exit controls on ACC off - if (addr == 1057) { - // 2 bits: 13-14 - int cruise_engaged = (GET_BYTES_04(to_push) >> 13) & 0x3; - if (cruise_engaged && !hyundai_cruise_engaged_last) { - controls_allowed = 1; + if (addr == 897) { + int torque_driver_new = ((GET_BYTES_04(to_push) >> 11) & 0xfff) - 2048; + // update array of samples + update_sample(&hyundai_torque_driver, torque_driver_new); } - if (!cruise_engaged) { - controls_allowed = 0; + + // enter controls on rising edge of ACC, exit controls on ACC off + if (addr == 1057) { + // 2 bits: 13-14 + int cruise_engaged = (GET_BYTES_04(to_push) >> 13) & 0x3; + if (cruise_engaged && !hyundai_cruise_engaged_last) { + controls_allowed = 1; + } + if (!cruise_engaged) { + controls_allowed = 0; + } + hyundai_cruise_engaged_last = cruise_engaged; } - hyundai_cruise_engaged_last = cruise_engaged; - } - // TODO: check gas pressed + // TODO: check gas pressed - // check if stock camera ECU is on bus 0 - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 832)) { - relay_malfunction = true; + // check if stock camera ECU is on bus 0 + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 832)) { + relay_malfunction = true; + } } - return 1; + return valid; } static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { diff --git a/board/safety/safety_subaru.h b/board/safety/safety_subaru.h index b4ff5f29d9dd21..885e2731d523c2 100644 --- a/board/safety/safety_subaru.h +++ b/board/safety/safety_subaru.h @@ -24,36 +24,42 @@ uint32_t subaru_ts_last = 0; struct sample_t subaru_torque_driver; // last few driver torques measured static int subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if (((addr == 0x119) || (addr == 0x371)) && (bus == 0)){ - int bit_shift = (addr == 0x119) ? 16 : 29; - int torque_driver_new = ((GET_BYTES_04(to_push) >> bit_shift) & 0x7FF); - torque_driver_new = to_signed(torque_driver_new, 11); - // update array of samples - update_sample(&subaru_torque_driver, torque_driver_new); - } - // enter controls on rising edge of ACC, exit controls on ACC off - if (((addr == 0x240) || (addr == 0x144)) && (bus == 0)) { - int bit_shift = (addr == 0x240) ? 9 : 17; - int cruise_engaged = ((GET_BYTES_48(to_push) >> bit_shift) & 1); - if (cruise_engaged && !subaru_cruise_engaged_last) { - controls_allowed = 1; + bool valid = addr_safety_check(to_push, subaru_rx_checks, SUBARU_RX_CHECK_LEN, + NULL, NULL, NULL); + + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); + + if (((addr == 0x119) || (addr == 0x371)) && (bus == 0)){ + int bit_shift = (addr == 0x119) ? 16 : 29; + int torque_driver_new = ((GET_BYTES_04(to_push) >> bit_shift) & 0x7FF); + torque_driver_new = to_signed(torque_driver_new, 11); + // update array of samples + update_sample(&subaru_torque_driver, torque_driver_new); } - if (!cruise_engaged) { - controls_allowed = 0; + + // enter controls on rising edge of ACC, exit controls on ACC off + if (((addr == 0x240) || (addr == 0x144)) && (bus == 0)) { + int bit_shift = (addr == 0x240) ? 9 : 17; + int cruise_engaged = ((GET_BYTES_48(to_push) >> bit_shift) & 1); + if (cruise_engaged && !subaru_cruise_engaged_last) { + controls_allowed = 1; + } + if (!cruise_engaged) { + controls_allowed = 0; + } + subaru_cruise_engaged_last = cruise_engaged; } - subaru_cruise_engaged_last = cruise_engaged; - } - // TODO: enforce cancellation on gas pressed + // TODO: enforce cancellation on gas pressed - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 0x122) || (addr == 0x164))) { - relay_malfunction = true; + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 0x122) || (addr == 0x164))) { + relay_malfunction = true; + } } - return 1; + return valid; } static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { diff --git a/board/safety/safety_volkswagen.h b/board/safety/safety_volkswagen.h index 4b01fd4bcd8942..102cb22b57b04f 100644 --- a/board/safety/safety_volkswagen.h +++ b/board/safety/safety_volkswagen.h @@ -33,42 +33,48 @@ uint32_t volkswagen_ts_last = 0; int volkswagen_gas_prev = 0; static int volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - // Update driver input torque samples from EPS_01.Driver_Strain for absolute torque, and EPS_01.Driver_Strain_VZ - // for the direction. - if ((bus == 0) && (addr == MSG_EPS_01)) { - int torque_driver_new = GET_BYTE(to_push, 5) | ((GET_BYTE(to_push, 6) & 0x1F) << 8); - int sign = (GET_BYTE(to_push, 6) & 0x80) >> 7; - if (sign == 1) { - torque_driver_new *= -1; - } - - update_sample(&volkswagen_torque_driver, torque_driver_new); - } - - // Monitor ACC_06.ACC_Status_ACC for stock ACC status. Because the current MQB port is lateral-only, OP's control - // allowed state is directly driven by stock ACC engagement. Permit the ACC message to come from either bus, in - // order to accommodate future camera-side integrations if needed. - if (addr == MSG_ACC_06) { - int acc_status = (GET_BYTE(to_push, 7) & 0x70) >> 4; - controls_allowed = ((acc_status == 3) || (acc_status == 4) || (acc_status == 5)) ? 1 : 0; - } - - // exit controls on rising edge of gas press. Bits [12-20) - if (addr == MSG_MOTOR_20) { - int gas = (GET_BYTES_04(to_push) >> 12) & 0xFF; - if ((gas > 0) && (volkswagen_gas_prev == 0)) { - controls_allowed = 0; - } - volkswagen_gas_prev = gas; - } - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) { - relay_malfunction = true; + bool valid = addr_safety_check(to_push, volkswagen_rx_checks, VOLKSWAGEN_RX_CHECK_LEN, + NULL, NULL, NULL); + + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); + + // Update driver input torque samples from EPS_01.Driver_Strain for absolute torque, and EPS_01.Driver_Strain_VZ + // for the direction. + if ((bus == 0) && (addr == MSG_EPS_01)) { + int torque_driver_new = GET_BYTE(to_push, 5) | ((GET_BYTE(to_push, 6) & 0x1F) << 8); + int sign = (GET_BYTE(to_push, 6) & 0x80) >> 7; + if (sign == 1) { + torque_driver_new *= -1; + } + + update_sample(&volkswagen_torque_driver, torque_driver_new); + } + + // Monitor ACC_06.ACC_Status_ACC for stock ACC status. Because the current MQB port is lateral-only, OP's control + // allowed state is directly driven by stock ACC engagement. Permit the ACC message to come from either bus, in + // order to accommodate future camera-side integrations if needed. + if (addr == MSG_ACC_06) { + int acc_status = (GET_BYTE(to_push, 7) & 0x70) >> 4; + controls_allowed = ((acc_status == 3) || (acc_status == 4) || (acc_status == 5)) ? 1 : 0; + } + + // exit controls on rising edge of gas press. Bits [12-20) + if (addr == MSG_MOTOR_20) { + int gas = (GET_BYTES_04(to_push) >> 12) & 0xFF; + if ((gas > 0) && (volkswagen_gas_prev == 0)) { + controls_allowed = 0; + } + volkswagen_gas_prev = gas; + } + + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) { + relay_malfunction = true; + } } - return 1; + return valid; } static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { diff --git a/python/uds.py b/python/uds.py index 96d07e1a722a0f..548f1bcceaab9c 100644 --- a/python/uds.py +++ b/python/uds.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import time import struct +from collections import deque from typing import Callable, NamedTuple, Tuple, List from enum import IntEnum @@ -275,11 +276,12 @@ def __init__(self, can_send: Callable[[Tuple[int, bytes, int]], None], can_recv: self.rx = can_recv self.tx_addr = tx_addr self.rx_addr = rx_addr + self.rx_buff = deque() self.sub_addr = sub_addr self.bus = bus self.debug = debug - def _recv_filter(self, bus, addr): + def _recv_filter(self, bus: int, addr: int) -> bool: # handle functional addresses (switch to first addr to respond) if self.tx_addr == 0x7DF: is_response = addr >= 0x7E8 and addr <= 0x7EF @@ -296,12 +298,12 @@ def _recv_filter(self, bus, addr): self.rx_addr = addr return bus == self.bus and addr == self.rx_addr - def recv(self, drain=False) -> List[bytes]: - msg_array = [] + def _recv_buffer(self, drain: bool=False) -> None: while True: msgs = self.rx() if drain: if self.debug: print("CAN-RX: drain - {}".format(len(msgs))) + self.rx_buff.clear() else: for rx_addr, rx_ts, rx_data, rx_bus in msgs or []: if self._recv_filter(rx_bus, rx_addr) and len(rx_data) > 0: @@ -313,15 +315,24 @@ def recv(self, drain=False) -> List[bytes]: if self.sub_addr is not None: rx_data = rx_data[1:] - msg_array.append(rx_data) + self.rx_buff.append(rx_data) # break when non-full buffer is processed if len(msgs) < 254: - return msg_array + return + + def recv(self, drain: bool=False) -> List[bytes]: + # buffer rx messages in case two response messages are received at once + # (e.g. response pending and success/failure response) + self._recv_buffer(drain) + try: + while True: + yield self.rx_buff.popleft() + except IndexError: + pass # empty def send(self, msgs: List[bytes], delay: float=0) -> None: - first = True - for msg in msgs: - if delay and not first: + for i, msg in enumerate(msgs): + if delay and i != 0: if self.debug: print(f"CAN-TX: delay - {delay}") time.sleep(delay) @@ -332,8 +343,9 @@ def send(self, msgs: List[bytes], delay: float=0) -> None: assert len(msg) <= 8 self.tx(self.tx_addr, msg, self.bus) - first = False - + # prevent rx buffer from overflowing on large tx + if i % 10 == 9: + self._recv_buffer() class IsoTpMessage(): def __init__(self, can_client: CanClient, timeout: float=1, debug: bool=False, max_len: int=8):