diff --git a/opendbc_repo/opendbc/car/__init__.py b/opendbc_repo/opendbc/car/__init__.py index 79fb45537..7a2bb3dc1 100644 --- a/opendbc_repo/opendbc/car/__init__.py +++ b/opendbc_repo/opendbc/car/__init__.py @@ -240,3 +240,39 @@ class Platforms(str, ReprEnum, metaclass=PlatformsType): @classmethod def with_flags(cls, flags: IntFlag) -> set['Platforms']: return {p for p in cls if p.config.flags & flags} + + +# OPGM variables +def crc8_pedal(data): + crc = 0xFF # standard init value + poly = 0xD5 # standard crc8: x8+x7+x6+x4+x2+1 + size = len(data) + for i in range(size - 1, -1, -1): + crc ^= data[i] + for _ in range(8): + if ((crc & 0x80) != 0): + crc = ((crc << 1) ^ poly) & 0xFF + else: + crc <<= 1 + return crc + + +def create_gas_interceptor_command(packer, gas_amount, idx): + # Common gas pedal msg generator + enable = gas_amount > 0.001 + + values = { + "ENABLE": enable, + "COUNTER_PEDAL": idx & 0xF, + } + + if enable: + values["GAS_COMMAND"] = gas_amount * 255. + values["GAS_COMMAND2"] = gas_amount * 255. + + dat = packer.make_can_msg("GAS_COMMAND", 0, values)[1] + + checksum = crc8_pedal(dat[:-1]) + values["CHECKSUM_PEDAL"] = checksum + + return packer.make_can_msg("GAS_COMMAND", 0, values) diff --git a/opendbc_repo/opendbc/car/gm/carcontroller.py b/opendbc_repo/opendbc/car/gm/carcontroller.py index 9f462004c..44f1afb59 100644 --- a/opendbc_repo/opendbc/car/gm/carcontroller.py +++ b/opendbc_repo/opendbc/car/gm/carcontroller.py @@ -1,10 +1,10 @@ import numpy as np from opendbc.can import CANPacker -from opendbc.car import Bus, DT_CTRL, structs +from opendbc.car import Bus, DT_CTRL, create_gas_interceptor_command, structs from opendbc.car.lateral import apply_driver_steer_torque_limits from opendbc.car.gm import gmcan from opendbc.car.common.conversions import Conversions as CV -from opendbc.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons +from opendbc.car.gm.values import CC_ONLY_CAR, DBC, CanBus, CarControllerParams, CruiseButtons, GMFlags from opendbc.car.interfaces import CarControllerBase VisualAlert = structs.CarControl.HUDControl.VisualAlert @@ -37,6 +37,26 @@ class CarController(CarControllerBase): self.packer_obj = CANPacker(DBC[self.CP.carFingerprint][Bus.radar]) self.packer_ch = CANPacker(DBC[self.CP.carFingerprint][Bus.chassis]) + # OPGM variables + self.prev_op_enabled = False + + self.apply_speed = 0 + self.pedal_steady = 0 + + # OPGM variables + @staticmethod + def calc_pedal_command(accel: float, long_active: bool, v_ego: float) -> float: + if not long_active: + return 0. + + if accel < -0.5: + pedal_gas = 0 + else: + pedaloffset = np.interp(v_ego, [0., 3, 6, 30], [0.10, 0.175, 0.240, 0.240]) + pedal_gas = np.clip((pedaloffset + accel * 0.6), 0.0, 1.0) + + return pedal_gas + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl @@ -85,6 +105,7 @@ class CarController(CarControllerBase): # Gas/regen, brakes, and UI commands - all at 25Hz if self.frame % 4 == 0: stopping = actuators.longControlState == LongCtrlState.stopping + interceptor_gas_cmd = 0 if not CC.longActive: # ASCM sends max regen when not enabled self.apply_gas = self.params.INACTIVE_REGEN @@ -97,26 +118,38 @@ class CarController(CarControllerBase): if stopping: self.apply_gas = self.params.INACTIVE_REGEN + # OPGM variables + if self.CP.carFingerprint in CC_ONLY_CAR: + # gas interceptor only used for full long control on cars without ACC + interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive, CS.out.vEgo) + idx = (self.frame // 4) % 4 at_full_stop = CC.longActive and CS.out.standstill near_stop = CC.longActive and (abs(CS.out.vEgo) < self.params.NEAR_STOP_BRAKE_PHASE) - friction_brake_bus = CanBus.CHASSIS - # GM Camera exceptions - # TODO: can we always check the longControlState? - if self.CP.networkLocation == NetworkLocation.fwdCamera: - at_full_stop = at_full_stop and stopping - friction_brake_bus = CanBus.POWERTRAIN + if self.CP.flags & GMFlags.CC_LONG.value: + if CC.longActive and CS.out.vEgo > self.CP.minEnableSpeed: + # 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)) + if self.CP.enableGasInterceptorDEPRECATED: + can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx)) + if self.CP.carFingerprint not in CC_ONLY_CAR: + friction_brake_bus = CanBus.CHASSIS + # GM Camera exceptions + # TODO: can we always check the longControlState? + if self.CP.networkLocation == NetworkLocation.fwdCamera and self.CP.carFingerprint not in CC_ONLY_CAR: + at_full_stop = at_full_stop and stopping + friction_brake_bus = CanBus.POWERTRAIN - # GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation - can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, CC.enabled, at_full_stop)) - can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake, + # GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation + can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, CC.enabled, at_full_stop)) + can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake, idx, CC.enabled, near_stop, at_full_stop, self.CP)) - # Send dashboard UI commands (ACC status) - send_fcw = hud_alert == VisualAlert.fcw - can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, CC.enabled, - hud_v_cruise * CV.MS_TO_KPH, hud_control, send_fcw)) + # Send dashboard UI commands (ACC status) + send_fcw = hud_alert == VisualAlert.fcw + can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, CC.enabled, + hud_v_cruise * CV.MS_TO_KPH, hud_control, send_fcw)) # Radar needs to know current speed and yaw rate (50hz), # and that ADAS is alive (10hz) @@ -137,6 +170,18 @@ class CarController(CarControllerBase): if self.CP.networkLocation == NetworkLocation.gateway and self.frame % self.params.ADAS_KEEPALIVE_STEP == 0: can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN) + # OPGM variables + # Pedal interceptor: always send CANCEL when cruise is on + if (self.CP.flags & GMFlags.PEDAL_LONG.value) and CS.out.cruiseState.enabled: + if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: + self.last_button_frame = self.frame + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL)) + # CC_LONG: only send CANCEL on OP disengage when cruise is still on + elif ((self.CP.flags & GMFlags.CC_LONG.value) and self.prev_op_enabled and not CC.enabled and CS.out.cruiseState.enabled): + if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: + self.last_button_frame = self.frame + 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. # A delayed cancellation allows camera to cancel and avoids a fault when user depresses brake quickly @@ -160,4 +205,10 @@ class CarController(CarControllerBase): new_actuators.brake = self.apply_brake self.frame += 1 + + # OPGM variables + new_actuators.speed = self.apply_speed + + self.prev_op_enabled = CC.enabled + return new_actuators, can_sends diff --git a/opendbc_repo/opendbc/car/gm/carstate.py b/opendbc_repo/opendbc/car/gm/carstate.py index f4a62a301..d81960055 100644 --- a/opendbc_repo/opendbc/car/gm/carstate.py +++ b/opendbc_repo/opendbc/car/gm/carstate.py @@ -3,7 +3,7 @@ from opendbc.can import CANDefine, CANParser from opendbc.car import Bus, create_button_events, structs from opendbc.car.common.conversions import Conversions as CV from opendbc.car.interfaces import CarStateBase -from opendbc.car.gm.values import DBC, AccState, CruiseButtons, STEER_THRESHOLD, SDGM_CAR, ALT_ACCS +from opendbc.car.gm.values import CAMERA_ACC_CAR, CC_ONLY_CAR, DBC, AccState, CruiseButtons, STEER_THRESHOLD, SDGM_CAR, ALT_ACCS ButtonType = structs.CarState.ButtonEvent.Type TransmissionType = structs.CarParams.TransmissionType @@ -14,6 +14,9 @@ STANDSTILL_THRESHOLD = 10 * 0.0311 BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise, CruiseButtons.MAIN: ButtonType.mainCruise, CruiseButtons.CANCEL: ButtonType.cancel} +# OPGM variables +GearShifter = structs.CarState.GearShifter + class CarState(CarStateBase): def __init__(self, CP): @@ -31,6 +34,11 @@ class CarState(CarStateBase): self.distance_button = 0 + # OPGM variables + self.single_pedal_mode = False + + self.pedal_steady = 0 + def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]): if not self.CP.pcmCruise: for b in buttonEvents: @@ -96,7 +104,13 @@ class CarState(CarStateBase): if self.CP.transmissionType == TransmissionType.direct: ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0 - ret.gasPressed = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254. > 1e-5 + if self.CP.enableGasInterceptorDEPRECATED: + gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2. + # Panda 515 threshold = 10.88. Set lower to avoid panda blocking messages and GasInterceptor faulting. + threshold = 20 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 + ret.gasPressed = gas > threshold + else: + ret.gasPressed = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254. > 1e-5 ret.steeringAngleDeg = pt_cp.vl["PSCMSteeringAngle"]["SteeringWheelAngle"] ret.steeringRateDeg = pt_cp.vl["PSCMSteeringAngle"]["SteeringWheelRate"] @@ -129,7 +143,7 @@ class CarState(CarStateBase): ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL if self.CP.networkLocation == NetworkLocation.fwdCamera: - if self.CP.carFingerprint not in ALT_ACCS: + if self.CP.carFingerprint not in (ALT_ACCS | CC_ONLY_CAR): ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS # This FCW signal only works for SDGM cars. CAM cars send FCW on GMLAN but this bit is always 0 for them ret.stockFcw = cam_cp.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] != 0 @@ -158,6 +172,16 @@ class CarState(CarStateBase): if ret.vEgo < self.CP.minSteerSpeed: ret.lowSpeedAlert = True + # OPGM variables + if self.CP.carFingerprint in CC_ONLY_CAR: + ret.accFaulted = False + + ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0 + ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS + + if self.CP.transmissionType == TransmissionType.direct: + self.single_pedal_mode = ret.gearShifter == GearShifter.low or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 + return ret @staticmethod diff --git a/opendbc_repo/opendbc/car/gm/fingerprints.py b/opendbc_repo/opendbc/car/gm/fingerprints.py index 2758e7980..7a879a16f 100644 --- a/opendbc_repo/opendbc/car/gm/fingerprints.py +++ b/opendbc_repo/opendbc/car/gm/fingerprints.py @@ -18,10 +18,28 @@ FINGERPRINTS = { }, { 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 368: 8, 381: 2, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 5, 844: 8, 853: 8, 866: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7 + }, + # Volt Premier 2017 w/ flashed firmware, cam harness + pedal + { + 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 513: 6, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1922: 7 }], CAR.BUICK_LACROSSE: [{ 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 }], + # CAR.CHEVROLET_VOLT_CC: [ + # FIXME: Need a message to distinguish flashed from non-flashed + # Volt Premier w/o acc 2016 + # { + # 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 8, 308: 4, 309: 8, 311: 8, 313: 8, 320: 8, 328: 1, 352: 5, 368: 8, 381: 6, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 4, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 8, 563: 5, 564: 5, 565: 8, 566: 5, 567: 3, 568: 1, 577: 8, 578: 8, 594: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 6, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1618: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 1930: 7, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2025: 8, 2028: 8 + # }, + # { + # 201: 8, 493: 8, 495: 4, 193: 8, 197: 8, 209: 7, 171: 8, 456: 8, 199: 4, 489: 8, 211: 2, 499: 3, 390: 7, 532: 6, 568: 1, 761: 7, 381: 6, 485: 8, 189: 7, 479: 3, 711: 6, 501: 8, 241: 6, 717: 5, 869: 4, 389: 2, 454: 8, 170: 8, 190: 6, 497: 8, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 500: 6, 508: 8, 528: 4, 647: 3, 1105: 6, 1005: 6, 481: 7, 844: 8, 866: 4, 564: 5, 969: 8, 388: 8, 352: 5, 562: 8, 961: 8, 386: 8, 707: 8, 977: 8, 979: 7, 298: 8, 840: 5, 842: 5, 988: 6, 1001: 8, 560: 8, 546: 7, 558: 8, 309: 8, 995: 7, 311: 8, 566: 5, 567:3, 989: 8, 384: 4, 800: 6, 1033: 7, 1034: 7, 313: 8, 554: 3, 810: 8, 1017: 8, 1019: 2, 1020: 8, 1217: 8, 1223: 3, 1233: 8, 1227: 4, 1417: 8, 1009: 8, 1221: 5, 1275: 3, 1225: 7, 289: 8, 550: 8, 1273: 3, 1928: 7, 1187: 4, 1265: 8, 1927: 7, 1267: 1, 1906: 7, 288: 5, 304: 1, 328: 1, 1912: 7, 320: 3, 1910: 7, 563: 5, 1249: 8, 1930: 7, 1257: 6, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 565: 5, 1280: 4, 1907: 7 + # }, + # # Volt Premier w/o ACC 2018 + Pedal + # { + # 189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 513: 6, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1922: 7, 1930: 7 + # } + # ], CAR.BUICK_REGAL: [{ 190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 8, 419: 8, 422: 4, 426: 8, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 463: 3, 479: 8, 481: 7, 485: 8, 487: 8, 489: 8, 495: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 882: 8, 884: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 967: 8, 969: 8, 977: 8, 979: 8, 985: 8, 1001: 8, 1005: 6, 1009: 8, 1011: 8, 1013: 3, 1017: 8, 1020: 8, 1024: 8, 1025: 8, 1026: 8, 1027: 8, 1028: 8, 1029: 8, 1030: 8, 1031: 8, 1032: 2, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 8, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 8, 1263: 8, 1265: 8, 1267: 8, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1603: 7, 1611: 8, 1618: 8, 1906: 8, 1907: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1930: 7, 2016: 8, 2018: 8, 2019: 8, 2024: 8, 2026: 8 }], @@ -49,6 +67,49 @@ FINGERPRINTS = { CAR.CHEVROLET_BOLT_EUV: [{ 189: 7, 190: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 3, 241: 6, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 458: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7 }], + CAR.CHEVROLET_BOLT_2017: [ + # Bolt Premier w/o ACC 2017 + { + 170: 8, 188: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 201: 6, 209: 7, 211: 2, 241: 6, 289: 1, 290: 1, 298: 8, 304: 8, 309: 8, 311: 8, 313: 8, 320: 8, 322: 7, 328: 1, 352: 5, 353: 3, 368: 8, 381: 6, 384: 8, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 512: 3, 513: 6, 514: 2, 516: 4, 519: 2, 521: 3, 528: 5, 530: 8, 532: 7, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 8, 566: 6, 567: 5, 568: 1, 569: 3, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 832: 8, 840: 6, 842: 6, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1601: 8, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1927: 7, 2016: 8, 2020: 8, 2024: 8, 2028: 8 + }, + # Bolt EV Premier 2017 + { + 170: 8, 188: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 201: 6, 209: 7, 211: 2, 241: 6, 289: 1, 290: 1, 298: 8, 304: 8, 309: 8, 311: 8, 313: 8, 320: 8, 322: 7, 328: 1, 352: 5, 353: 3, 368: 8, 381: 6, 384: 8, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 513: 6, 512: 3, 514: 2, 516: 4, 519: 2, 521: 3, 528: 5, 530: 8, 532: 7, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 8, 566: 6, 567: 5, 568: 1, 569: 3, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 832: 8, 840: 6, 842: 6, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1601: 8, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1927: 7, 2016: 8, 2020: 8, 2024: 8, 2028: 8 + }, + # Bolt EV Premier 2017 w Pedal + { # pylint: disable=duplicate-key + 170: 8, 188: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 201: 6, 209: 7, 211: 2, 241: 6, 289: 1, 290: 1, 298: 8, 304: 8, 309: 8, 311: 8, 313: 8, 320: 8, 322: 7, 328: 1, 352: 5, 353: 3, 368: 8, 381: 6, 384: 8, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 512: 3, 512: 6, 513: 6, 514: 2, 516: 4, 519: 2, 521: 3, 528: 5, 530: 8, 532: 7, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 8, 566: 6, 567: 5, 568: 1, 569: 3, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 832: 8, 840: 6, 842: 6, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1601: 8, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1927: 7, 2016: 8, 2020: 8, 2024: 8, 2028: 8 # pylint: disable=duplicate-key # noqa: F601 + }, + # Bolt EV Premier 2017 2 w Pedal + { + 170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 6, 567: 5, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1922: 7, 1927: 7 + }], + CAR.CHEVROLET_BOLT_2018: [ + # Bolt Premier no ACC 2018 + Pedal + { + 170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 6, 567: 5, 568: 1, 573: 1, 577: 8, 592: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1601: 8, 1616: 8, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1922: 7, 1927: 7, 2020: 8, 2023: 8, 2028: 8, 2031: 8 + }, + # Bolt Premier no ACC 2019 + Pedal + { + 170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 512: 6, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 7, 567: 5, 568: 2, 569: 3, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1037: 5, 1105: 5, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1268: 2, 1275: 3, 1279: 4, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1927: 7, 2016: 8, 2024: 8 + }, + # Bolt Premier no ACC 2020 + { + 170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 7, 567: 5, 568: 2, 569: 3, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1037: 5, 1105: 5, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1268: 2, 1275: 3, 1279: 4, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1927: 7, 2016: 8, 2024: 8 + }], + CAR.CHEVROLET_BOLT_CC: [ + # Bolt EV Premier no ACC 2023 w Pedal + { + 170: 8, 188: 8, 189: 7, 190: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 3, 241: 6, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 308: 4, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 398: 8, 407: 7, 417: 8, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 8, 567: 5, 568: 2, 569: 3, 573: 1, 577: 8, 592: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 711: 6, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 866: 4, 869: 4, 872: 1, 880: 6, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1010: 8, 1013: 6, 1015: 1, 1017: 8, 1019: 2, 1020: 8, 1037: 5, 1105: 5, 1187: 5, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1601: 8, 1616: 8, 1618: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1913: 7, 1922: 7, 1927: 7, 1930: 7, 2016: 8, 2020: 8, 2023: 8, 2024: 8, 2028: 8, 2031: 8 + }, + # Bolt EV Premier no ACC 2021 + { + 170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 257: 8, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 7, 567: 5, 568: 1, 569: 3, 573: 1, 577: 8, 578: 8, 579: 8, 592: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1037: 5, 1105: 5, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1279: 4, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1346: 8, 1347: 8, 1513: 8, 1516: 8, 1601: 8, 1616: 8, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1922: 7, 1927: 7, 2016: 8, 2017: 8, 2018: 8, 2020: 8, 2023: 8, 2024: 8, 2028: 8, 2031: 8 + }, + # shermy99's Bolt EV Premier no ACC 2023 + { + 170: 8, 188: 8, 189: 7, 190: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 3, 241: 6, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 308: 4, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 398: 8, 407: 7, 417: 8, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 8, 567: 5, 568: 2, 569: 3, 573: 1, 577: 8, 579: 8, 592: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 711: 6, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 866: 4, 869: 4, 872: 1, 880: 6, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1010: 8, 1013: 6, 1015: 1, 1017: 8, 1019: 2, 1020: 8, 1037: 5, 1105: 5, 1187: 5, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1347: 8, 1513: 8, 1516: 8, 1601: 8, 1609: 8, 1613: 8, 1616: 8, 1618: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1913: 7, 1920: 8, 1922: 7, 1924: 8, 1927: 7, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1984: 8, 1988: 8, 2000: 8, 2001: 8, 2002: 8, 2017: 8, 2018: 8, 2020: 8, 2023: 8, 2025: 8, 2028: 8, 2031: 8 + }], CAR.CHEVROLET_SILVERADO: [{ 190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7 }], @@ -70,6 +131,50 @@ FINGERPRINTS = { CAR.GMC_YUKON: [{ 190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 510: 8, 528: 5, 532: 6, 534: 2, 562: 8, 563: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 761: 7, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1355: 8, 1611: 8 }], + CAR.CHEVROLET_EQUINOX_CC: [{ + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 8, 398: 8, 401: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 444: 7, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1273: 3, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1611: 8, 1618: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 7, 1930: 7 + }, + { + 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 384: 4, 393: 8, 398: 8, 401: 8, 413: 8, 422: 4, 431: 8, 444: 7, 453: 6, 456: 8, 479: 3, 481: 7, 485: 8, 499: 3, 500: 6, 501: 8, 567: 5, 647: 6, 800: 6, 1033: 7, 1034: 7, 1296: 4 + }], + # Trailblazer also matches as a Silverado, so comment out to avoid conflicts. + # TODO: split with FW versions + # CAR.TRAILBLAZER: [ + # { + # 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1609: 8, 1611: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8 + # }], + CAR.CHEVROLET_SUBURBAN_CC: [ + # Slav's 2018 Suburban, LKAS no ACC + { + 170: 8, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 393: 8, 398: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 493: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 562: 8, 563: 5, 564: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 7 + }, + # Qube's 2017 Suburban, LKAS no ACC + { + 190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 510: 8, 528: 5, 532: 6, 534: 2, 562: 8, 563: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1609: 8, 1611: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1871: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1920: 8, 1924: 8, 1927: 8, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1984: 8, 1988: 8, 1990: 8, 2000: 8, 2001: 8, 2004: 8, 2017: 8, 2018: 8, 2020: 8 + }], + CAR.CADILLAC_CT6_CC: [ + # badgers4life's 2017 CT6 + { + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 4, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 460: 5, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 3, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 717: 5, 723: 2, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 977: 8, 979: 7, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 1, 1017: 8, 1019: 2, 1020: 8, 1105: 6, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 7, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 4, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1919: 7, 1920: 8, 1924: 8, 1927: 8, 1928: 7, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1984: 8, 1988: 8, 2000: 8, 2001: 8, 2002: 8, 2004: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 + }], + CAR.CHEVROLET_TRAILBLAZER_CC: [ + { + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 717: 5, 723: 4, 730: 4, 761: 7, 800: 6, 840: 5, 842: 5, 844: 8, 869: 4, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 6, 1017: 8, 1020: 8, 1037: 5, 1105: 5, 1187: 5, 1195: 3, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1276: 2, 1277: 7, 1278: 4, 1279: 4, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7 + }], + CAR.CHEVROLET_MALIBU_CC: [ + # Verylukyguy's Malibu + { + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 328: 1, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 409: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 717: 5, 730: 4, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 6, 1017: 8, 1020: 8, 1037: 5, 1105: 5, 1187: 6, 1189: 1, 1195: 3, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1279: 4, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7 + }, + # Tesla's Malibu + { + 189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 4, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 560: 8, 562: 8, 566: 6, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8 + }], + CAR.CADILLAC_XT5_CC: [ + # TRain's 2017 XT5 + { + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 647: 3, 707: 8, 717: 5, 723: 2, 753: 5, 761: 7, 800: 6, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1919: 7, 1920: 7 + }], } FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = { diff --git a/opendbc_repo/opendbc/car/gm/gmcan.py b/opendbc_repo/opendbc/car/gm/gmcan.py index cb74b609e..91417eacc 100644 --- a/opendbc_repo/opendbc/car/gm/gmcan.py +++ b/opendbc_repo/opendbc/car/gm/gmcan.py @@ -1,5 +1,9 @@ +from typing import Literal + +from opendbc.car import DT_CTRL from opendbc.car.can_definitions import CanData -from opendbc.car.gm.values import CAR +from opendbc.car.common.conversions import Conversions as CV +from opendbc.car.gm.values import CAR, CanBus, CruiseButtons def create_buttons(packer, bus, idx, button): @@ -169,3 +173,80 @@ def create_lka_icon_command(bus, active, critical, steer): else: dat = b"\x00\x00\x00" return CanData(0x104c006c, dat, bus) + + +# OPGM variables +def _create_gm_cc_spam_command_accel(controller, CS, actuators): + # if controller.params_.get_bool("IsMetric"): + # _CV = CV.MS_TO_KPH + # RATE_UP_MAX = 0.04 + # RATE_DOWN_MAX = 0.04 + # else: + _CV = CV.MS_TO_MPH + RATE_UP_MAX = 0.2 + RATE_DOWN_MAX = 0.2 + + accel = actuators.accel * _CV # m/s/s to mph/s + speed_setpoint = int(round(CS.out.cruiseState.speed * _CV)) + + button = CruiseButtons.INIT + if speed_setpoint == CS.CP.minEnableSpeed and accel < -1: + button = CruiseButtons.CANCEL + controller.apply_speed = 0 + rate = 0.04 + elif accel < 0: + button = CruiseButtons.DECEL_SET + if speed_setpoint > (CS.out.vEgo * _CV) + 3.0: # If accel is changing directions, bring set speed to current speed as fast as possible + rate = RATE_DOWN_MAX + else: + rate = max(-1 / accel, RATE_DOWN_MAX) + controller.apply_speed = (speed_setpoint - 1) / _CV + elif accel > 0: + button = CruiseButtons.RES_ACCEL + if speed_setpoint < (CS.out.vEgo * _CV) - 3.0: + rate = RATE_UP_MAX + else: + rate = max(1 / accel, RATE_UP_MAX) + controller.apply_speed = (speed_setpoint + 1) / _CV + else: + controller.apply_speed = speed_setpoint / _CV + rate = float('inf') + + return button, rate + + +def _create_gm_cc_spam_command_velocity(controller, CS, actuators): + _CV = CV.MS_TO_MPH + speed_desired = int(round(actuators.speed * _CV)) + speed_setpoint = int(round(CS.out.cruiseState.speed * _CV)) + + if speed_desired > speed_setpoint: + button = CruiseButtons.RES_ACCEL + controller.apply_speed = (speed_setpoint + 1) / _CV + elif speed_desired < speed_setpoint: + button = CruiseButtons.DECEL_SET + controller.apply_speed = (speed_setpoint - 1) / _CV + else: + button = CruiseButtons.INIT + controller.apply_speed = speed_setpoint / _CV + + return button + + +def create_gm_cc_spam_command(packer, controller, CS, actuators, mode: Literal["velocity", "accel"] = "accel"): + if mode == "velocity": + button = _create_gm_cc_spam_command_velocity(controller, CS, actuators) + rate = 0.04 + elif mode == "accel": + button, rate = _create_gm_cc_spam_command_accel(controller, CS, actuators) + else: + raise ValueError("Invalid mode. Use 'velocity' or 'accel'.") + + # Check rlogs closely - our message shouldn't show up on the pt bus for us + # Or bus 2, since we're forwarding... but I think it does + if (button != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate): + controller.last_button_frame = controller.frame + idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV + return [create_buttons(packer, CanBus.POWERTRAIN, idx, button)] + else: + return [] diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 38adf80d6..7c57c8250 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -7,7 +7,7 @@ from opendbc.car.common.conversions import Conversions as CV from opendbc.car.gm.carcontroller import CarController from opendbc.car.gm.carstate import CarState from opendbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG, CAMERA_DATA_HEADER_MSG -from opendbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags +from opendbc.car.gm.values import ALT_ACCS, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, EV_CAR, SDGM_CAR, CarControllerParams, CanBus, GMFlags, GMSafetyFlags from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LateralAccelFromTorqueCallbackType TransmissionType = structs.CarParams.TransmissionType @@ -16,9 +16,16 @@ NetworkLocation = structs.CarParams.NetworkLocation NON_LINEAR_TORQUE_PARAMS = { CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178], CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772], - CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122] + CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122], + + # OPGM variables + CAR.CHEVROLET_BOLT_2017: [2.24, 1.1, 0.28, -0.07], + CAR.CHEVROLET_BOLT_2018: [1.8, 1.1, 0.3, -0.045] } +# OPGM variables +PEDAL_MSG = 0x201 + class CarInterface(CarInterfaceBase): CarState = CarState @@ -149,6 +156,11 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 ret.longitudinalActuatorDelay = 0.5 # large delay to initially start braking + # OPGM variables + if PEDAL_MSG in fingerprint[0]: + ret.enableGasInterceptorDEPRECATED = True + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_GAS_INTERCEPTOR.value + if candidate == CAR.CHEVROLET_VOLT: ret.lateralTuning.pid.kpBP = [0., 40.] ret.lateralTuning.pid.kpV = [0., 0.17] @@ -157,6 +169,9 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_volt() ret.steerActuatorDelay = 0.2 + # OPGM variables + ret.minEnableSpeed = -1 + elif candidate == CAR.GMC_ACADIA: ret.minEnableSpeed = -1. # engage speed is decided by pcm ret.steerActuatorDelay = 0.2 @@ -180,10 +195,19 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - elif candidate == CAR.CHEVROLET_BOLT_EUV: + elif candidate in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_2017, CAR.CHEVROLET_BOLT_2018, CAR.CHEVROLET_BOLT_CC): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + # OPGM variables + if ret.enableGasInterceptorDEPRECATED: + # ACC Bolts use pedal for full longitudinal control, not just sng + ret.flags |= GMFlags.PEDAL_LONG.value + ret.longitudinalTuning.kiBP = [0.0, 3., 6., 35.] + ret.longitudinalTuning.kiV = [0.125, 0.175, 0.225, 0.33] + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PEDAL_LONG.value + ret.stoppingDecelRate = 0.8 + elif candidate == CAR.CHEVROLET_SILVERADO: # On the Bolt, the ECM and camera independently check that you are either above 5 kph or at a stop # with foot on brake to allow engagement, but this platform only has that check in the camera. @@ -192,10 +216,10 @@ class CarInterface(CarInterfaceBase): ret.minEnableSpeed = -1. CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - elif candidate == CAR.CHEVROLET_EQUINOX: + elif candidate in (CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_EQUINOX_CC): CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - elif candidate == CAR.CHEVROLET_TRAILBLAZER: + elif candidate in (CAR.CHEVROLET_TRAILBLAZER, CAR.CHEVROLET_TRAILBLAZER_CC): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) @@ -217,4 +241,39 @@ class CarInterface(CarInterfaceBase): CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) ret.dashcamOnly = True # Needs steerRatio, tireStiffness, and lat accel factor tuning + # OPGM variables + elif candidate in (CAR.CHEVROLET_MALIBU, CAR.CHEVROLET_MALIBU_CC): + ret.steerActuatorDelay = 0.2 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + + if ret.enableGasInterceptorDEPRECATED: + ret.autoResumeSng = True + ret.minEnableSpeed = -1 + ret.networkLocation = NetworkLocation.fwdCamera + ret.openpilotLongitudinalControl = True + ret.pcmCruise = False + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.HW_CAM.value + + elif candidate in CC_ONLY_CAR: + ret.alphaLongitudinalAvailable = True + ret.longitudinalActuatorDelay = 1. # TODO: measure this + ret.longitudinalTuning.deadzoneBPDEPRECATED = [0.] + ret.longitudinalTuning.deadzoneVDEPRECATED = [0.56] # == 2 km/h/s, 1.25 mph/s + ret.longitudinalTuning.kiBP = [0.] + ret.longitudinalTuning.kiV = [0.1] + ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph + ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed + ret.minEnableSpeed = 24 * CV.MPH_TO_MS + ret.pcmCruise = True + ret.radarUnavailable = True + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_CC_LONG.value + ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate) + + if alpha_long: + ret.flags |= GMFlags.CC_LONG.value + ret.openpilotLongitudinalControl = True + + if candidate in CC_ONLY_CAR: + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value + return ret diff --git a/opendbc_repo/opendbc/car/gm/tests/test_gm.py b/opendbc_repo/opendbc/car/gm/tests/test_gm.py index c14b9bd24..14ce81628 100644 --- a/opendbc_repo/opendbc/car/gm/tests/test_gm.py +++ b/opendbc_repo/opendbc/car/gm/tests/test_gm.py @@ -1,7 +1,7 @@ from parameterized import parameterized from opendbc.car.gm.fingerprints import FINGERPRINTS -from opendbc.car.gm.values import CAMERA_ACC_CAR, GM_RX_OFFSET +from opendbc.car.gm.values import CAMERA_ACC_CAR, CC_ONLY_CAR, GM_RX_OFFSET CAMERA_DIAGNOSTIC_ADDRESS = 0x24b @@ -14,7 +14,7 @@ class TestGMFingerprint: assert all(len(finger) for finger in fingerprints) # The camera can sometimes be communicating on startup - if car_model in CAMERA_ACC_CAR: + if car_model in CAMERA_ACC_CAR - CC_ONLY_CAR: for finger in fingerprints: for required_addr in (CAMERA_DIAGNOSTIC_ADDRESS, CAMERA_DIAGNOSTIC_ADDRESS + GM_RX_OFFSET): assert finger.get(required_addr) == 8, required_addr diff --git a/opendbc_repo/opendbc/car/gm/values.py b/opendbc_repo/opendbc/car/gm/values.py index 9101e2f65..ca72359c9 100644 --- a/opendbc_repo/opendbc/car/gm/values.py +++ b/opendbc_repo/opendbc/car/gm/values.py @@ -36,7 +36,7 @@ class CarControllerParams: # Gas/brake lookups self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen - if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR): + if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR) and CP.carFingerprint not in CC_ONLY_CAR: self.MAX_GAS = 1346.0 self.MAX_ACC_REGEN = -540.0 self.INACTIVE_REGEN = -500.0 @@ -64,6 +64,12 @@ class GMSafetyFlags(IntFlag): HW_CAM_LONG = 2 EV = 4 + # OPGM variables + FLAG_GM_CC_LONG = 8 + FLAG_GM_GAS_INTERCEPTOR = 16 + FLAG_GM_NO_ACC = 32 + FLAG_GM_PEDAL_LONG = 64 + class Footnote(Enum): SETUP = CarFootnote( @@ -121,7 +127,7 @@ class CAR(Platforms): ) CHEVROLET_VOLT = GMASCMPlatformConfig( [GMCarDocs("Chevrolet Volt 2017-18", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")], - GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=17.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469), + GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=17.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469, minEnableSpeed=-1), ) CADILLAC_ATS = GMASCMPlatformConfig( [GMCarDocs("Cadillac ATS Premium Performance 2018")], @@ -193,6 +199,52 @@ class CAR(Platforms): [GMCarDocs("GMC Yukon 2019-20", "Adaptive Cruise Control (ACC) & LKAS")], GMCarSpecs(mass=2490, wheelbase=2.94, steerRatio=17.3, centerToFrontRatio=0.5, tireStiffnessFactor=1.0), ) + # OPGM variables + # Separate car def is required when there is no ASCM + # (for now) unless there is a way to detect it when it has been unplugged... + # CHEVROLET_VOLT_CC = GMPlatformConfig( + # [GMCarDocs("Chevrolet Volt LT 2017-18")], + # CHEVROLET_VOLT.specs, + # ) + CADILLAC_CT6_CC = GMPlatformConfig( + [GMCarDocs("Cadillac CT6 2018 (NO ACC)")], + CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4), + ) + CADILLAC_XT5_CC = GMPlatformConfig( + [GMCarDocs("Cadillac XT5 2018 (NO ACC)")], + CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5), + ) + CHEVROLET_BOLT_2017 = GMPlatformConfig( + [GMCarDocs("Chevrolet Bolt EV 2017")], + CHEVROLET_BOLT_EUV.specs, + ) + CHEVROLET_BOLT_2018 = GMPlatformConfig( + [GMCarDocs("Chevrolet Bolt EV 2018-21")], + CHEVROLET_BOLT_EUV.specs, + ) + CHEVROLET_BOLT_CC = GMPlatformConfig( + [ + GMCarDocs("Chevrolet Bolt EUV LT 2022-23"), + GMCarDocs("Chevrolet Bolt EV LT 2022-23"), + ], + CHEVROLET_BOLT_EUV.specs, + ) + CHEVROLET_EQUINOX_CC = GMPlatformConfig( + [GMCarDocs("Chevrolet Equinox 2019-22 (NO ACC)")], + CHEVROLET_EQUINOX.specs, + ) + CHEVROLET_MALIBU_CC = GMPlatformConfig( + [GMCarDocs("Chevrolet Malibu 2018 (NO ACC)")], + CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4), + ) + CHEVROLET_SUBURBAN_CC = GMPlatformConfig( + [GMCarDocs("Chevrolet Suburban 2016-20")], + CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49), + ) + CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig( + [GMCarDocs("Chevrolet Trailblazer 2021-22 (NO ACC)")], + CHEVROLET_TRAILBLAZER.specs, + ) class CruiseButtons: @@ -220,6 +272,12 @@ class CanBus: DROPPED = 192 +# OPGM variables +class GMFlags(IntFlag): + PEDAL_LONG = 1 + CC_LONG = 2 + + # In a Data Module, an identifier is a string used to recognize an object, # either by itself or together with the identifiers of parent objects. # Each returns a 4 byte hex representation of the decimal part number. `b"\x02\x8c\xf0'"` -> 42790951 @@ -283,4 +341,12 @@ SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_TRAVERSE} STEER_THRESHOLD = 1.0 +# OPGM variables +CC_ONLY_CAR = {CAR.CHEVROLET_BOLT_2017, CAR.CHEVROLET_BOLT_2018, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, + CAR.CHEVROLET_SUBURBAN_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CHEVROLET_MALIBU_CC, + CAR.CADILLAC_XT5_CC} +CAMERA_ACC_CAR.update(CC_ONLY_CAR) + +EV_CAR.update(CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_BOLT_EUV) + DBC = CAR.create_dbc_map() diff --git a/opendbc_repo/opendbc/car/tests/routes.py b/opendbc_repo/opendbc/car/tests/routes.py index 01bcd5b30..31f582898 100644 --- a/opendbc_repo/opendbc/car/tests/routes.py +++ b/opendbc_repo/opendbc/car/tests/routes.py @@ -1,7 +1,7 @@ from typing import NamedTuple from opendbc.car.chrysler.values import CAR as CHRYSLER -from opendbc.car.gm.values import CAR as GM +from opendbc.car.gm.values import CAR as GM, CC_ONLY_CAR from opendbc.car.ford.values import CAR as FORD from opendbc.car.honda.values import CAR as HONDA from opendbc.car.hyundai.values import CAR as HYUNDAI @@ -40,6 +40,9 @@ non_tested_cars = [ ] +# OPGM variables +non_tested_cars.extend(CC_ONLY_CAR) + class CarTestRoute(NamedTuple): route: str diff --git a/opendbc_repo/opendbc/car/torque_data/override.toml b/opendbc_repo/opendbc/car/torque_data/override.toml index 69cc6048d..c44d1d9f6 100644 --- a/opendbc_repo/opendbc/car/torque_data/override.toml +++ b/opendbc_repo/opendbc/car/torque_data/override.toml @@ -99,3 +99,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] # Manually checked "HONDA_CIVIC_2022" = [2.5, 1.2, 0.15] "HONDA_HRV_3G" = [2.5, 1.2, 0.2] + +# OPGM variables +"CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075] diff --git a/opendbc_repo/opendbc/car/torque_data/substitute.toml b/opendbc_repo/opendbc/car/torque_data/substitute.toml index db26c1a01..238dd7c4a 100644 --- a/opendbc_repo/opendbc/car/torque_data/substitute.toml +++ b/opendbc_repo/opendbc/car/torque_data/substitute.toml @@ -85,3 +85,13 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "SUBARU_FORESTER_PREGLOBAL" = "SUBARU_IMPREZA" "SUBARU_LEGACY_PREGLOBAL" = "SUBARU_IMPREZA" "SUBARU_ASCENT" = "SUBARU_FORESTER" + +# OPGM variables +"CADILLAC_CT6_CC" = "CHEVROLET_VOLT" +"CADILLAC_XT5_CC" = "GMC_ACADIA" +"CHEVROLET_BOLT_2017" = "CHEVROLET_BOLT_EUV" +"CHEVROLET_BOLT_2018" = "CHEVROLET_BOLT_EUV" +"CHEVROLET_BOLT_CC" = "CHEVROLET_BOLT_EUV" +"CHEVROLET_EQUINOX_CC" = "CHEVROLET_EQUINOX" +"CHEVROLET_SUBURBAN_CC" = "CHEVROLET_SILVERADO" +"CHEVROLET_TRAILBLAZER_CC" = "CHEVROLET_TRAILBLAZER" diff --git a/opendbc_repo/opendbc/dbc/generator/gm/gm_global_a_powertrain.dbc b/opendbc_repo/opendbc/dbc/generator/gm/gm_global_a_powertrain.dbc index e9a469e09..297c4686c 100644 --- a/opendbc_repo/opendbc/dbc/generator/gm/gm_global_a_powertrain.dbc +++ b/opendbc_repo/opendbc/dbc/generator/gm/gm_global_a_powertrain.dbc @@ -1,4 +1,5 @@ +CM_ "IMPORT _community.dbc"; VERSION "" diff --git a/opendbc_repo/opendbc/safety/declarations.h b/opendbc_repo/opendbc/safety/declarations.h index a29b5d296..b83b35fc0 100644 --- a/opendbc_repo/opendbc/safety/declarations.h +++ b/opendbc_repo/opendbc/safety/declarations.h @@ -247,6 +247,9 @@ void speed_mismatch_check(const float speed_2); void safety_tick(const safety_config *safety_config); +// OPGM variables +bool longitudinal_interceptor_checks(const CANPacket_t *to_send); + // This can be set by the safety hooks extern bool controls_allowed; extern bool relay_malfunction; @@ -285,6 +288,9 @@ extern uint32_t ts_angle_check_last; extern int desired_angle_last; extern struct sample_t angle_meas; // last 6 steer angles/curvatures +// OPGM variables +extern bool enable_gas_interceptor; + // Alt experiences can be set with a USB command // It enables features that allow alternative experiences, like not disengaging on gas press // It is only either 0 or 1 on mainline comma.ai openpilot diff --git a/opendbc_repo/opendbc/safety/longitudinal.h b/opendbc_repo/opendbc/safety/longitudinal.h index 281099609..71495c969 100644 --- a/opendbc_repo/opendbc/safety/longitudinal.h +++ b/opendbc_repo/opendbc/safety/longitudinal.h @@ -33,3 +33,8 @@ bool longitudinal_brake_checks(int desired_brake, const LongitudinalLimits limit violation |= desired_brake > limits.max_brake; return violation; } + +// OPGM variables +bool longitudinal_interceptor_checks(const CANPacket_t *msg) { + return (!get_longitudinal_allowed() || brake_pressed_prev) && (msg->data[0] || msg->data[1]); +} diff --git a/opendbc_repo/opendbc/safety/modes/gm.h b/opendbc_repo/opendbc/safety/modes/gm.h index aa0cdac65..a4004e42c 100644 --- a/opendbc_repo/opendbc/safety/modes/gm.h +++ b/opendbc_repo/opendbc/safety/modes/gm.h @@ -7,11 +7,14 @@ {.msg = {{0x184, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ {.msg = {{0x34A, 0, 5, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ {.msg = {{0x1E1, 0, 7, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ + /* OPGM Variables */ \ + {.msg = {{0x1C4, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ + {.msg = {{0xC9, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ + +#define GM_ACC_RX_CHECKS \ {.msg = {{0xBE, 0, 6, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, /* Volt, Silverado, Acadia Denali */ \ {0xBE, 0, 7, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, /* Bolt EUV */ \ {0xBE, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}}}, /* Escalade */ \ - {.msg = {{0x1C4, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ - {.msg = {{0xC9, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \ static const LongitudinalLimits *gm_long_limits; @@ -29,9 +32,17 @@ typedef enum { static GmHardware gm_hw = GM_ASCM; static bool gm_pcm_cruise = false; +// OPGM variables +static bool gm_cc_long = false; +static bool gm_has_acc = true; +static bool gm_pedal_long = false; + static void gm_rx_hook(const CANPacket_t *msg) { const int GM_STANDSTILL_THRSLD = 10; // 0.311kph + // OPGM variables + const int GM_GAS_INTERCEPTOR_THRESHOLD = 550; + if (msg->bus == 0U) { if (msg->addr == 0x184U) { int torque_driver_new = ((msg->data[6] & 0x7U) << 8) | msg->data[7]; @@ -48,7 +59,7 @@ static void gm_rx_hook(const CANPacket_t *msg) { } // ACC steering wheel buttons (GM_CAM is tied to the PCM) - if ((msg->addr == 0x1E1U) && !gm_pcm_cruise) { + if ((msg->addr == 0x1E1U) && (!gm_pcm_cruise || gm_cc_long)) { int button = (msg->data[5] & 0x70U) >> 4; // enter controls on falling edge of set or rising edge of resume (avoids fault) @@ -77,10 +88,12 @@ static void gm_rx_hook(const CANPacket_t *msg) { } if (msg->addr == 0x1C4U) { - gas_pressed = msg->data[5] != 0U; + if (!enable_gas_interceptor) { + gas_pressed = msg->data[5] != 0U; + } // enter controls on rising edge of ACC, exit controls when ACC off - if (gm_pcm_cruise) { + if (gm_pcm_cruise && gm_has_acc) { bool cruise_engaged = (msg->data[1] >> 5) != 0U; pcm_cruise_check(cruise_engaged); } @@ -89,6 +102,26 @@ static void gm_rx_hook(const CANPacket_t *msg) { if (msg->addr == 0xBDU) { regen_braking = (msg->data[0] >> 4) != 0U; } + + // OPGM variables + // Cruise check for CC only cars + if ((msg->addr == 0x3D1U) && !gm_has_acc) { + bool cruise_engaged = (msg->data[4] >> 7) != 0U; + if (gm_cc_long) { + pcm_cruise_check(cruise_engaged); + } else { + cruise_engaged_prev = cruise_engaged; + } + } + + // Pedal Interceptor + if ((msg->addr == 0x201U) && enable_gas_interceptor) { + // Pedal Interceptor: average between 2 tracks + int track1 = ((msg->data[0] << 8) + msg->data[1]); + int track2 = ((msg->data[2] << 8) + msg->data[3]); + int gas_interceptor = (track1 + track2) / 2; + gas_pressed = gas_interceptor > GM_GAS_INTERCEPTOR_THRESHOLD; + } } } @@ -143,11 +176,24 @@ static bool gm_tx_hook(const CANPacket_t *msg) { } // BUTTONS: used for resume spamming and cruise cancellation with stock longitudinal - if ((msg->addr == 0x1E1U) && gm_pcm_cruise) { + if ((msg->addr == 0x1E1U) && (gm_pcm_cruise || gm_pedal_long || gm_cc_long)) { int button = (msg->data[5] >> 4) & 0x7U; - bool allowed_cancel = (button == 6) && cruise_engaged_prev; - if (!allowed_cancel) { + bool allowed_btn = (button == GM_BTN_CANCEL) && cruise_engaged_prev; + // For standard CC, allow spamming of SET / RESUME + if (gm_cc_long) { + allowed_btn |= cruise_engaged_prev && ((button == GM_BTN_SET) || (button == GM_BTN_RESUME) || (button == GM_BTN_UNPRESS)); + } + + if (!allowed_btn) { + tx = false; + } + } + + // OPGM variables + // GAS: safety check (interceptor) + if (msg->addr == 0x200U) { + if (longitudinal_interceptor_checks(msg)) { tx = false; } } @@ -171,7 +217,10 @@ static safety_config gm_init(uint16_t param) { static const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x409, 0, 7, .check_relay = false}, {0x40A, 0, 7, .check_relay = false}, {0x2CB, 0, 8, .check_relay = true}, {0x370, 0, 6, .check_relay = false}, // pt bus {0xA1, 1, 7, .check_relay = false}, {0x306, 1, 8, .check_relay = false}, {0x308, 1, 7, .check_relay = false}, {0x310, 1, 2, .check_relay = false}, // obs bus - {0x315, 2, 5, .check_relay = false}}; // ch bus + {0x315, 2, 5, .check_relay = false}, // ch bus + // OPGM Variables + {0x200, 0, 6, .check_relay = false}, + {0x1E1, 0, 7, .check_relay = false}}; // pt bus static const LongitudinalLimits GM_CAM_LONG_LIMITS = { @@ -183,20 +232,53 @@ static safety_config gm_init(uint16_t param) { // block PSCMStatus (0x184); forwarded through openpilot to hide an alert from the camera static const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x315, 0, 5, .check_relay = true}, {0x2CB, 0, 8, .check_relay = true}, {0x370, 0, 6, .check_relay = true}, // pt bus - {0x184, 2, 8, .check_relay = true}}; // camera bus + {0x184, 2, 8, .check_relay = true}, // camera bus + // OPGM Variables + {0x200, 0, 6, .check_relay = false}, {0x1E1, 0, 7, .check_relay = false}}; // pt bus static RxCheck gm_rx_checks[] = { GM_COMMON_RX_CHECKS + + // OPGM Variables + GM_ACC_RX_CHECKS }; static RxCheck gm_ev_rx_checks[] = { GM_COMMON_RX_CHECKS {.msg = {{0xBD, 0, 7, 40U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, + + // OPGM Variables + GM_ACC_RX_CHECKS }; static const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, // pt bus - {0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = true}}; // camera bus + {0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = true}, // camera bus + // OPGM Variables + {0x200, 0, 6, .check_relay = false}, + {0x1E1, 0, 7, .check_relay = false}}; // pt bus + + // OPGM Variables + static RxCheck gm_no_acc_ev_rx_checks[] = { + GM_COMMON_RX_CHECKS + {.msg = {{0xBD, 0, 7, 40U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, + {.msg = {{0x3D1, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // Non-ACC PCM + }; + + static RxCheck gm_no_acc_rx_checks[] = { + GM_COMMON_RX_CHECKS + {.msg = {{0x3D1, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // Non-ACC PCM + }; + + static RxCheck gm_pedal_rx_checks[] = { + GM_COMMON_RX_CHECKS + {.msg = {{0xBD, 0, 7, 40U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, + {.msg = {{0x3D1, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // Non-ACC PCM + {.msg = {{0x201, 0, 6, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // pedal + }; + + static const CanMsg GM_CC_LONG_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x1E1, 0, 7, .check_relay = false}, // pt bus + {0x184, 2, 8, .check_relay = true}, {0x1E1, 2, 7, .check_relay = false}}; // camera bus gm_hw = GET_FLAG(param, GM_PARAM_HW_CAM) ? GM_CAM : GM_ASCM; @@ -207,31 +289,52 @@ static safety_config gm_init(uint16_t param) { } else { } - bool gm_cam_long = false; - -#ifdef ALLOW_DEBUG const uint16_t GM_PARAM_HW_CAM_LONG = 2; - gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG); -#endif - gm_pcm_cruise = (gm_hw == GM_CAM) && !gm_cam_long; + bool gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG); + gm_pcm_cruise = (gm_hw == GM_CAM) && !gm_cam_long && !gm_pedal_long; + + // OPGM Variables + const uint16_t GM_PARAM_CC_LONG = 8; + gm_cc_long = GET_FLAG(param, GM_PARAM_CC_LONG); + + const uint16_t GM_PARAM_PEDAL_INTERCEPTOR = 16; + enable_gas_interceptor = GET_FLAG(param, GM_PARAM_PEDAL_INTERCEPTOR); + + const uint16_t GM_PARAM_NO_ACC = 32; + gm_has_acc = !GET_FLAG(param, GM_PARAM_NO_ACC); + + const uint16_t GM_PARAM_PEDAL_LONG = 64; + gm_pedal_long = GET_FLAG(param, GM_PARAM_PEDAL_LONG); safety_config ret; if (gm_hw == GM_CAM) { // FIXME: cppcheck thinks that gm_cam_long is always false. This is not true // if ALLOW_DEBUG is defined but cppcheck is run without ALLOW_DEBUG // cppcheck-suppress knownConditionTrueFalse - ret = gm_cam_long ? BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS) : BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS); + if (gm_cc_long) { + ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CC_LONG_TX_MSGS); + } else if (gm_cam_long) { + ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS); + } else { + ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS); + } } else { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_ASCM_TX_MSGS); } const bool gm_ev = GET_FLAG(param, GM_PARAM_EV); - if (gm_ev) { + if (enable_gas_interceptor) { + SET_RX_CHECKS(gm_pedal_rx_checks, ret); + } else if (!gm_has_acc && gm_ev) { + SET_RX_CHECKS(gm_no_acc_ev_rx_checks, ret); + } else if (!gm_has_acc && !gm_ev) { + SET_RX_CHECKS(gm_no_acc_rx_checks, ret); + } else if (gm_ev) { SET_RX_CHECKS(gm_ev_rx_checks, ret); } // ASCM does not forward any messages - if (gm_hw == GM_ASCM) { + if (gm_hw == GM_ASCM || gm_cc_long) { ret.disable_forwarding = true; } return ret; diff --git a/opendbc_repo/opendbc/safety/safety.h b/opendbc_repo/opendbc/safety/safety.h index 50376a417..6211ab2e8 100644 --- a/opendbc_repo/opendbc/safety/safety.h +++ b/opendbc_repo/opendbc/safety/safety.h @@ -91,6 +91,9 @@ uint16_t current_safety_param = 0; static const safety_hooks *current_hooks = &nooutput_hooks; safety_config current_safety_config; +// OPGM variables +bool enable_gas_interceptor = false; + static void generic_rx_checks(void); static void stock_ecu_check(bool stock_ecu_detected); @@ -482,6 +485,10 @@ int set_safety_hooks(uint16_t mode, uint16_t param) { current_safety_config.rx_checks[j].status = (RxStatus){0}; } } + + // OPGM variables + enable_gas_interceptor = false; + return set_status; } diff --git a/opendbc_repo/opendbc/safety/tests/common.py b/opendbc_repo/opendbc/safety/tests/common.py index ae2a30e1c..20f7cf7a6 100644 --- a/opendbc_repo/opendbc/safety/tests/common.py +++ b/opendbc_repo/opendbc/safety/tests/common.py @@ -886,7 +886,8 @@ class SafetyTest(SafetyTestBase): if {attr, current_test}.issubset({'TestVolkswagenPqSafety', 'TestVolkswagenPqStockSafety', 'TestVolkswagenPqLongSafety'}): continue if {attr, current_test}.issubset({'TestGmCameraSafety', 'TestGmCameraLongitudinalSafety', 'TestGmAscmSafety', - 'TestGmCameraEVSafety', 'TestGmCameraLongitudinalEVSafety', 'TestGmAscmEVSafety'}): + 'TestGmCameraEVSafety', 'TestGmCameraLongitudinalEVSafety', 'TestGmAscmEVSafety', + 'TestGmInterceptorSafety', 'TestGmCcLongitudinalSafety'}): continue if attr.startswith('TestFord') and current_test.startswith('TestFord'): continue @@ -1125,3 +1126,64 @@ class CarSafetyTest(SafetyTest): self.safety.safety_tick_current_safety_config() self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.safety_config_valid()) + + +# OPGM variables +class GasInterceptorSafetyTest(PandaSafetyTestBase): + + INTERCEPTOR_THRESHOLD = 0 + + cnt_gas_cmd = 0 + cnt_user_gas = 0 + + packer: CANPackerPanda + + @classmethod + def setUpClass(cls): + if cls.__name__ == "GasInterceptorSafetyTest" or cls.__name__.endswith("Base"): + cls.safety = None + raise unittest.SkipTest + + def _interceptor_gas_cmd(self, gas: int): + values: dict[str, float | int] = {"COUNTER_PEDAL": self.__class__.cnt_gas_cmd & 0xF} + if gas > 0: + values["GAS_COMMAND"] = gas * 255. + values["GAS_COMMAND2"] = gas * 255. + self.__class__.cnt_gas_cmd += 1 + return self.packer.make_can_msg_panda("GAS_COMMAND", 0, values) + + def _interceptor_user_gas(self, gas: int): + values = {"INTERCEPTOR_GAS": gas, "INTERCEPTOR_GAS2": gas, + "COUNTER_PEDAL": self.__class__.cnt_user_gas} + self.__class__.cnt_user_gas += 1 + return self.packer.make_can_msg_panda("GAS_SENSOR", 0, values) + + # Skip non-interceptor user gas tests + def test_prev_gas(self): + pass + + def test_no_disengage_on_gas(self): + pass + + def test_no_disengage_on_gas_interceptor(self): + for g in range(0x1000): + self._rx(self._interceptor_user_gas(0)) + self.safety.set_controls_allowed(True) + self._rx(self._interceptor_user_gas(g)) + self.assertTrue(self.safety.get_controls_allowed(), g) + + def test_allow_engage_with_gas_interceptor_pressed(self): + self._rx(self._interceptor_user_gas(0x1000)) + self.safety.set_controls_allowed(True) + self._rx(self._interceptor_user_gas(0x1000)) + self.assertTrue(self.safety.get_controls_allowed()) + + def test_gas_interceptor_safety_check(self): + for gas in np.arange(0, 4000, 100): + for controls_allowed in [True, False]: + self.safety.set_controls_allowed(controls_allowed) + if controls_allowed: + send = True + else: + send = gas == 0 + self.assertEqual(send, self._tx(self._interceptor_gas_cmd(gas))) diff --git a/opendbc_repo/opendbc/safety/tests/test_gm.py b/opendbc_repo/opendbc/safety/tests/test_gm.py index aae308f7e..007ec7341 100755 --- a/opendbc_repo/opendbc/safety/tests/test_gm.py +++ b/opendbc_repo/opendbc/safety/tests/test_gm.py @@ -228,5 +228,117 @@ class TestGmCameraLongitudinalEVSafety(TestGmCameraLongitudinalSafety, TestGmEVS pass +# OPGM variables +def interceptor_msg(gas, addr): + to_send = common.make_msg(0, addr, 6) + to_send[0].data[0] = (gas & 0xFF00) >> 8 + to_send[0].data[1] = gas & 0xFF + to_send[0].data[2] = (gas & 0xFF00) >> 8 + to_send[0].data[3] = gas & 0xFF + return to_send + + +class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafety, TestGmEVSafetyBase): + INTERCEPTOR_THRESHOLD = 550 + + def setUp(self): + self.packer = CANPackerPanda("gm_global_a_powertrain_generated") + self.packer_chassis = CANPackerPanda("gm_global_a_chassis") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks( + CarParams.SafetyModel.gm, + GMSafetyFlags.HW_CAM | GMSafetyFlags.FLAG_GM_NO_ACC | GMSafetyFlags.FLAG_GM_PEDAL_LONG | GMSafetyFlags.FLAG_GM_GAS_INTERCEPTOR | self.EXTRA_SAFETY_PARAM) + self.safety.init_tests() + + def test_pcm_sets_cruise_engaged(self): + for enabled in [True, False]: + self._rx(self._pcm_status_msg(enabled)) + self.assertEqual(enabled, self.safety.get_cruise_engaged_prev()) + + def test_no_pcm_enable(self): + self.safety.set_controls_allowed(False) + self.assertFalse(self.safety.get_controls_allowed()) + self._rx(self._pcm_status_msg(True)) + self.assertFalse(self.safety.get_controls_allowed()) + self.assertTrue(self.safety.get_cruise_engaged_prev()) + + def test_no_response_to_acc_pcm_message(self): + for enable in [True, False]: + self.safety.set_controls_allowed(enable) + self._rx(self.packer.make_can_msg_panda("AcceleratorPedal2", 0, {"CruiseState": True})) + self.assertEqual(enable, self.safety.get_controls_allowed()) + self._rx(self.packer.make_can_msg_panda("AcceleratorPedal2", 0, {"CruiseState": False})) + self.assertEqual(enable, self.safety.get_controls_allowed()) + + def test_buttons(self): + # Only CANCEL button is allowed while cruise is enabled + self.safety.set_controls_allowed(False) + for btn in range(8): + self.assertFalse(self._tx(self._button_msg(btn))) + + self.safety.set_controls_allowed(True) + for btn in range(8): + self.assertFalse(self._tx(self._button_msg(btn))) + + self.safety.set_controls_allowed(True) + for enabled in (True, False): + self._rx(self._pcm_status_msg(enabled)) + self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL))) + self.assertTrue(self.safety.get_controls_allowed()) + + def test_fwd_hook(self): + pass + + def test_disable_control_allowed_from_cruise(self): + pass + + def test_enable_control_allowed_from_cruise(self): + pass + + def _interceptor_gas_cmd(self, gas): + return interceptor_msg(gas, 0x200) + + def _interceptor_user_gas(self, gas): + return interceptor_msg(gas, 0x201) + + def _pcm_status_msg(self, enable): + values = {"CruiseActive": enable} + return self.packer.make_can_msg_panda("ECMCruiseControl", 0, values) + + +class TestGmCcLongitudinalSafety(TestGmCameraSafety): + TX_MSGS = [[0x180, 0], [0x1E1, 0], [0x184, 2]] + FWD_BLACKLISTED_ADDRS = {2: [0x180], 0: [0x184]} # block LKAS message and PSCMStatus + BUTTONS_BUS = 0 # tx only + + def setUp(self): + self.packer = CANPackerPanda("gm_global_a_powertrain_generated") + self.packer_chassis = CANPackerPanda("gm_global_a_chassis") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | GMSafetyFlags.FLAG_GM_NO_ACC | GMSafetyFlags.FLAG_GM_CC_LONG) + self.safety.init_tests() + + def _pcm_status_msg(self, enable): + values = {"CruiseActive": enable} + return self.packer.make_can_msg_panda("ECMCruiseControl", 0, values) + + def test_fwd_hook(self): + pass + + def test_buttons(self): + self.safety.set_controls_allowed(0) + for btn in range(8): + self.assertFalse(self._tx(self._button_msg(btn))) + + self.safety.set_controls_allowed(1) + for btn in range(8): + self.assertFalse(self._tx(self._button_msg(btn))) + + for enabled in (True, False): + for btn in (Buttons.RES_ACCEL, Buttons.DECEL_SET, Buttons.CANCEL): + self._rx(self._pcm_status_msg(enabled)) + self.assertEqual(enabled, self._tx(self._button_msg(btn))) + + if __name__ == "__main__": unittest.main() diff --git a/selfdrive/car/car_specific.py b/selfdrive/car/car_specific.py index 6210983d9..1e5107f8a 100644 --- a/selfdrive/car/car_specific.py +++ b/selfdrive/car/car_specific.py @@ -1,6 +1,7 @@ from cereal import car, log import cereal.messaging as messaging from opendbc.car import DT_CTRL, structs +from opendbc.car.gm.values import GMFlags from opendbc.car.interfaces import MAX_CTRL_SPEED from openpilot.selfdrive.selfdrived.events import Events @@ -110,9 +111,13 @@ class CarSpecificEvents: if CS.vEgo < self.CP.minEnableSpeed and not (CS.standstill and CS.brake >= 20 and self.CP.networkLocation == NetworkLocation.fwdCamera): events.add(EventName.belowEngageSpeed) - if CS.cruiseState.standstill: + if CS.cruiseState.standstill and not self.CP.autoResumeSng: events.add(EventName.resumeRequired) + # OPGM variables + if (self.CP.flags & GMFlags.CC_LONG) and CS.vEgo < self.CP.minEnableSpeed and CS.cruiseState.enabled: + events.add(EventName.speedTooLow) + elif self.CP.brand == 'volkswagen': events = self.create_common_events(CS, CS_prev, extra_gears=extra_gears, pcm_enable=self.CP.pcmCruise) diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 27b04ae65..42cdc1ff0 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -11,7 +11,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper from openpilot.common.swaglog import cloudlog, ForwardingHandler -from opendbc.car import DT_CTRL, structs +from opendbc.car import DT_CTRL, ButtonType, structs from opendbc.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from opendbc.car.carlog import carlog from opendbc.car.fw_versions import ObdCallback @@ -159,6 +159,9 @@ class Car: # card is driven by can recv, expected at 100Hz self.rk = Ratekeeper(100, print_delay_threshold=None) + # OPGM variables + self.resume_prev_button = False + def state_update(self) -> tuple[car.CarState, structs.RadarDataT | None]: """carState update loop, driven by can""" @@ -187,12 +190,18 @@ class Car: self.v_cruise_helper.update_v_cruise(CS, self.sm['carControl'].enabled, self.is_metric) if self.sm['carControl'].enabled and not self.CC_prev.enabled: # Use CarState w/ buttons from the step selfdrived enables on - self.v_cruise_helper.initialize_v_cruise(self.CS_prev, self.experimental_mode) + self.v_cruise_helper.initialize_v_cruise(self.CS_prev, self.experimental_mode, self.resume_prev_button) # TODO: mirror the carState.cruiseState struct? CS.vCruise = float(self.v_cruise_helper.v_cruise_kph) CS.vCruiseCluster = float(self.v_cruise_helper.v_cruise_cluster_kph) + # OPGM variables + if any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in CS.buttonEvents): + self.resume_prev_button = True + elif any(be.type in (ButtonType.decelCruise, ButtonType.setCruise) for be in CS.buttonEvents): + self.resume_prev_button = False + return CS, RD def state_publish(self, CS: car.CarState, RD: structs.RadarDataT | None): diff --git a/selfdrive/car/cruise.py b/selfdrive/car/cruise.py index 0d761844b..644337b93 100644 --- a/selfdrive/car/cruise.py +++ b/selfdrive/car/cruise.py @@ -2,6 +2,7 @@ import math import numpy as np from cereal import car +from opendbc.car.gm.values import CC_ONLY_CAR, GMFlags from openpilot.common.constants import CV @@ -37,6 +38,9 @@ class VCruiseHelper: self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers} + # OPGM variables + self.gm_cc_only = self.CP.carFingerprint in CC_ONLY_CAR and self.CP.flags & GMFlags.CC_LONG.value + @property def v_cruise_initialized(self): return self.v_cruise_kph != V_CRUISE_UNSET @@ -45,7 +49,7 @@ class VCruiseHelper: self.v_cruise_kph_last = self.v_cruise_kph if CS.cruiseState.available: - if not self.CP.pcmCruise: + if self.gm_cc_only or not self.CP.pcmCruise: # if stock cruise is completely disabled, then we can use our own set speed logic self._update_v_cruise_non_pcm(CS, enabled, is_metric) self.v_cruise_cluster_kph = self.v_cruise_kph @@ -123,14 +127,15 @@ class VCruiseHelper: self.button_timers[b.type.raw] = 1 if b.pressed else 0 self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled} - def initialize_v_cruise(self, CS, experimental_mode: bool) -> None: + def initialize_v_cruise(self, CS, experimental_mode: bool, resume_prev_button: bool) -> None: # initializing is handled by the PCM - if self.CP.pcmCruise: + if self.CP.pcmCruise and not self.gm_cc_only: return initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode else V_CRUISE_INITIAL - if any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) and self.v_cruise_initialized: + if (any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) + and self.v_cruise_initialized or (self.gm_cc_only and resume_prev_button)): self.v_cruise_kph = self.v_cruise_kph_last else: self.v_cruise_kph = int(round(np.clip(CS.vEgo * CV.MS_TO_KPH, initial, V_CRUISE_MAX))) diff --git a/selfdrive/car/tests/test_cruise_speed.py b/selfdrive/car/tests/test_cruise_speed.py index aa70e49f5..86965ef14 100644 --- a/selfdrive/car/tests/test_cruise_speed.py +++ b/selfdrive/car/tests/test_cruise_speed.py @@ -59,7 +59,7 @@ class TestVCruiseHelper: def enable(self, v_ego, experimental_mode): # Simulates user pressing set with a current speed - self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego), experimental_mode) + self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego), experimental_mode, False) def test_adjust_speed(self): """ diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 9e31ac152..1599c7c63 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -126,6 +126,11 @@ class Controls: curvature_limited, lat_delay) actuators.torque = float(steer) actuators.steeringAngleDeg = float(steeringAngleDeg) + + # OPGM variables + if len(long_plan.speeds): + actuators.speed = long_plan.speeds[-1] + # Ensure no NaNs/Infs for p in ACTUATOR_FIELDS: attr = getattr(actuators, p)