CAN-FD non-ISO support (#1082)

CAN FD non-ISO support
This commit is contained in:
Greg Hogan 2022-10-12 15:28:20 -07:00 committed by GitHub
parent ffb3109e28
commit 2f3e2825e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 64 deletions

View File

@ -12,6 +12,7 @@ typedef struct {
uint32_t can_data_speed;
bool canfd_enabled;
bool brs_enabled;
bool canfd_non_iso;
} bus_config_t;
uint32_t safety_tx_blocked = 0;
@ -155,10 +156,10 @@ void can_clear(can_ring *q) {
// Helpers
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
bus_config_t bus_config[] = {
{ .bus_lookup = 0U, .can_num_lookup = 0U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .can_speed = 333U, .can_data_speed = 333U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 0U, .can_num_lookup = 0U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .can_speed = 333U, .can_data_speed = 333U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
};
#define CANIF_FROM_CAN_NUM(num) (cans[num])

View File

@ -20,6 +20,7 @@ bool can_set_speed(uint8_t can_number) {
CANx,
bus_config[bus_number].can_speed,
bus_config[bus_number].can_data_speed,
bus_config[bus_number].canfd_non_iso,
can_loopback,
(unsigned int)(can_silent) & (1U << can_number)
);

View File

@ -28,7 +28,7 @@ struct __attribute__((packed)) health_t {
uint8_t safety_rx_checks_invalid;
};
#define CAN_HEALTH_PACKET_VERSION 2
#define CAN_HEALTH_PACKET_VERSION 3
typedef struct __attribute__((packed)) {
uint8_t bus_off;
uint32_t bus_off_cnt;
@ -50,4 +50,5 @@ typedef struct __attribute__((packed)) {
uint16_t can_data_speed;
uint8_t canfd_enabled;
uint8_t brs_enabled;
uint8_t canfd_non_iso;
} can_health_t;

View File

@ -254,6 +254,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
can_health[req->param1].can_data_speed = (bus_config[req->param1].can_data_speed / 10U);
can_health[req->param1].canfd_enabled = bus_config[req->param1].canfd_enabled;
can_health[req->param1].brs_enabled = bus_config[req->param1].brs_enabled;
can_health[req->param1].canfd_non_iso = bus_config[req->param1].canfd_non_iso;
resp_len = sizeof(can_health[req->param1]);
(void)memcpy(resp, &can_health[req->param1], resp_len);
}
@ -534,7 +535,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
heartbeat_disabled = true;
}
break;
// **** 0xde: set CAN FD data bitrate
// **** 0xf9: set CAN FD data bitrate
case 0xf9:
if ((req->param1 < CAN_CNT) &&
current_board->has_canfd &&
@ -546,18 +547,18 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
UNUSED(ret);
}
break;
// **** 0xfa: check if CAN FD and BRS are enabled
case 0xfa:
if (req->param1 < CAN_CNT) {
resp[0] = bus_config[req->param1].canfd_enabled;
resp[1] = bus_config[req->param1].brs_enabled;
resp_len = 2;
}
break;
// **** 0xfb: allow highest power saving mode (stop) to be entered
case 0xfb:
deepsleep_allowed = true;
break;
// **** 0xfc: set CAN FD non-ISO mode
case 0xfc:
if ((req->param1 < CAN_CNT) && current_board->has_canfd) {
bus_config[req->param1].canfd_non_iso = (req->param2 != 0U);
bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1));
UNUSED(ret);
}
break;
default:
puts("NO HANDLER ");
puth(req->request);

View File

@ -84,7 +84,7 @@ bool fdcan_exit_init(FDCAN_GlobalTypeDef *CANx) {
return ret;
}
bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_speed, bool loopback, bool silent) {
bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_speed, bool non_iso, bool loopback, bool silent) {
UNUSED(speed);
bool ret = fdcan_request_init(CANx);
@ -97,6 +97,7 @@ bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_sp
CANx->TEST &= ~(FDCAN_TEST_LBCK);
CANx->CCCR &= ~(FDCAN_CCCR_MON);
CANx->CCCR &= ~(FDCAN_CCCR_ASM);
CANx->CCCR &= ~(FDCAN_CCCR_NISO);
// TODO: add as a separate safety mode
// Enable ASM restricted operation(for debug or automatic bitrate switching)
@ -130,6 +131,11 @@ bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_sp
CANx->DBTP = (((sjw & 0xFU)-1U)<<FDCAN_DBTP_DSJW_Pos) | (((seg1 & 0x1FU)-1U)<<FDCAN_DBTP_DTSEG1_Pos) | (((seg2 & 0xFU)-1U)<<FDCAN_DBTP_DTSEG2_Pos) | (((prescaler & 0x1FU)-1U)<<FDCAN_DBTP_DBRP_Pos);
if (non_iso) {
// FD non-ISO mode
CANx->CCCR |= FDCAN_CCCR_NISO;
}
// Silent loopback is known as internal loopback in the docs
if (loopback) {
CANx->CCCR |= FDCAN_CCCR_TEST;

View File

@ -186,9 +186,9 @@ class Panda:
CAN_PACKET_VERSION = 2
HEALTH_PACKET_VERSION = 11
CAN_HEALTH_PACKET_VERSION = 2
CAN_HEALTH_PACKET_VERSION = 3
HEALTH_STRUCT = struct.Struct("<IIIIIIIIIBBBBBBHBBBHfBB")
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIHHBB")
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIHHBBB")
F2_DEVICES = (HW_TYPE_PEDAL, )
F4_DEVICES = (HW_TYPE_WHITE_PANDA, HW_TYPE_GREY_PANDA, HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS)
@ -509,6 +509,7 @@ class Panda:
"can_data_speed": a[17],
"canfd_enabled": a[18],
"brs_enabled": a[19],
"canfd_non_iso": a[20],
}
# ******************* control *******************
@ -626,14 +627,8 @@ class Panda:
def set_can_data_speed_kbps(self, bus, speed):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf9, bus, int(speed * 10), b'')
# CAN FD and BRS status
def get_canfd_status(self, bus):
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xfa, bus, 0, 2)
if dat:
a = struct.unpack("BB", dat)
return (a[0], a[1])
else:
return (None, None)
def set_canfd_non_iso(self, bus, non_iso):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xfc, bus, int(non_iso), b'')
def set_uart_baud(self, uart, rate):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe4, uart, int(rate / 300), b'')

