Skip to content

Commit

Permalink
New SDGM Harness
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettpall committed Nov 13, 2024
1 parent af2a9e1 commit 9e674a6
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 174 deletions.
12 changes: 1 addition & 11 deletions panda/board/drivers/can_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ void ignition_can_hook(CANPacket_t *to_push) {
if (bus == 0) {
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);

// GM exception
if ((addr == 0x1F1) && (len == 8)) {
// SystemPowerMode (2=Run, 3=Crank Request)
Expand All @@ -220,16 +220,6 @@ void ignition_can_hook(CANPacket_t *to_push) {
ignition_can = (GET_BYTE(to_push, 0) >> 5) == 0x6U;
ignition_can_cnt = 0U;
}

} else if (bus == 2) {
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
// GM exception, SDGM cars have this message on bus 2
if ((addr == 0x1F1) && (len == 8)) {
// SystemPowerMode (2=Run, 3=Crank Request)
ignition_can = (GET_BYTE(to_push, 0) & 0x2U) != 0U;
ignition_can_cnt = 0U;
}
}
}

Expand Down
85 changes: 31 additions & 54 deletions panda/board/safety/safety_gm.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,27 @@ const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, {0x200, 0, 6}, {0x1E1, 0, 7}, /
const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x315, 0, 5}, {0x2CB, 0, 8}, {0x370, 0, 6}, {0x200, 0, 6}, // pt bus
{0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus

const CanMsg GM_SDGM_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, // pt bus
{0x184, 2, 8}}; // camera bus

const CanMsg GM_CC_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, // pt bus
{0x184, 2, 8}, {0x1E1, 2, 7}}; // camera bus

