Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
7213b37
Allow brake TX on PT bus
JMPZ11 Jun 8, 2022
4da6484
Initial Panda GM cam harness support
JMPZ11 Jun 8, 2022
1293b0e
Remove keepalive; regen == braking
JMPZ11 Jun 8, 2022
d7462da
Fix MISRA violations
JMPZ11 Jun 9, 2022
bba00e9
EPS timing opt-in by param
JMPZ11 Jun 9, 2022
f06df92
Minor clean up
sshane Jun 15, 2022
73ee49a
remove timing code for readability
sshane Jun 15, 2022
3094061
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
JMPZ11 Jun 15, 2022
6749f0c
we only need to send one message if cam harness and stock long
sshane Jun 15, 2022
06d5e00
Simplify params
JMPZ11 Jun 15, 2022
7bdceda
Merge branch 'gm-cam-harness' of https://github.com/opgm/panda into g…
JMPZ11 Jun 15, 2022
ee10d4e
Removed dup brake msg
JMPZ11 Jun 15, 2022
1cbe6a9
revised params, split 3-ways
JMPZ11 Jun 15, 2022
ae38cdb
add test
sshane Jun 15, 2022
5b69c38
clean up a bit, no need to send ACC yet
sshane Jun 15, 2022
0ca1514
split out button enable and pcm enable into seperate tests
sshane Jun 15, 2022
0ddba83
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
JMPZ11 Jun 18, 2022
ff09389
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
JMPZ11 Jun 27, 2022
e14f154
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
JMPZ11 Jul 4, 2022
a1c2bd7
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
sshane Aug 3, 2022
df8ffe3
some formatting
sshane Aug 9, 2022
bdd9c80
GM CAM uses PCM cruise for controls_allowed
sshane Aug 9, 2022
4992abf
fix gas safety tests
sshane Aug 9, 2022
c6f61f4
misra
sshane Aug 9, 2022
a55850c
fix static analysis
sshane Aug 9, 2022
0209679
fix brake pressed
sshane Aug 9, 2022
a4b096c
Add OP VOACC override stock cam
JMPZ11 Aug 9, 2022
2e46f87
Add VOACC safetyparam to init.py
JMPZ11 Aug 9, 2022
07136b9
Revert "Add VOACC safetyparam to init.py"
sshane Aug 9, 2022
a1053de
Revert "Add OP VOACC override stock cam"
sshane Aug 9, 2022
9d4e7f9
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
sshane Aug 10, 2022
aee5894
better comments
sshane Aug 10, 2022
8a3d455
better comments
sshane Aug 10, 2022
835c73f
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
sshane Aug 10, 2022
1b021eb
move non-base msg definitions to subclass
sshane Aug 10, 2022
eb798c3
various comments
sshane Aug 10, 2022
62a7cbe
TODO: add button safety
sshane Aug 10, 2022
3e1d8cd
add button safety
sshane Aug 10, 2022
626fdcf
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
sshane Aug 12, 2022
26f2e28
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
sshane Aug 12, 2022
e7acd2d
use new pcm_cruise_check
sshane Aug 12, 2022
56269c7
revert regen braking change
sshane Aug 12, 2022
ffb7678
only cancel button allowed
sshane Aug 12, 2022
7a3b132
Apply suggestions from code review
sshane Aug 12, 2022
af9f6c6
Update board/safety/safety_gm.h
sshane Aug 12, 2022
d9cfb89
fix suggestion
sshane Aug 12, 2022
5005779
Fix tests
sshane Aug 12, 2022
ecd713a
Revert "Fix tests"
sshane Aug 12, 2022
8168ed4
this is a much simpler fix, do full fix in another PR
sshane Aug 12, 2022
dce61cf
tx button safety
sshane Aug 12, 2022
37bd38e
Merge remote-tracking branch 'upstream/master' into gm-cam-harness
sshane Aug 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 65 additions & 15 deletions board/safety/safety_gm.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ const int GM_MAX_RATE_UP = 7;
const int GM_MAX_RATE_DOWN = 17;
const int GM_DRIVER_TORQUE_ALLOWANCE = 50;
const int GM_DRIVER_TORQUE_FACTOR = 4;

const int GM_MAX_GAS = 3072;
const int GM_MAX_REGEN = 1404;
const int GM_MAX_BRAKE = 350;
const CanMsg GM_TX_MSGS[] = {{384, 0, 4}, {1033, 0, 7}, {1034, 0, 7}, {715, 0, 8}, {880, 0, 6}, // pt bus
{161, 1, 7}, {774, 1, 8}, {776, 1, 7}, {784, 1, 2}, // obs bus
{789, 2, 5}, // ch bus
{0x104c006c, 3, 3}, {0x10400060, 3, 5}}; // gmlan