View File

@ -15,38 +15,41 @@ if os.getenv("H7_PANDAS_EXCLUDE"):
#TODO: REMOVE, temporary list of CAN FD lengths, one in panda python lib MUST be used
DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48]
_panda_serials = []
def panda_reset():
panda_serials = []
if JUNGLE_SERIAL:
panda_jungle = PandaJungle(JUNGLE_SERIAL)
panda_jungle.set_panda_power(False)
time.sleep(2)
panda_jungle.set_panda_power(True)
time.sleep(4)
def panda_init(serial, enable_canfd=False):
for serial in Panda.list():
if serial not in H7_PANDAS_EXCLUDE:
p = Panda(serial=serial)
if p.get_type() in H7_HW_TYPES:
assert p.recover(timeout=30)
panda_serials.append(serial)
p.close()
if len(panda_serials) < 2:
print("Minimum two H7 type pandas should be connected.")
assert False
return panda_serials
def panda_init(serial, enable_canfd=False, enable_non_iso=False):
p = Panda(serial=serial)
p.set_power_save(False)
for bus in range(3):
if enable_canfd:
p.set_can_data_speed_kbps(bus, 2000)
if enable_non_iso:
p.set_canfd_non_iso(bus, True)
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
return p
if JUNGLE_SERIAL:
panda_jungle = PandaJungle(JUNGLE_SERIAL)
panda_jungle.set_panda_power(False)
time.sleep(2)
panda_jungle.set_panda_power(True)
time.sleep(4)
for serial in Panda.list():
if serial not in H7_PANDAS_EXCLUDE:
p = Panda(serial=serial)
if p.get_type() in H7_HW_TYPES:
assert p.recover(timeout=30)
_panda_serials.append(serial)
p.close()
if len(_panda_serials) < 2:
print("Minimum two H7 type pandas should be connected.")
assert False
def canfd_test(p_send, p_recv):
for _ in range(100):
sent_msgs = defaultdict(set)
@ -78,27 +81,46 @@ def canfd_test(p_send, p_recv):
p_recv.set_safety_mode(Panda.SAFETY_SILENT)
p_send.set_power_save(True)
p_recv.set_power_save(True)
p_send.close()
p_recv.close()
print("Got all messages intact")
p_send = panda_init(_panda_serials[0], enable_canfd=False)
p_recv = panda_init(_panda_serials[1], enable_canfd=True)
def setup_test(enable_non_iso=False):
panda_serials = panda_reset()
# Check that sending panda CAN FD and BRS are turned off
for bus in range(3):
canfd, brs = p_send.get_canfd_status(bus)
assert not canfd
assert not brs
p_send = panda_init(panda_serials[0], enable_canfd=False, enable_non_iso=enable_non_iso)
p_recv = panda_init(panda_serials[1], enable_canfd=True, enable_non_iso=enable_non_iso)
# Receiving panda sends dummy CAN FD message that should enable CAN FD on sender side
for bus in range(3):
p_recv.can_send(0x200, b"dummymessage", bus)
p_recv.can_recv()
# Check that sending panda CAN FD and BRS are turned off
for bus in range(3):
health = p_send.can_health(bus)
assert not health["canfd_enabled"]
assert not health["brs_enabled"]
assert health["canfd_non_iso"] == enable_non_iso
# Check if all tested buses on sending panda have swithed to CAN FD with BRS
for bus in range(3):
canfd, brs = p_send.get_canfd_status(bus)
assert canfd
assert brs
# Receiving panda sends dummy CAN FD message that should enable CAN FD on sender side
for bus in range(3):
p_recv.can_send(0x200, b"dummymessage", bus)
p_recv.can_recv()
canfd_test(p_send, p_recv)
# Check if all tested buses on sending panda have swithed to CAN FD with BRS
for bus in range(3):
health = p_send.can_health(bus)
assert health["canfd_enabled"]
assert health["brs_enabled"]
assert health["canfd_non_iso"] == enable_non_iso
return p_send, p_recv
def main():
print("[TEST CAN-FD]")
p_send, p_recv = setup_test()
canfd_test(p_send, p_recv)
print("[TEST CAN-FD non-ISO]")
p_send, p_recv = setup_test(enable_non_iso=True)
canfd_test(p_send, p_recv)
if __name__ == "__main__":
main()