// TODO: do checksum and counter checks. Add correct timestep, 0.1s for now.
RxCheck gm_rx_checks[] = {
{.msg = {{0x184, 0, 8, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{0x34A, 0, 5, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{0x1E1, 0, 7, .frequency = 10U}, // Non-SDGM Car
{0x1E1, 2, 7, .frequency = 100000U}}}, // SDGM Car
{.msg = {{0xF1, 0, 6, .frequency = 10U}, // Non-SDGM Car
{0xF1, 2, 6, .frequency = 100000U}}}, // SDGM Car
{.msg = {{0x1E1, 0, 7, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{0xF1, 0, 6, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{0x1C4, 0, 8, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{0xC9, 0, 8, .frequency = 10U}, { 0 }, { 0 }}},
};

const uint16_t GM_PARAM_HW_CAM = 1;
const uint16_t GM_PARAM_HW_CAM_LONG = 2;
const uint16_t GM_PARAM_HW_SDGM = 4;
const uint16_t GM_PARAM_CC_LONG = 8;
const uint16_t GM_PARAM_HW_ASCM_LONG = 16;
const uint16_t GM_PARAM_NO_CAMERA = 32;
const uint16_t GM_PARAM_NO_ACC = 64;
const uint16_t GM_PARAM_PEDAL_LONG = 128; // TODO: this can be inferred
const uint16_t GM_PARAM_PEDAL_INTERCEPTOR = 256;
const uint16_t GM_PARAM_CC_LONG = 4;
const uint16_t GM_PARAM_HW_ASCM_LONG = 8;
const uint16_t GM_PARAM_NO_CAMERA = 16;
const uint16_t GM_PARAM_NO_ACC = 32;
const uint16_t GM_PARAM_PEDAL_LONG = 64; // TODO: this can be inferred
const uint16_t GM_PARAM_PEDAL_INTERCEPTOR = 128;

enum {
GM_BTN_UNPRESS = 1,
Expand All @@ -93,8 +87,7 @@ enum {

typedef enum {
GM_ASCM,
GM_CAM,
GM_SDGM
GM_CAM
} GmHardware;
GmHardware gm_hw = GM_ASCM;
bool gm_cam_long = false;
Expand All @@ -105,29 +98,7 @@ bool gm_cc_long = false;
bool gm_skip_relay_check = false;
bool gm_force_ascm = false;

static void handle_gm_wheel_buttons(const CANPacket_t *to_push) {
int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4;

// enter controls on falling edge of set or rising edge of resume (avoids fault)
bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET);
bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME);
if (set || res) {
controls_allowed = true;
}

// exit controls on cancel press
if (button == GM_BTN_CANCEL) {
controls_allowed = false;
}

cruise_button_prev = button;
}

static void gm_rx_hook(const CANPacket_t *to_push) {
if ((GET_BUS(to_push) == 2U) && (GET_ADDR(to_push) == 0x1E1) && (gm_hw == GM_SDGM)) {
// SDGM buttons are on bus 2
handle_gm_wheel_buttons(to_push);
}
if (GET_BUS(to_push) == 0U) {
int addr = GET_ADDR(to_push);

Expand All @@ -145,9 +116,23 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
vehicle_moving = (left_rear_speed > GM_STANDSTILL_THRSLD) || (right_rear_speed > GM_STANDSTILL_THRSLD);
}

// ACC steering wheel buttons (GM_CAM and GM_SDGM are tied to the PCM)
if ((addr == 0x1E1) && (!gm_pcm_cruise || gm_cc_long) && (gm_hw != GM_SDGM)) {
handle_gm_wheel_buttons(to_push);
// ACC steering wheel buttons (GM_CAM is tied to the PCM)
if ((addr == 0x1E1) && (!gm_pcm_cruise || gm_cc_long)) {
int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4;

// enter controls on falling edge of set or rising edge of resume (avoids fault)
bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET);
bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME);
if (set || res) {
controls_allowed = true;
}

// exit controls on cancel press
if (button == GM_BTN_CANCEL) {
controls_allowed = false;
}

cruise_button_prev = button;
}

// Reference for brake pressed signals:
Expand All @@ -156,7 +141,7 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
brake_pressed = GET_BYTE(to_push, 1) >= 8U;
}

if ((addr == 0xC9) && ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM))) {
if ((addr == 0xC9) && (gm_hw == GM_CAM)) {
brake_pressed = GET_BIT(to_push, 40U) != 0U;
}

Expand Down Expand Up @@ -276,7 +261,7 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
static int gm_fwd_hook(int bus_num, int addr) {
int bus_fwd = -1;

if ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM)) {
if (gm_hw == GM_CAM) {
if (bus_num == 0) {
// block PSCMStatus; forwarded through openpilot to hide an alert from the camera
bool is_pscm_msg = (addr == 0x184);
Expand All @@ -302,13 +287,7 @@ static int gm_fwd_hook(int bus_num, int addr) {
static safety_config gm_init(uint16_t param) {
sport_mode = alternative_experience & ALT_EXP_RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX;

if GET_FLAG(param, GM_PARAM_HW_CAM) {
gm_hw = GM_CAM;
} else if GET_FLAG(param, GM_PARAM_HW_SDGM) {
gm_hw = GM_SDGM;
} else {
gm_hw = GM_ASCM;
}
gm_hw = GET_FLAG(param, GM_PARAM_HW_CAM) ? GM_CAM : GM_ASCM;

gm_force_ascm = GET_FLAG(param, GM_PARAM_HW_ASCM_LONG);

Expand All @@ -318,7 +297,7 @@ static safety_config gm_init(uint16_t param) {
} else {
gm_long_limits = &GM_ASCM_LONG_LIMITS;
}
} else if ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM)) {
} else if (gm_hw == GM_CAM) {
if (sport_mode) {
gm_long_limits = &GM_CAM_LONG_LIMITS_SPORT;
} else {
Expand All @@ -330,7 +309,7 @@ static safety_config gm_init(uint16_t param) {
gm_pedal_long = GET_FLAG(param, GM_PARAM_PEDAL_LONG);
gm_cc_long = GET_FLAG(param, GM_PARAM_CC_LONG);
gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG) && !gm_cc_long;
gm_pcm_cruise = ((gm_hw == GM_CAM) && (!gm_cam_long || gm_cc_long) && !gm_force_ascm && !gm_pedal_long) || (gm_hw == GM_SDGM);
gm_pcm_cruise = ((gm_hw == GM_CAM) && (!gm_cam_long || gm_cc_long) && !gm_force_ascm && !gm_pedal_long);
gm_skip_relay_check = GET_FLAG(param, GM_PARAM_NO_CAMERA);
gm_has_acc = !GET_FLAG(param, GM_PARAM_NO_ACC);
enable_gas_interceptor = GET_FLAG(param, GM_PARAM_PEDAL_INTERCEPTOR);
Expand All @@ -344,8 +323,6 @@ static safety_config gm_init(uint16_t param) {
} else {
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS);
}
} else if (gm_hw == GM_SDGM) {
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_TX_MSGS);
}
return ret;
}
Expand Down
13 changes: 6 additions & 7 deletions panda/python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,12 @@ class Panda:

FLAG_GM_HW_CAM = 1
FLAG_GM_HW_CAM_LONG = 2
FLAG_GM_HW_SDGM = 4
FLAG_GM_CC_LONG = 8
FLAG_GM_HW_ASCM_LONG = 16
FLAG_GM_NO_CAMERA = 32
FLAG_GM_NO_ACC = 64
FLAG_GM_PEDAL_LONG = 128 # TODO: This can be inferred
FLAG_GM_GAS_INTERCEPTOR = 256
FLAG_GM_CC_LONG = 4
FLAG_GM_HW_ASCM_LONG = 8
FLAG_GM_NO_CAMERA = 16
FLAG_GM_NO_ACC = 32
FLAG_GM_PEDAL_LONG = 64 # TODO: This can be inferred
FLAG_GM_GAS_INTERCEPTOR = 128

FLAG_FORD_LONG_CONTROL = 1
FLAG_FORD_CANFD = 2
Expand Down
5 changes: 1 addition & 4 deletions selfdrive/car/gm/carcontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,7 @@ def update(self, CC, CS, now_nanos, frogpilot_toggles):
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
if self.CP.carFingerprint in SDGM_CAR:
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, CS.buttons_counter, CruiseButtons.CANCEL))
else:
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL))
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
Expand Down
98 changes: 26 additions & 72 deletions selfdrive/car/gm/carstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,9 @@ def update(self, pt_cp, cam_cp, loopback_cp, frogpilot_toggles):