const CanMsg GM_ASCM_TX_MSGS[] = {{384, 0, 4}, {1033, 0, 7}, {1034, 0, 7}, {715, 0, 8}, {880, 0, 6}, // pt bus
{161, 1, 7}, {774, 1, 8}, {776, 1, 7}, {784, 1, 2}, // obs bus
{789, 2, 5}, // ch bus
{0x104c006c, 3, 3}, {0x10400060, 3, 5}}; // gmlan

const CanMsg GM_CAM_TX_MSGS[] = {{384, 0, 4}, // pt bus
{481, 2, 7}}; // camera bus

// TODO: do checksum and counter checks. Add correct timestep, 0.1s for now.
AddrCheckStruct gm_addr_checks[] = {
Expand All @@ -34,6 +39,7 @@ AddrCheckStruct gm_addr_checks[] = {
#define GM_RX_CHECK_LEN (sizeof(gm_addr_checks) / sizeof(gm_addr_checks[0]))
addr_checks gm_rx_checks = {gm_addr_checks, GM_RX_CHECK_LEN};

const uint16_t GM_PARAM_HW_CAM = 1;

enum {
GM_BTN_UNPRESS = 1,
Expand All @@ -42,6 +48,8 @@ enum {
GM_BTN_CANCEL = 6,
};

enum {GM_ASCM, GM_CAM} gm_hw = GM_ASCM;

static int gm_rx_hook(CANPacket_t *to_push) {

bool valid = addr_safety_check(to_push, &gm_rx_checks, NULL, NULL, NULL);
Expand All @@ -62,8 +70,8 @@ static int gm_rx_hook(CANPacket_t *to_push) {
vehicle_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1);
}

// ACC steering wheel buttons
if (addr == 481) {
// ACC steering wheel buttons (GM_CAM is tied to the PCM)
if ((addr == 481) && (gm_hw == GM_ASCM)) {
int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4;

// exit controls on cancel press
Expand All @@ -90,6 +98,12 @@ static int gm_rx_hook(CANPacket_t *to_push) {

if (addr == 452) {
gas_pressed = GET_BYTE(to_push, 5) != 0U;

// enter controls on rising edge of ACC, exit controls when ACC off
if (gm_hw == GM_CAM) {
bool cruise_engaged = (GET_BYTE(to_push, 1) >> 5) != 0U;
pcm_cruise_check(cruise_engaged);
}
}

// exit controls on regen paddle
Expand All @@ -100,11 +114,13 @@ static int gm_rx_hook(CANPacket_t *to_push) {
}
}

// Check if ASCM or LKA camera are online
// on powertrain bus.
// 384 = ASCMLKASteeringCmd
// 715 = ASCMGasRegenCmd
generic_rx_checks(((addr == 384) || (addr == 715)));
bool stock_ecu_detected = (addr == 384); // ASCMLKASteeringCmd

// Only check ASCMGasRegenCmd if ASCM, GM_CAM uses stock longitudinal
if ((gm_hw == GM_ASCM) && (addr == 715)) {
stock_ecu_detected = true;
}
generic_rx_checks(stock_ecu_detected);
}
return valid;
}
Expand All @@ -120,8 +136,10 @@ static int gm_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) {
int tx = 1;
int addr = GET_ADDR(to_send);

if (!msg_allowed(to_send, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) {
tx = 0;
if (gm_hw == GM_CAM) {
tx = msg_allowed(to_send, GM_CAM_TX_MSGS, sizeof(GM_CAM_TX_MSGS)/sizeof(GM_CAM_TX_MSGS[0]));
} else {
tx = msg_allowed(to_send, GM_ASCM_TX_MSGS, sizeof(GM_ASCM_TX_MSGS)/sizeof(GM_ASCM_TX_MSGS[0]));
}

// disallow actuator commands if gas or brake (with vehicle moving) are pressed
Expand Down Expand Up @@ -218,12 +236,44 @@ static int gm_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) {
}
}

// BUTTONS: used for resume spamming and cruise cancellation with stock longitudinal
if ((addr == 481) && (gm_hw == GM_CAM)) {
int button = (GET_BYTE(to_send, 5) >> 4) & 0x7U;

bool allowed_cancel = (button == 6) && cruise_engaged_prev;
if (!allowed_cancel) {
tx = 0;
}
}

// 1 allows the message through
return tx;
}

static int gm_fwd_hook(int bus_num, CANPacket_t *to_fwd) {

int bus_fwd = -1;

if (gm_hw == GM_CAM) {
if (bus_num == 0) {
bus_fwd = 2;
}

if (bus_num == 2) {
// block lkas message, forward all others
int addr = GET_ADDR(to_fwd);
bool is_lkas_msg = (addr == 384);
if (!is_lkas_msg) {
bus_fwd = 0;
}
}
}

return bus_fwd;
}

static const addr_checks* gm_init(uint16_t param) {
UNUSED(param);
gm_hw = GET_FLAG(param, GM_PARAM_HW_CAM) ? GM_CAM : GM_ASCM;
return &gm_rx_checks;
}

Expand All @@ -232,5 +282,5 @@ const safety_hooks gm_hooks = {
.rx = gm_rx_hook,
.tx = gm_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
.fwd = default_fwd_hook,
.fwd = gm_fwd_hook,
};
2 changes: 2 additions & 0 deletions python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ class Panda:

FLAG_SUBARU_GEN2 = 1

FLAG_GM_HW_CAM = 1

def __init__(self, serial: Optional[str] = None, claim: bool = True):
self._serial = serial
self._handle = None
Expand Down
153 changes: 109 additions & 44 deletions tests/safety/test_gm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,11 @@ class Buttons:
CANCEL = 6


class TestGmSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest):
TX_MSGS = [[384, 0], [1033, 0], [1034, 0], [715, 0], [880, 0], # pt bus
[161, 1], [774, 1], [776, 1], [784, 1], # obs bus
[789, 2], # ch bus
[0x104c006c, 3], [0x10400060, 3]] # gmlan
class TestGmSafetyBase(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest):
STANDSTILL_THRESHOLD = 0
RELAY_MALFUNCTION_ADDR = 384
RELAY_MALFUNCTION_BUS = 0
FWD_BLACKLISTED_ADDRS: Dict[int, List[int]] = {}
FWD_BUS_LOOKUP: Dict[int, int] = {}
BUTTONS_BUS = 0

MAX_RATE_UP = 7
MAX_RATE_DOWN = 17
Expand All @@ -37,34 +32,27 @@ class TestGmSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest
DRIVER_TORQUE_ALLOWANCE = 50
DRIVER_TORQUE_FACTOR = 4

@classmethod
def setUpClass(cls):
if cls.__name__ == "TestGmSafetyBase":
cls.packer = None
cls.safety = None
raise unittest.SkipTest

def setUp(self):
self.packer = CANPackerPanda("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerPanda("gm_global_a_chassis")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_GM, 0)
self.safety.init_tests()

# override these tests from PandaSafetyTest, GM uses button enable
def test_disable_control_allowed_from_cruise(self):
pass

def test_enable_control_allowed_from_cruise(self):
pass

def test_cruise_engaged_prev(self):
pass

def _pcm_status_msg(self, enable):
raise NotImplementedError

def _speed_msg(self, speed):
values = {"%sWheelSpd" % s: speed for s in ["RL", "RR"]}
return self.packer.make_can_msg_panda("EBCMWheelSpdRear", 0, values)

def _button_msg(self, buttons):
values = {"ACCButtons": buttons}
return self.packer.make_can_msg_panda("ASCMSteeringButton", 0, values)

def _user_brake_msg(self, brake):
# GM safety has a brake threshold of 10
values = {"BrakePedalPosition": 10 if brake else 0}
Expand All @@ -90,40 +78,24 @@ def _torque_cmd_msg(self, torque, steer_req=1):
values = {"LKASteeringCmd": torque}
return self.packer.make_can_msg_panda("ASCMLKASteeringCmd", 0, values)

def test_set_resume_buttons(self):
"""
SET and RESUME enter controls allowed on their falling edge.
"""
for btn in range(8):
self.safety.set_controls_allowed(0)
for _ in range(10):
self._rx(self._button_msg(btn))
self.assertFalse(self.safety.get_controls_allowed())

# should enter controls allowed on falling edge
if btn in (Buttons.RES_ACCEL, Buttons.DECEL_SET):
self._rx(self._button_msg(Buttons.UNPRESS))
self.assertTrue(self.safety.get_controls_allowed())

def test_cancel_button(self):
self.safety.set_controls_allowed(1)
self._rx(self._button_msg(Buttons.CANCEL))
self.assertFalse(self.safety.get_controls_allowed())
def _button_msg(self, buttons):
values = {"ACCButtons": buttons}
return self.packer.make_can_msg_panda("ASCMSteeringButton", self.BUTTONS_BUS, values)

def test_brake_safety_check(self):
def test_brake_safety_check(self, stock_longitudinal=False):
for enabled in [0, 1]:
for b in range(0, 500):
self.safety.set_controls_allowed(enabled)
if abs(b) > MAX_BRAKE or (not enabled and b != 0):
if abs(b) > MAX_BRAKE or (not enabled and b != 0) or stock_longitudinal:
self.assertFalse(self._tx(self._send_brake_msg(b)))
else:
self.assertTrue(self._tx(self._send_brake_msg(b)))

def test_gas_safety_check(self):
def test_gas_safety_check(self, stock_longitudinal=False):
for enabled in [0, 1]:
for g in range(0, 2**12 - 1):
self.safety.set_controls_allowed(enabled)
if abs(g) > MAX_GAS or (not enabled and g != MAX_REGEN):
if abs(g) > MAX_GAS or (not enabled and g != MAX_REGEN) or stock_longitudinal:
self.assertFalse(self._tx(self._send_gas_msg(g)))
else:
self.assertTrue(self._tx(self._send_gas_msg(g)))
Expand Down Expand Up @@ -180,5 +152,98 @@ def test_tx_hook_on_pedal_pressed_on_alternative_gas_experience(self):
self._rx(self._user_gas_msg(0))


class TestGmAscmSafety(TestGmSafetyBase):
TX_MSGS = [[384, 0], [1033, 0], [1034, 0], [715, 0], [880, 0], # pt bus
[161, 1], [774, 1], [776, 1], [784, 1], # obs bus
[789, 2], # ch bus
[0x104c006c, 3], [0x10400060, 3]] # gmlan
FWD_BLACKLISTED_ADDRS: Dict[int, List[int]] = {}
FWD_BUS_LOOKUP: Dict[int, int] = {}

def setUp(self):
self.packer = CANPackerPanda("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerPanda("gm_global_a_chassis")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_GM, 0)
self.safety.init_tests()

# override these tests from PandaSafetyTest, ASCM GM uses button enable
def test_disable_control_allowed_from_cruise(self):
pass

def test_enable_control_allowed_from_cruise(self):
pass

def test_cruise_engaged_prev(self):
pass

def _pcm_status_msg(self, enable):
raise NotImplementedError

def test_set_resume_buttons(self):
"""
SET and RESUME enter controls allowed on their falling edge.
"""
for btn in range(8):
self.safety.set_controls_allowed(0)
for _ in range(10):
self._rx(self._button_msg(btn))
self.assertFalse(self.safety.get_controls_allowed())

# should enter controls allowed on falling edge
if btn in (Buttons.RES_ACCEL, Buttons.DECEL_SET):
self._rx(self._button_msg(Buttons.UNPRESS))
self.assertTrue(self.safety.get_controls_allowed())

def test_cancel_button(self):
self.safety.set_controls_allowed(1)
self._rx(self._button_msg(Buttons.CANCEL))
self.assertFalse(self.safety.get_controls_allowed())


class TestGmCameraSafety(TestGmSafetyBase):
TX_MSGS = [[384, 0]] # pt bus
FWD_BLACKLISTED_ADDRS = {2: [384]} # LKAS message, ACC messages are (715, 880, 789)
FWD_BUS_LOOKUP = {0: 2, 2: 0}
BUTTONS_BUS = 2 # tx only

def setUp(self):
self.packer = CANPackerPanda("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerPanda("gm_global_a_chassis")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_GM, Panda.FLAG_GM_HW_CAM)
self.safety.init_tests()

def _user_gas_msg(self, gas):
cruise_active = self.safety.get_controls_allowed()
values = {"AcceleratorPedal2": 1 if gas else 0, "CruiseState": cruise_active}
return self.packer.make_can_msg_panda("AcceleratorPedal2", 0, values)

def _pcm_status_msg(self, enable):
values = {"CruiseState": enable}
return self.packer.make_can_msg_panda("AcceleratorPedal2", 0, values)

def test_buttons(self):
# Only CANCEL button is allowed while cruise is enabled
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):
self._rx(self._pcm_status_msg(enabled))
self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL)))

# Uses stock longitudinal, allow no longitudinal actuation
def test_brake_safety_check(self, stock_longitudinal=True):
super().test_brake_safety_check(stock_longitudinal=stock_longitudinal)

def test_gas_safety_check(self, stock_longitudinal=True):
super().test_gas_safety_check(stock_longitudinal=stock_longitudinal)


if __name__ == "__main__":
unittest.main()