From 3e47e9593492d8f7febad0ece009b90b3d56a8b3 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 10 Jan 2026 14:41:02 -0600 Subject: [PATCH] Malibu Checksum --- selfdrive/car/gm/carcontroller.py | 21 +++++++++++++++++---- selfdrive/car/gm/gmcan.py | 13 +++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 37a4b8a6b..9d7420da7 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -57,6 +57,7 @@ class CarController(CarControllerBase): self.coeffDrag = 0.30 self.airDensity = 1.225 self.params_ = Params() + self.malibu_cancel_phase = 0 self.packer_pt = CANPacker(DBC[self.CP.carFingerprint]['pt']) self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) @@ -229,7 +230,10 @@ class CarController(CarControllerBase): # Using extend instead of append since the message is only sent intermittently can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, frogpilot_toggles)) elif CC.enabled and self.frame % 52 == 0 and CS.cruise_buttons == CruiseButtons.UNPRESS and CS.out.gasPressed and CS.out.cruiseState.speed < CS.out.vEgo < hud_v_cruise: - can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET)) + if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC: + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, 0, CruiseButtons.DECEL_SET)) + else: + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET)) if self.CP.enableGasInterceptor: can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx)) if self.CP.carFingerprint not in CC_ONLY_CAR: @@ -288,9 +292,15 @@ class CarController(CarControllerBase): (self.CP.flags & GMFlags.PEDAL_LONG.value) # Always cancel stock CC when using pedal interceptor or (self.CP.flags & GMFlags.CC_LONG.value and not CC.enabled) # Cancel stock CC if OP is not active ) and CS.out.cruiseState.enabled: - if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: + cancel_interval = 0.03 if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC else 0.04 + if (self.frame - self.last_button_frame) * DT_CTRL > cancel_interval: self.last_button_frame = self.frame - can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL)) + if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC: + # Match the car's 33 Hz button cadence to keep checksum phase aligned. + self.malibu_cancel_phase = (self.malibu_cancel_phase + 1) % 4 + can_sends.append(gmcan.create_buttons_malibu_cancel(CanBus.POWERTRAIN, self.malibu_cancel_phase)) + else: + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL)) else: # While car is braking, cancel button causes ECM to enter a soft disable state with a fault status. @@ -301,7 +311,10 @@ class CarController(CarControllerBase): if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: if self.cancel_counter > CAMERA_CANCEL_DELAY_FRAMES: self.last_button_frame = self.frame - can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) + if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC: + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, 0, CruiseButtons.CANCEL)) + else: + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) if self.CP.networkLocation == NetworkLocation.fwdCamera: # Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1 diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index f2a87bae4..4ff85b460 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -24,6 +24,19 @@ def create_buttons(packer, bus, idx, button): return packer.make_can_msg("ASCMSteeringButton", bus, values) +def create_buttons_malibu_cancel(bus, phase): + # Malibu Hybrid CC cancel frames use a 4-value pattern in the last 2 bytes. + data = bytearray(7) + data[3] = 0x01 # ACCAlwaysOne + data[4] = 0x00 + # Observed cancel payloads (bus 0/130): 00 00 00 01 00 60 AF / 65 9E / 6A 8D / 6F 7C + cancel_bytes = (0x60, 0xAF, 0x65, 0x9E, 0x6A, 0x8D, 0x6F, 0x7C) + idx = (phase % 4) * 2 + data[5] = cancel_bytes[idx] + data[6] = cancel_bytes[idx + 1] + return make_can_msg(0x1e1, bytes(data), bus) + + def create_pscm_status(packer, bus, pscm_status): values = {s: pscm_status[s] for s in [ "HandsOffSWDetectionMode",