self.prev_cruise_buttons = self.cruise_buttons
self.prev_distance_button = self.distance_button
if self.CP.carFingerprint not in SDGM_CAR:
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
else:
self.cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = cam_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = cam_cp.vl["ASCMSteeringButton"]["RollingCounter"]
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
# This is to avoid a fault where you engage while still moving backwards after shifting to D.
# An Equinox has been seen with an unsupported status (3), so only check if either wheel is in reverse (2)
Expand Down Expand Up @@ -113,32 +108,18 @@ def update(self, pt_cp, cam_cp, loopback_cp, frogpilot_toggles):
ret.steerFaultTemporary = self.lkas_status == 2
ret.steerFaultPermanent = self.lkas_status == 3

if self.CP.carFingerprint not in SDGM_CAR:
# 1 - open, 0 - closed
ret.doorOpen = (pt_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or
pt_cp.vl["BCMDoorBeltStatus"]["FrontRightDoor"] == 1 or
pt_cp.vl["BCMDoorBeltStatus"]["RearLeftDoor"] == 1 or
pt_cp.vl["BCMDoorBeltStatus"]["RearRightDoor"] == 1)
# 1 - open, 0 - closed
ret.doorOpen = (pt_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or
pt_cp.vl["BCMDoorBeltStatus"]["FrontRightDoor"] == 1 or
pt_cp.vl["BCMDoorBeltStatus"]["RearLeftDoor"] == 1 or
pt_cp.vl["BCMDoorBeltStatus"]["RearRightDoor"] == 1)

# 1 - latched
ret.seatbeltUnlatched = pt_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0
ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1
ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2
# 1 - latched
ret.seatbeltUnlatched = pt_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0
ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1
ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2

ret.parkingBrake = pt_cp.vl["BCMGeneralPlatformStatus"]["ParkBrakeSwActive"] == 1
else:
# 1 - open, 0 - closed
ret.doorOpen = (cam_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or
cam_cp.vl["BCMDoorBeltStatus"]["FrontRightDoor"] == 1 or
cam_cp.vl["BCMDoorBeltStatus"]["RearLeftDoor"] == 1 or
cam_cp.vl["BCMDoorBeltStatus"]["RearRightDoor"] == 1)

