Add openpilot tests
This commit is contained in:
42
panda/tests/libpanda/SConscript
Normal file
42
panda/tests/libpanda/SConscript
Normal file
@@ -0,0 +1,42 @@
|
||||
import platform
|
||||
|
||||
CC = 'gcc'
|
||||
system = platform.system()
|
||||
if system == 'Darwin':
|
||||
# gcc installed by homebrew has version suffix (e.g. gcc-12) in order to be
|
||||
# distinguishable from system one - which acts as a symlink to clang
|
||||
CC += '-13'
|
||||
|
||||
env = Environment(
|
||||
CC=CC,
|
||||
CFLAGS=[
|
||||
'-nostdlib',
|
||||
'-fno-builtin',
|
||||
'-std=gnu11',
|
||||
'-Wfatal-errors',
|
||||
'-Wno-pointer-to-int-cast',
|
||||
],
|
||||
CPPPATH=[".", "../../board/"],
|
||||
)
|
||||
if system == "Darwin":
|
||||
env.PrependENVPath('PATH', '/opt/homebrew/bin')
|
||||
|
||||
if GetOption('ubsan'):
|
||||
flags = [
|
||||
"-fsanitize=undefined",
|
||||
"-fno-sanitize-recover=undefined",
|
||||
]
|
||||
env['CFLAGS'] += flags
|
||||
env['LINKFLAGS'] += flags
|
||||
|
||||
panda = env.SharedObject("panda.os", "panda.c")
|
||||
libpanda = env.SharedLibrary("libpanda.so", [panda])
|
||||
|
||||
if GetOption('coverage'):
|
||||
env.Append(
|
||||
CFLAGS=["-fprofile-arcs", "-ftest-coverage", "-fprofile-abs-path",],
|
||||
LIBS=["gcov"],
|
||||
)
|
||||
# GCC note file is generated by compiler, ensure we build it, and allow scons to clean it up
|
||||
AlwaysBuild(panda)
|
||||
env.SideEffect("panda.gcno", panda)
|
||||
98
panda/tests/libpanda/libpanda_py.py
Normal file
98
panda/tests/libpanda/libpanda_py.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import os
|
||||
from cffi import FFI
|
||||
from typing import Any, Protocol
|
||||
|
||||
from panda import LEN_TO_DLC
|
||||
from panda.tests.libpanda.safety_helpers import PandaSafety, setup_safety_helpers
|
||||
|
||||
libpanda_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
libpanda_fn = os.path.join(libpanda_dir, "libpanda.so")
|
||||
|
||||
ffi = FFI()
|
||||
|
||||
ffi.cdef("""
|
||||
typedef struct {
|
||||
unsigned char reserved : 1;
|
||||
unsigned char bus : 3;
|
||||
unsigned char data_len_code : 4;
|
||||
unsigned char rejected : 1;
|
||||
unsigned char returned : 1;
|
||||
unsigned char extended : 1;
|
||||
unsigned int addr : 29;
|
||||
unsigned char checksum;
|
||||
unsigned char data[64];
|
||||
} CANPacket_t;
|
||||
""", packed=True)
|
||||
|
||||
ffi.cdef("""
|
||||
bool safety_rx_hook(CANPacket_t *to_send);
|
||||
bool safety_tx_hook(CANPacket_t *to_push);
|
||||
int safety_fwd_hook(int bus_num, int addr);
|
||||
int set_safety_hooks(uint16_t mode, uint16_t param);
|
||||
""")
|
||||
|
||||
ffi.cdef("""
|
||||
typedef struct {
|
||||
volatile uint32_t w_ptr;
|
||||
volatile uint32_t r_ptr;
|
||||
uint32_t fifo_size;
|
||||
CANPacket_t *elems;
|
||||
} can_ring;
|
||||
|
||||
extern can_ring *rx_q;
|
||||
extern can_ring *txgmlan_q;
|
||||
extern can_ring *tx1_q;
|
||||
extern can_ring *tx2_q;
|
||||
extern can_ring *tx3_q;
|
||||
|
||||
bool can_pop(can_ring *q, CANPacket_t *elem);
|
||||
bool can_push(can_ring *q, CANPacket_t *elem);
|
||||
void can_set_checksum(CANPacket_t *packet);
|
||||
int comms_can_read(uint8_t *data, uint32_t max_len);
|
||||
void comms_can_write(uint8_t *data, uint32_t len);
|
||||
void comms_can_reset(void);
|
||||
uint32_t can_slots_empty(can_ring *q);
|
||||
""")
|
||||
|
||||
setup_safety_helpers(ffi)
|
||||
|
||||
class CANPacket:
|
||||
reserved: int
|
||||
bus: int
|
||||
data_len_code: int
|
||||
rejected: int
|
||||
returned: int
|
||||
extended: int
|
||||
addr: int
|
||||
data: list[int]
|
||||
|
||||
class Panda(PandaSafety, Protocol):
|
||||
# CAN
|
||||
tx1_q: Any
|
||||
tx2_q: Any
|
||||
tx3_q: Any
|
||||
txgmlan_q: Any
|
||||
def can_set_checksum(self, p: CANPacket) -> None: ...
|
||||
|
||||
# safety
|
||||
def safety_rx_hook(self, to_send: CANPacket) -> int: ...
|
||||
def safety_tx_hook(self, to_push: CANPacket) -> int: ...
|
||||
def safety_fwd_hook(self, bus_num: int, addr: int) -> int: ...
|
||||
def set_safety_hooks(self, mode: int, param: int) -> int: ...
|
||||
|
||||
|
||||
libpanda: Panda = ffi.dlopen(libpanda_fn)
|
||||
|
||||
|
||||
# helpers
|
||||
|
||||
def make_CANPacket(addr: int, bus: int, dat):
|
||||
ret = ffi.new('CANPacket_t *')
|
||||
ret[0].extended = 1 if addr >= 0x800 else 0
|
||||
ret[0].addr = addr
|
||||
ret[0].data_len_code = LEN_TO_DLC[len(dat)]
|
||||
ret[0].bus = bus
|
||||
ret[0].data = bytes(dat)
|
||||
libpanda.can_set_checksum(ret)
|
||||
|
||||
return ret
|
||||
33
panda/tests/libpanda/panda.c
Normal file
33
panda/tests/libpanda/panda.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "fake_stm.h"
|
||||
#include "config.h"
|
||||
#include "can_definitions.h"
|
||||
|
||||
bool bitbang_gmlan(CANPacket_t *to_bang) { return true; }
|
||||
bool can_init(uint8_t can_number) { return true; }
|
||||
void process_can(uint8_t can_number) { }
|
||||
//int safety_tx_hook(CANPacket_t *to_send) { return 1; }
|
||||
|
||||
typedef struct harness_configuration harness_configuration;
|
||||
void refresh_can_tx_slots_available(void);
|
||||
void can_tx_comms_resume_usb(void) { };
|
||||
void can_tx_comms_resume_spi(void) { };
|
||||
|
||||
#include "health.h"
|
||||
#include "faults.h"
|
||||
#include "libc.h"
|
||||
#include "boards/board_declarations.h"
|
||||
#include "safety.h"
|
||||
#include "main_declarations.h"
|
||||
#include "drivers/can_common.h"
|
||||
|
||||
can_ring *rx_q = &can_rx_q;
|
||||
can_ring *txgmlan_q = &can_txgmlan_q;
|
||||
can_ring *tx1_q = &can_tx1_q;
|
||||
can_ring *tx2_q = &can_tx2_q;
|
||||
can_ring *tx3_q = &can_tx3_q;
|
||||
|
||||
#include "comms_definitions.h"
|
||||
#include "can_comms.h"
|
||||
|
||||
// libpanda stuff
|
||||
#include "safety_helpers.h"
|
||||
195
panda/tests/libpanda/safety_helpers.h
Normal file
195
panda/tests/libpanda/safety_helpers.h
Normal file
@@ -0,0 +1,195 @@
|
||||
void safety_tick_current_safety_config() {
|
||||
safety_tick(¤t_safety_config);
|
||||
}
|
||||
|
||||
bool safety_config_valid() {
|
||||
if (current_safety_config.rx_checks_len <= 0) {
|
||||
printf("missing RX checks\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < current_safety_config.rx_checks_len; i++) {
|
||||
const RxCheck addr = current_safety_config.rx_checks[i];
|
||||
bool valid = addr.status.msg_seen && !addr.status.lagging && addr.status.valid_checksum && (addr.status.wrong_counters < MAX_WRONG_COUNTERS) && addr.status.valid_quality_flag;
|
||||
if (!valid) {
|
||||
// printf("i %d seen %d lagging %d valid checksum %d wrong counters %d valid quality flag %d\n", i, addr.status.msg_seen, addr.status.lagging, addr.status.valid_checksum, addr.status.wrong_counters, addr.status.valid_quality_flag);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_controls_allowed(bool c){
|
||||
controls_allowed = c;
|
||||
}
|
||||
|
||||
void set_alternative_experience(int mode){
|
||||
alternative_experience = mode;
|
||||
}
|
||||
|
||||
void set_relay_malfunction(bool c){
|
||||
relay_malfunction = c;
|
||||
}
|
||||
|
||||
bool get_controls_allowed(void){
|
||||
return controls_allowed;
|
||||
}
|
||||
|
||||
int get_alternative_experience(void){
|
||||
return alternative_experience;
|
||||
}
|
||||
|
||||
bool get_relay_malfunction(void){
|
||||
return relay_malfunction;
|
||||
}
|
||||
|
||||
int get_gas_interceptor_prev(void){
|
||||
return gas_interceptor_prev;
|
||||
}
|
||||
|
||||
bool get_gas_pressed_prev(void){
|
||||
return gas_pressed_prev;
|
||||
}
|
||||
|
||||
bool get_brake_pressed_prev(void){
|
||||
return brake_pressed_prev;
|
||||
}
|
||||
|
||||
bool get_regen_braking_prev(void){
|
||||
return regen_braking_prev;
|
||||
}
|
||||
|
||||
bool get_cruise_engaged_prev(void){
|
||||
return cruise_engaged_prev;
|
||||
}
|
||||
|
||||
void set_cruise_engaged_prev(bool engaged){
|
||||
cruise_engaged_prev = engaged;
|
||||
}
|
||||
|
||||
bool get_vehicle_moving(void){
|
||||
return vehicle_moving;
|
||||
}
|
||||
|
||||
bool get_acc_main_on(void){
|
||||
return acc_main_on;
|
||||
}
|
||||
|
||||
int get_vehicle_speed_min(void){
|
||||
return vehicle_speed.min;
|
||||
}
|
||||
|
||||
int get_vehicle_speed_max(void){
|
||||
return vehicle_speed.max;
|
||||
}
|
||||
|
||||
int get_vehicle_speed_last(void){
|
||||
return vehicle_speed.values[0];
|
||||
}
|
||||
|
||||
int get_current_safety_mode(void){
|
||||
return current_safety_mode;
|
||||
}
|
||||
|
||||
int get_current_safety_param(void){
|
||||
return current_safety_param;
|
||||
}
|
||||
|
||||
int get_hw_type(void){
|
||||
return hw_type;
|
||||
}
|
||||
|
||||
void set_timer(uint32_t t){
|
||||
timer.CNT = t;
|
||||
}
|
||||
|
||||
void set_torque_meas(int min, int max){
|
||||
torque_meas.min = min;
|
||||
torque_meas.max = max;
|
||||
}
|
||||
|
||||
int get_torque_meas_min(void){
|
||||
return torque_meas.min;
|
||||
}
|
||||
|
||||
int get_torque_meas_max(void){
|
||||
return torque_meas.max;
|
||||
}
|
||||
|
||||
void set_torque_driver(int min, int max){
|
||||
torque_driver.min = min;
|
||||
torque_driver.max = max;
|
||||
}
|
||||
|
||||
int get_torque_driver_min(void){
|
||||
return torque_driver.min;
|
||||
}
|
||||
|
||||
int get_torque_driver_max(void){
|
||||
return torque_driver.max;
|
||||
}
|
||||
|
||||
void set_rt_torque_last(int t){
|
||||
rt_torque_last = t;
|
||||
}
|
||||
|
||||
void set_desired_torque_last(int t){
|
||||
desired_torque_last = t;
|
||||
}
|
||||
|
||||
void set_desired_angle_last(int t){
|
||||
desired_angle_last = t;
|
||||
}
|
||||
|
||||
int get_desired_angle_last(void){
|
||||
return desired_angle_last;
|
||||
}
|
||||
|
||||
void set_angle_meas(int min, int max){
|
||||
angle_meas.min = min;
|
||||
angle_meas.max = max;
|
||||
}
|
||||
|
||||
int get_angle_meas_min(void){
|
||||
return angle_meas.min;
|
||||
}
|
||||
|
||||
int get_angle_meas_max(void){
|
||||
return angle_meas.max;
|
||||
}
|
||||
|
||||
|
||||
// ***** car specific helpers *****
|
||||
|
||||
void set_honda_alt_brake_msg(bool c){
|
||||
honda_alt_brake_msg = c;
|
||||
}
|
||||
|
||||
void set_honda_bosch_long(bool c){
|
||||
honda_bosch_long = c;
|
||||
}
|
||||
|
||||
int get_honda_hw(void) {
|
||||
return honda_hw;
|
||||
}
|
||||
|
||||
void set_honda_fwd_brake(bool c){
|
||||
honda_fwd_brake = c;
|
||||
}
|
||||
|
||||
bool get_honda_fwd_brake(void){
|
||||
return honda_fwd_brake;
|
||||
}
|
||||
|
||||
void init_tests(void){
|
||||
// get HW_TYPE from env variable set in test.sh
|
||||
if (getenv("HW_TYPE")) {
|
||||
hw_type = atoi(getenv("HW_TYPE"));
|
||||
}
|
||||
safety_mode_cnt = 2U; // avoid ignoring relay_malfunction logic
|
||||
alternative_experience = 0;
|
||||
set_timer(0);
|
||||
ts_steer_req_mismatch_last = 0;
|
||||
valid_steer_req_count = 0;
|
||||
invalid_steer_req_count = 0;
|
||||
}
|
||||
106
panda/tests/libpanda/safety_helpers.py
Normal file
106
panda/tests/libpanda/safety_helpers.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# panda safety helpers, from safety_helpers.c
|
||||
from typing import Protocol
|
||||
|
||||
def setup_safety_helpers(ffi):
|
||||
ffi.cdef("""
|
||||
void set_controls_allowed(bool c);
|
||||
bool get_controls_allowed(void);
|
||||
bool get_longitudinal_allowed(void);
|
||||
void set_alternative_experience(int mode);
|
||||
int get_alternative_experience(void);
|
||||
void set_relay_malfunction(bool c);
|
||||
bool get_relay_malfunction(void);
|
||||
int get_gas_interceptor_prev(void);
|
||||
bool get_gas_pressed_prev(void);
|
||||
bool get_brake_pressed_prev(void);
|
||||
bool get_regen_braking_prev(void);
|
||||
bool get_acc_main_on(void);
|
||||
int get_vehicle_speed_min(void);
|
||||
int get_vehicle_speed_max(void);
|
||||
int get_vehicle_speed_last(void);
|
||||
int get_current_safety_mode(void);
|
||||
int get_current_safety_param(void);
|
||||
|
||||
void set_torque_meas(int min, int max);
|
||||
int get_torque_meas_min(void);
|
||||
int get_torque_meas_max(void);
|
||||
void set_torque_driver(int min, int max);
|
||||
int get_torque_driver_min(void);
|
||||
int get_torque_driver_max(void);
|
||||
void set_desired_torque_last(int t);
|
||||
void set_rt_torque_last(int t);
|
||||
void set_desired_angle_last(int t);
|
||||
int get_desired_angle_last();
|
||||
void set_angle_meas(int min, int max);
|
||||
int get_angle_meas_min(void);
|
||||
int get_angle_meas_max(void);
|
||||
|
||||
bool get_cruise_engaged_prev(void);
|
||||
void set_cruise_engaged_prev(bool engaged);
|
||||
bool get_vehicle_moving(void);
|
||||
int get_hw_type(void);
|
||||
void set_timer(uint32_t t);
|
||||
|
||||
void safety_tick_current_safety_config();
|
||||
bool safety_config_valid();
|
||||
|
||||
void init_tests(void);
|
||||
|
||||
void set_honda_fwd_brake(bool c);
|
||||
bool get_honda_fwd_brake(void);
|
||||
void set_honda_alt_brake_msg(bool c);
|
||||
void set_honda_bosch_long(bool c);
|
||||
int get_honda_hw(void);
|
||||
""")
|
||||
|
||||
class PandaSafety(Protocol):
|
||||
def set_controls_allowed(self, c: bool) -> None: ...
|
||||
def get_controls_allowed(self) -> bool: ...
|
||||
def get_longitudinal_allowed(self) -> bool: ...
|
||||
def set_alternative_experience(self, mode: int) -> None: ...
|
||||
def get_alternative_experience(self) -> int: ...
|
||||
def set_relay_malfunction(self, c: bool) -> None: ...
|
||||
def get_relay_malfunction(self) -> bool: ...
|
||||
def get_gas_interceptor_prev(self) -> int: ...
|
||||
def get_gas_pressed_prev(self) -> bool: ...
|
||||
def get_brake_pressed_prev(self) -> bool: ...
|
||||
def get_regen_braking_prev(self) -> bool: ...
|
||||
def get_acc_main_on(self) -> bool: ...
|
||||
def get_vehicle_speed_min(self) -> int: ...
|
||||
def get_vehicle_speed_max(self) -> int: ...
|
||||
def get_vehicle_speed_last(self) -> int: ...
|
||||
def get_current_safety_mode(self) -> int: ...
|
||||
def get_current_safety_param(self) -> int: ...
|
||||
|
||||
def set_torque_meas(self, min: int, max: int) -> None: ... # noqa: A002
|
||||
def get_torque_meas_min(self) -> int: ...
|
||||
def get_torque_meas_max(self) -> int: ...
|
||||
def set_torque_driver(self, min: int, max: int) -> None: ... # noqa: A002
|
||||
def get_torque_driver_min(self) -> int: ...
|
||||
def get_torque_driver_max(self) -> int: ...
|
||||
def set_desired_torque_last(self, t: int) -> None: ...
|
||||
def set_rt_torque_last(self, t: int) -> None: ...
|
||||
def set_desired_angle_last(self, t: int) -> None: ...
|
||||
def get_desired_angle_last(self) -> int: ...
|
||||
def set_angle_meas(self, min: int, max: int) -> None: ... # noqa: A002
|
||||
def get_angle_meas_min(self) -> int: ...
|
||||
def get_angle_meas_max(self) -> int: ...
|
||||
|
||||
def get_cruise_engaged_prev(self) -> bool: ...
|
||||
def set_cruise_engaged_prev(self, enabled: bool) -> None: ...
|
||||
def get_vehicle_moving(self) -> bool: ...
|
||||
def get_hw_type(self) -> int: ...
|
||||
def set_timer(self, t: int) -> None: ...
|
||||
|
||||
def safety_tick_current_safety_config(self) -> None: ...
|
||||
def safety_config_valid(self) -> bool: ...
|
||||
|
||||
def init_tests(self) -> None: ...
|
||||
|
||||
def set_honda_fwd_brake(self, c: bool) -> None: ...
|
||||
def get_honda_fwd_brake(self) -> bool: ...
|
||||
def set_honda_alt_brake_msg(self, c: bool) -> None: ...
|
||||
def set_honda_bosch_long(self, c: bool) -> None: ...
|
||||
def get_honda_hw(self) -> int: ...
|
||||
|
||||
|
||||
Reference in New Issue
Block a user