const int HYUNDAI_MAX_STEER = 250; const int HYUNDAI_MAX_RT_DELTA = 112; // max delta torque allowed for real time checks const int32_t HYUNDAI_RT_INTERVAL = 250000; // 250ms between real time checks const int HYUNDAI_MAX_RATE_UP = 3; const int HYUNDAI_MAX_RATE_DOWN = 7; const int HYUNDAI_DRIVER_TORQUE_ALLOWANCE = 50; const int HYUNDAI_DRIVER_TORQUE_FACTOR = 2; int hyundai_camera_detected = 0; int hyundai_giraffe_switch_2 = 0; // is giraffe switch 2 high? int hyundai_rt_torque_last = 0; int hyundai_desired_torque_last = 0; int hyundai_cruise_engaged_last = 0; uint32_t hyundai_ts_last = 0; struct sample_t hyundai_torque_driver; // last few driver torques measured static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = (to_push->RDTR >> 4) & 0xFF; uint32_t addr; if (to_push->RIR & 4) { // Extended // Not looked at, but have to be separated // to avoid address collision addr = to_push->RIR >> 3; } else { // Normal addr = to_push->RIR >> 21; } if (addr == 897) { int torque_driver_new = ((to_push->RDLR >> 11) & 0xfff) - 2048; // update array of samples update_sample(&hyundai_torque_driver, torque_driver_new); } // check if stock camera ECU is still online if (bus == 0 && addr == 832) { hyundai_camera_detected = 1; controls_allowed = 0; } // enter controls on rising edge of ACC, exit controls on ACC off if ((to_push->RIR>>21) == 1057) { // 2 bits: 13-14 int cruise_engaged = (to_push->RDLR >> 13) & 0x3; if (cruise_engaged && !hyundai_cruise_engaged_last) { controls_allowed = 1; } else if (!cruise_engaged) { controls_allowed = 0; } hyundai_cruise_engaged_last = cruise_engaged; } // 832 is lkas cmd. If it is on bus 2, then giraffe switch 2 is high if ((to_push->RIR>>21) == 832 && (bus == 2)) { hyundai_giraffe_switch_2 = 1; } } static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // There can be only one! (camera) if (hyundai_camera_detected) { return 0; } uint32_t addr; if (to_send->RIR & 4) { // Extended addr = to_send->RIR >> 3; } else { // Normal addr = to_send->RIR >> 21; } // LKA STEER: safety check if (addr == 832) { int desired_torque = ((to_send->RDLR >> 16) & 0x7ff) - 1024; uint32_t ts = TIM2->CNT; int violation = 0; if (controls_allowed) { // *** global torque limit check *** violation |= max_limit_check(desired_torque, HYUNDAI_MAX_STEER, -HYUNDAI_MAX_STEER); // *** torque rate limit check *** violation |= driver_limit_check(desired_torque, hyundai_desired_torque_last, &hyundai_torque_driver, HYUNDAI_MAX_STEER, HYUNDAI_MAX_RATE_UP, HYUNDAI_MAX_RATE_DOWN, HYUNDAI_DRIVER_TORQUE_ALLOWANCE, HYUNDAI_DRIVER_TORQUE_FACTOR); // used next time hyundai_desired_torque_last = desired_torque; // *** torque real time rate limit check *** violation |= rt_rate_limit_check(desired_torque, hyundai_rt_torque_last, HYUNDAI_MAX_RT_DELTA); // every RT_INTERVAL set the new limits uint32_t ts_elapsed = get_ts_elapsed(ts, hyundai_ts_last); if (ts_elapsed > HYUNDAI_RT_INTERVAL) { hyundai_rt_torque_last = desired_torque; hyundai_ts_last = ts; } } // no torque if controls is not allowed if (!controls_allowed && (desired_torque != 0)) { violation = 1; } // reset to 0 if either controls is not allowed or there's a violation if (violation || !controls_allowed) { hyundai_desired_torque_last = 0; hyundai_rt_torque_last = 0; hyundai_ts_last = ts; } if (violation) { return false; } } // FORCE CANCEL: safety check only relevant when spamming the cancel button. // ensuring that only the cancel button press is sent (VAL 4) when controls are off. // This avoids unintended engagements while still allowing resume spam if (((to_send->RIR>>21) == 1265) && !controls_allowed && ((to_send->RDTR >> 4) & 0xFF) == 0) { if ((to_send->RDLR & 0x7) != 4) return 0; } // 1 allows the message through return true; } static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { // forward cam to ccan and viceversa, except lkas cmd if ((bus_num == 0 || bus_num == 2) && hyundai_giraffe_switch_2) { int addr = to_fwd->RIR>>21; bool is_lkas_msg = addr == 832 && bus_num == 2; return is_lkas_msg? -1 : (uint8_t)(~bus_num & 0x2); } return -1; } static void hyundai_init(int16_t param) { controls_allowed = 0; hyundai_giraffe_switch_2 = 0; } const safety_hooks hyundai_hooks = { .init = hyundai_init, .rx = hyundai_rx_hook, .tx = hyundai_tx_hook, .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = hyundai_fwd_hook, };