# 1 - latched
ret.seatbeltUnlatched = cam_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0
ret.leftBlinker = cam_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1
ret.rightBlinker = cam_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2

ret.parkingBrake = cam_cp.vl["BCMGeneralPlatformStatus"]["ParkBrakeSwActive"] == 1
ret.parkingBrake = pt_cp.vl["BCMGeneralPlatformStatus"]["ParkBrakeSwActive"] == 1
ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0
ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1
ret.accFaulted = (pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED or
Expand All @@ -151,8 +132,6 @@ def update(self, pt_cp, cam_cp, loopback_cp, frogpilot_toggles):
ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS
if self.CP.carFingerprint not in SDGM_CAR:
ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
else:
ret.stockAeb = False
# openpilot controls nonAdaptive when not pcmCruise
if self.CP.pcmCruise:
ret.cruiseState.nonAdaptive = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCruiseState"] not in (2, 3)
Expand All @@ -162,21 +141,14 @@ def update(self, pt_cp, cam_cp, loopback_cp, frogpilot_toggles):
ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0

if self.CP.enableBsm:
if self.CP.carFingerprint not in SDGM_CAR:
ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1
ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1
else:
ret.leftBlindspot = cam_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1
ret.rightBlindspot = cam_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1
ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1
ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1

# FrogPilot CarState functions
fp_ret.hasMenu = not (self.CP.flags & GMFlags.NO_CAMERA.value or self.CP.carFingerprint in CC_ONLY_CAR)

self.lkas_previously_enabled = self.lkas_enabled
if self.CP.carFingerprint in SDGM_CAR:
self.lkas_enabled = cam_cp.vl["ASCMSteeringButton"]["LKAButton"]
else:
self.lkas_enabled = pt_cp.vl["ASCMSteeringButton"]["LKAButton"]
self.lkas_enabled = pt_cp.vl["ASCMSteeringButton"]["LKAButton"]

self.pcm_acc_status = pt_cp.vl["AcceleratorPedal2"]["CruiseState"]

Expand All @@ -191,16 +163,7 @@ def get_cam_can_parser(CP):
messages += [
("ASCMLKASteeringCmd", 10),
]
if CP.carFingerprint in SDGM_CAR:
messages += [
("BCMTurnSignals", 1),
("BCMDoorBeltStatus", 10),
("BCMGeneralPlatformStatus", 10),
("ASCMSteeringButton", 33),
]
if CP.enableBsm:
messages.append(("BCMBlindSpotMonitor", 10))
else:
if CP.carFingerprint not in SDGM_CAR:
messages += [
("AEBCmd", 10),
]
Expand All @@ -214,34 +177,25 @@ def get_cam_can_parser(CP):
@staticmethod
def get_can_parser(CP):
messages = [
("BCMTurnSignals", 1),
("ECMPRDNL2", 10),
("PSCMStatus", 10),
("ESPStatus", 10),
("BCMDoorBeltStatus", 10),
("BCMGeneralPlatformStatus", 10),
("EBCMWheelSpdFront", 20),
("EBCMWheelSpdRear", 20),
("EBCMFrictionBrakeStatus", 20),
("AcceleratorPedal2", 33),
("ASCMSteeringButton", 33),
("ECMEngineStatus", 100),
("PSCMSteeringAngle", 100),
("ECMAcceleratorPos", 80),
("SportMode", 0),
]

if CP.carFingerprint in SDGM_CAR:
messages += [
("ECMPRDNL2", 40),
("AcceleratorPedal2", 40),
("ECMEngineStatus", 80),
]
else:
messages += [
("ECMPRDNL2", 10),
("AcceleratorPedal2", 33),
("ECMEngineStatus", 100),
("BCMTurnSignals", 1),
("BCMDoorBeltStatus", 10),
("BCMGeneralPlatformStatus", 10),
("ASCMSteeringButton", 33),
]
if CP.enableBsm:
messages.append(("BCMBlindSpotMonitor", 10))
if CP.enableBsm:
messages.append(("BCMBlindSpotMonitor", 10))

# Used to read back last counter sent to PT by camera
if CP.networkLocation == NetworkLocation.fwdCamera:
Expand Down
Loading

0 comments on commit 9e674a6

Please sign in to comment.