Black panda Jenkins (#256)

* Jenkins test refactor and black panda addition

* Added HW types needed by previous commit

* Fixed ignition interrupts when not on EON build

* Added functions for load switches

* More test scripts for black panda

* Added NONE power mode to the code

* Fixed race condition when setting GPIO pins was interrupted.

* Added relay test script

* Fixed flashing with critical sections and GPS load switch

* Fixing critical depth after reboot

* Made the loopback test asserting

* Made critical depth a local variable to avoid race conditions

* Added GPS to power savings mode

* Fixed DFU mode on white panda and bumped version

* Fixed PEDAL_USB compilation error

* Fixed misra compliance of new critical depth code

* Cleaned up heartbeat logic in the testing code. Re-added ALL_CAN_BUT_MAIN_SILENT. Bumped version. Improved critical section code.

* Fixed DFU flashing (once again)

* Fixed VERSION

* Added relay endurance test

* Changed to alloutput on ELM mode for fingerprinting.

* Fixed minor remarks
master
robbederks 2019-08-28 12:57:42 -07:00 committed by rbiasini
parent d68508c79a
commit 6f532c6d51
21 changed files with 939 additions and 342 deletions

2
.gitignore vendored
View File

@ -4,6 +4,7 @@
*.o *.o
*.so *.so
*.d *.d
*.dump
a.out a.out
*~ *~
.#* .#*
@ -12,4 +13,5 @@ pandacan.egg-info/
board/obj/ board/obj/
examples/output.csv examples/output.csv
.DS_Store .DS_Store
.vscode
nosetests.xml nosetests.xml

View File

@ -1 +1 @@
v1.4.3 v1.4.6

View File

@ -24,7 +24,7 @@ struct board {
}; };
// ******************* Definitions ******************** // ******************* Definitions ********************
// These should match the enum in cereal/log.capnp // These should match the enums in cereal/log.capnp and __init__.py
#define HW_TYPE_UNKNOWN 0U #define HW_TYPE_UNKNOWN 0U
#define HW_TYPE_WHITE_PANDA 1U #define HW_TYPE_WHITE_PANDA 1U
#define HW_TYPE_GREY_PANDA 2U #define HW_TYPE_GREY_PANDA 2U
@ -54,4 +54,4 @@ struct board {
#define CAN_MODE_OBD_CAN2 3U #define CAN_MODE_OBD_CAN2 3U
// ********************* Globals ********************** // ********************* Globals **********************
uint8_t usb_power_mode = USB_POWER_NONE; uint8_t usb_power_mode = USB_POWER_NONE;

View File

@ -23,8 +23,9 @@ void black_enable_can_transciever(uint8_t transciever, bool enabled) {
} }
void black_enable_can_transcievers(bool enabled) { void black_enable_can_transcievers(bool enabled) {
for(uint8_t i=1; i<=4U; i++) for(uint8_t i=1U; i<=4U; i++){
black_enable_can_transciever(i, enabled); black_enable_can_transciever(i, enabled);
}
} }
void black_set_led(uint8_t color, bool enabled) { void black_set_led(uint8_t color, bool enabled) {
@ -43,26 +44,41 @@ void black_set_led(uint8_t color, bool enabled) {
} }
} }
void black_set_usb_power_mode(uint8_t mode){ void black_set_gps_load_switch(bool enabled) {
set_gpio_output(GPIOC, 12, enabled);
}
void black_set_usb_load_switch(bool enabled) {
set_gpio_output(GPIOB, 1, !enabled);
}
void black_set_usb_power_mode(uint8_t mode) {
usb_power_mode = mode; usb_power_mode = mode;
puts("Trying to set USB power mode on black panda. This is not supported.\n"); if (mode == USB_POWER_NONE) {
black_set_usb_load_switch(false);
} else {
black_set_usb_load_switch(true);
}
} }
void black_set_esp_gps_mode(uint8_t mode) { void black_set_esp_gps_mode(uint8_t mode) {
switch (mode) { switch (mode) {
case ESP_GPS_DISABLED: case ESP_GPS_DISABLED:
// ESP OFF // GPS OFF
set_gpio_output(GPIOC, 14, 0); set_gpio_output(GPIOC, 14, 0);
set_gpio_output(GPIOC, 5, 0); set_gpio_output(GPIOC, 5, 0);
black_set_gps_load_switch(false);
break; break;
case ESP_GPS_ENABLED: case ESP_GPS_ENABLED:
// ESP ON // GPS ON
set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 1); set_gpio_output(GPIOC, 5, 1);
black_set_gps_load_switch(true);
break; break;
case ESP_GPS_BOOTMODE: case ESP_GPS_BOOTMODE:
set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 14, 1);
set_gpio_output(GPIOC, 5, 0); set_gpio_output(GPIOC, 5, 0);
black_set_gps_load_switch(true);
break; break;
default: default:
puts("Invalid ESP/GPS mode\n"); puts("Invalid ESP/GPS mode\n");
@ -132,9 +148,11 @@ void black_init(void) {
// C8: FAN aka TIM3_CH3 // C8: FAN aka TIM3_CH3
set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3);
// C12: GPS load switch. Turn on permanently for now // Turn on GPS load switch.
set_gpio_output(GPIOC, 12, true); black_set_gps_load_switch(true);
//set_gpio_output(GPIOC, 12, false); //TODO: stupid inverted switch on prototype
// Turn on USB load switch.
black_set_usb_load_switch(true);
// Initialize harness // Initialize harness
harness_init(); harness_init();

View File

@ -285,6 +285,13 @@ void white_init(void) {
// Set normal CAN mode // Set normal CAN mode
white_set_can_mode(CAN_MODE_NORMAL); white_set_can_mode(CAN_MODE_NORMAL);
// Setup ignition interrupts
SYSCFG->EXTICR[1] = SYSCFG_EXTICR1_EXTI1_PA;
EXTI->IMR |= (1U << 1);
EXTI->RTSR |= (1U << 1);
EXTI->FTSR |= (1U << 1);
NVIC_EnableIRQ(EXTI1_IRQn);
} }
const harness_configuration white_harness_config = { const harness_configuration white_harness_config = {

View File

@ -78,9 +78,11 @@ void started_interrupt_handler(uint8_t interrupt_line) {
// jenky debounce // jenky debounce
delay(100000); delay(100000);
// set power savings mode here // set power savings mode here if on EON build
int power_save_state = current_board->check_ignition() ? POWER_SAVE_STATUS_DISABLED : POWER_SAVE_STATUS_ENABLED; #ifdef EON
set_power_save_state(power_save_state); int power_save_state = current_board->check_ignition() ? POWER_SAVE_STATUS_DISABLED : POWER_SAVE_STATUS_ENABLED;
set_power_save_state(power_save_state);
#endif
} }
EXTI->PR = (1U << interrupt_line); EXTI->PR = (1U << interrupt_line);
} }
@ -100,14 +102,6 @@ void EXTI3_IRQHandler(void) {
started_interrupt_handler(3); started_interrupt_handler(3);
} }
void started_interrupt_init(void) {
SYSCFG->EXTICR[1] = SYSCFG_EXTICR1_EXTI1_PA;
EXTI->IMR |= (1U << 1);
EXTI->RTSR |= (1U << 1);
EXTI->FTSR |= (1U << 1);
NVIC_EnableIRQ(EXTI1_IRQn);
}
// ****************************** safety mode ****************************** // ****************************** safety mode ******************************
// this is the only way to leave silent mode // this is the only way to leave silent mode
@ -116,30 +110,29 @@ void set_safety_mode(uint16_t mode, int16_t param) {
if (err == -1) { if (err == -1) {
puts("Error: safety set mode failed\n"); puts("Error: safety set mode failed\n");
} else { } else {
if (mode == SAFETY_NOOUTPUT) {
can_silent = ALL_CAN_SILENT;
} else {
can_silent = ALL_CAN_LIVE;
}
switch (mode) { switch (mode) {
case SAFETY_NOOUTPUT: case SAFETY_NOOUTPUT:
set_intercept_relay(false); set_intercept_relay(false);
if(hw_type == HW_TYPE_BLACK_PANDA){ if(hw_type == HW_TYPE_BLACK_PANDA){
current_board->set_can_mode(CAN_MODE_NORMAL); current_board->set_can_mode(CAN_MODE_NORMAL);
} }
can_silent = ALL_CAN_SILENT;
break; break;
case SAFETY_ELM327: case SAFETY_ELM327:
set_intercept_relay(false); set_intercept_relay(false);
heartbeat_counter = 0U;
if(hw_type == HW_TYPE_BLACK_PANDA){ if(hw_type == HW_TYPE_BLACK_PANDA){
current_board->set_can_mode(CAN_MODE_OBD_CAN2); current_board->set_can_mode(CAN_MODE_OBD_CAN2);
} }
can_silent = ALL_CAN_LIVE;
break; break;
default: default:
set_intercept_relay(true); set_intercept_relay(true);
heartbeat_counter = 0U;
if(hw_type == HW_TYPE_BLACK_PANDA){ if(hw_type == HW_TYPE_BLACK_PANDA){
current_board->set_can_mode(CAN_MODE_NORMAL); current_board->set_can_mode(CAN_MODE_NORMAL);
} }
can_silent = ALL_CAN_LIVE;
break; break;
} }
if (safety_ignition_hook() != -1) { if (safety_ignition_hook() != -1) {
@ -464,7 +457,10 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
break; break;
// **** 0xe6: set USB power // **** 0xe6: set USB power
case 0xe6: case 0xe6:
if (setup->b.wValue.w == 1U) { if (setup->b.wValue.w == 0U) {
puts("user setting NONE mode\n");
current_board->set_usb_power_mode(USB_POWER_NONE);
} else if (setup->b.wValue.w == 1U) {
puts("user setting CDP mode\n"); puts("user setting CDP mode\n");
current_board->set_usb_power_mode(USB_POWER_CDP); current_board->set_usb_power_mode(USB_POWER_CDP);
} else if (setup->b.wValue.w == 2U) { } else if (setup->b.wValue.w == 2U) {
@ -610,11 +606,10 @@ void TIM3_IRQHandler(void) {
pending_can_live = 0; pending_can_live = 0;
} }
#ifdef DEBUG #ifdef DEBUG
//TODO: re-enable puts("** blink ");
//puts("** blink "); puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" ");
//puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" "); puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" ");
//puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" "); puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n");
//puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n");
#endif #endif
// set green LED to be controls allowed // set green LED to be controls allowed
@ -730,11 +725,6 @@ int main(void) {
/*if (current_board->check_ignition()) { /*if (current_board->check_ignition()) {
set_power_save_state(POWER_SAVE_STATUS_ENABLED); set_power_save_state(POWER_SAVE_STATUS_ENABLED);
}*/ }*/
if (hw_type != HW_TYPE_BLACK_PANDA) {
// interrupt on started line
started_interrupt_init();
}
#endif #endif
// 48mhz / 65536 ~= 732 / 732 = 1 // 48mhz / 65536 ~= 732 / 732 = 1

View File

@ -28,6 +28,13 @@ void set_power_save_state(int state) {
// Switch CAN transcievers // Switch CAN transcievers
current_board->enable_can_transcievers(enable); current_board->enable_can_transcievers(enable);
// Switch EPS/GPS
if (enable) {
current_board->set_esp_gps_mode(ESP_GPS_ENABLED);
} else {
current_board->set_esp_gps_mode(ESP_GPS_DISABLED);
}
if(hw_type != HW_TYPE_BLACK_PANDA){ if(hw_type != HW_TYPE_BLACK_PANDA){
// turn on GMLAN // turn on GMLAN
set_gpio_output(GPIOB, 14, enable); set_gpio_output(GPIOB, 14, enable);

View File

@ -135,6 +135,12 @@ class Panda(object):
REQUEST_IN = usb1.ENDPOINT_IN | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE REQUEST_IN = usb1.ENDPOINT_IN | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE
REQUEST_OUT = usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE REQUEST_OUT = usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE
HW_TYPE_UNKNOWN = '\x00'
HW_TYPE_WHITE_PANDA = '\x01'
HW_TYPE_GREY_PANDA = '\x02'
HW_TYPE_BLACK_PANDA = '\x03'
HW_TYPE_PEDAL = '\x04'
def __init__(self, serial=None, claim=True): def __init__(self, serial=None, claim=True):
self._serial = serial self._serial = serial
self._handle = None self._handle = None
@ -363,11 +369,14 @@ class Panda(object):
def get_type(self): def get_type(self):
return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40) return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
def is_white(self):
return self.get_type() == Panda.HW_TYPE_WHITE_PANDA
def is_grey(self): def is_grey(self):
return self.get_type() == "\x02" return self.get_type() == Panda.HW_TYPE_GREY_PANDA
def is_black(self): def is_black(self):
return self.get_type() == "\x03" return self.get_type() == Panda.HW_TYPE_BLACK_PANDA
def get_serial(self): def get_serial(self):
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 0, 0, 0x20) dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 0, 0, 0x20)
@ -470,6 +479,7 @@ class Panda(object):
break break
except (usb1.USBErrorIO, usb1.USBErrorOverflow): except (usb1.USBErrorIO, usb1.USBErrorOverflow):
print("CAN: BAD RECV, RETRYING") print("CAN: BAD RECV, RETRYING")
time.sleep(0.1)
return parse_can_buffer(dat) return parse_can_buffer(dat)
def can_clear(self, bus): def can_clear(self, bus):

View File

@ -1,15 +1,13 @@
import os import os
from panda import Panda from panda import Panda
from helpers import panda_color_to_serial, test_white_and_grey from helpers import panda_type_to_serial, test_white_and_grey, test_all_pandas, panda_connect_and_init
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_recover(serial=None): def test_recover(p):
p = Panda(serial=serial)
assert p.recover(timeout=30) assert p.recover(timeout=30)
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_flash(serial=None): def test_flash(p):
p = Panda(serial=serial)
p.flash() p.flash()

View File

@ -4,16 +4,11 @@ import sys
import time import time
from panda import Panda from panda import Panda
from nose.tools import assert_equal, assert_less, assert_greater from nose.tools import assert_equal, assert_less, assert_greater
from helpers import time_many_sends, connect_wo_esp, test_white_and_grey, panda_color_to_serial from helpers import SPEED_NORMAL, SPEED_GMLAN, time_many_sends, test_white_and_grey, panda_type_to_serial, test_all_pandas, panda_connect_and_init
SPEED_NORMAL = 500
SPEED_GMLAN = 33.3
@test_white_and_grey
@panda_color_to_serial
def test_can_loopback(serial=None):
p = connect_wo_esp(serial)
@test_all_pandas
@panda_connect_and_init
def test_can_loopback(p):
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
@ -26,9 +21,6 @@ def test_can_loopback(serial=None):
busses = [0,1,2] busses = [0,1,2]
for bus in busses: for bus in busses:
# send heartbeat
p.send_heartbeat()
# set bus 0 speed to 250 # set bus 0 speed to 250
p.set_can_speed_kbps(bus, 250) p.set_can_speed_kbps(bus, 250)
@ -47,17 +39,12 @@ def test_can_loopback(serial=None):
assert 0x1aa == sr[0][0] == lb[0][0] assert 0x1aa == sr[0][0] == lb[0][0]
assert "message" == sr[0][2] == lb[0][2] assert "message" == sr[0][2] == lb[0][2]
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_safety_nooutput(serial=None): def test_safety_nooutput(p):
p = connect_wo_esp(serial)
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_NOOUTPUT) p.set_safety_mode(Panda.SAFETY_NOOUTPUT)
# send heartbeat
p.send_heartbeat()
# enable CAN loopback mode # enable CAN loopback mode
p.set_can_loopback(True) p.set_can_loopback(True)
@ -69,11 +56,9 @@ def test_safety_nooutput(serial=None):
r = p.can_recv() r = p.can_recv()
assert len(r) == 0 assert len(r) == 0
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_reliability(serial=None): def test_reliability(p):
p = connect_wo_esp(serial)
LOOP_COUNT = 100 LOOP_COUNT = 100
MSG_COUNT = 100 MSG_COUNT = 100
@ -82,17 +67,11 @@ def test_reliability(serial=None):
p.set_can_loopback(True) p.set_can_loopback(True)
p.set_can_speed_kbps(0, 1000) p.set_can_speed_kbps(0, 1000)
# send heartbeat
p.send_heartbeat()
addrs = range(100, 100+MSG_COUNT) addrs = range(100, 100+MSG_COUNT)
ts = [(j, 0, "\xaa"*8, 0) for j in addrs] ts = [(j, 0, "\xaa"*8, 0) for j in addrs]
# 100 loops # 100 loops
for i in range(LOOP_COUNT): for i in range(LOOP_COUNT):
# send heartbeat
p.send_heartbeat()
st = time.time() st = time.time()
p.can_send_many(ts) p.can_send_many(ts)
@ -115,17 +94,12 @@ def test_reliability(serial=None):
sys.stdout.write("P") sys.stdout.write("P")
sys.stdout.flush() sys.stdout.flush()
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_throughput(serial=None): def test_throughput(p):
p = connect_wo_esp(serial)
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# send heartbeat
p.send_heartbeat()
# enable CAN loopback mode # enable CAN loopback mode
p.set_can_loopback(True) p.set_can_loopback(True)
@ -134,9 +108,6 @@ def test_throughput(serial=None):
p.set_can_speed_kbps(0, speed) p.set_can_speed_kbps(0, speed)
time.sleep(0.05) time.sleep(0.05)
# send heartbeat
p.send_heartbeat()
comp_kbps = time_many_sends(p, 0) comp_kbps = time_many_sends(p, 0)
# bit count from https://en.wikipedia.org/wiki/CAN_bus # bit count from https://en.wikipedia.org/wiki/CAN_bus
@ -147,19 +118,15 @@ def test_throughput(serial=None):
print("loopback 100 messages at speed %d, comp speed is %.2f, percent %.2f" % (speed, comp_kbps, saturation_pct)) print("loopback 100 messages at speed %d, comp speed is %.2f, percent %.2f" % (speed, comp_kbps, saturation_pct))
@test_white_and_grey @test_white_and_grey
@panda_color_to_serial @panda_type_to_serial
def test_gmlan(serial=None): @panda_connect_and_init
p = connect_wo_esp(serial) def test_gmlan(p):
if p.legacy: if p.legacy:
return return
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# send heartbeat
p.send_heartbeat()
# enable CAN loopback mode # enable CAN loopback mode
p.set_can_loopback(True) p.set_can_loopback(True)
@ -169,9 +136,6 @@ def test_gmlan(serial=None):
# set gmlan on CAN2 # set gmlan on CAN2
for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3, Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3, Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]:
# send heartbeat
p.send_heartbeat()
p.set_gmlan(bus) p.set_gmlan(bus)
comp_kbps_gmlan = time_many_sends(p, 3) comp_kbps_gmlan = time_many_sends(p, 3)
assert_greater(comp_kbps_gmlan, 0.8 * SPEED_GMLAN) assert_greater(comp_kbps_gmlan, 0.8 * SPEED_GMLAN)
@ -185,27 +149,20 @@ def test_gmlan(serial=None):
print("%d: %.2f kbps vs %.2f kbps" % (bus, comp_kbps_gmlan, comp_kbps_normal)) print("%d: %.2f kbps vs %.2f kbps" % (bus, comp_kbps_gmlan, comp_kbps_normal))
@test_white_and_grey @test_white_and_grey
@panda_color_to_serial @panda_type_to_serial
def test_gmlan_bad_toggle(serial=None): @panda_connect_and_init
p = connect_wo_esp(serial) def test_gmlan_bad_toggle(p):
if p.legacy: if p.legacy:
return return
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# send heartbeat
p.send_heartbeat()
# enable CAN loopback mode # enable CAN loopback mode
p.set_can_loopback(True) p.set_can_loopback(True)
# GMLAN_CAN2 # GMLAN_CAN2
for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]:
# send heartbeat
p.send_heartbeat()
p.set_gmlan(bus) p.set_gmlan(bus)
comp_kbps_gmlan = time_many_sends(p, 3) comp_kbps_gmlan = time_many_sends(p, 3)
assert_greater(comp_kbps_gmlan, 0.6 * SPEED_GMLAN) assert_greater(comp_kbps_gmlan, 0.6 * SPEED_GMLAN)
@ -213,9 +170,6 @@ def test_gmlan_bad_toggle(serial=None):
# normal # normal
for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: for bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]:
# send heartbeat
p.send_heartbeat()
p.set_gmlan(None) p.set_gmlan(None)
comp_kbps_normal = time_many_sends(p, bus) comp_kbps_normal = time_many_sends(p, bus)
assert_greater(comp_kbps_normal, 0.6 * SPEED_NORMAL) assert_greater(comp_kbps_normal, 0.6 * SPEED_NORMAL)
@ -223,10 +177,9 @@ def test_gmlan_bad_toggle(serial=None):
# this will fail if you have hardware serial connected # this will fail if you have hardware serial connected
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_serial_debug(serial=None): def test_serial_debug(p):
p = connect_wo_esp(serial)
junk = p.serial_read(Panda.SERIAL_DEBUG) junk = p.serial_read(Panda.SERIAL_DEBUG)
p.call_control_api(0xc0) p.call_control_api(0xc0)
assert(p.serial_read(Panda.SERIAL_DEBUG).startswith("can ")) assert(p.serial_read(Panda.SERIAL_DEBUG).startswith("can "))

View File

@ -2,46 +2,44 @@ from __future__ import print_function
import os import os
import time import time
from panda import Panda from panda import Panda
from helpers import connect_wifi, test_white, test_white_and_grey, panda_color_to_serial from helpers import connect_wifi, test_white, test_all_pandas, panda_type_to_serial, panda_connect_and_init
import requests import requests
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_get_serial(serial=None): def test_get_serial(p):
p = Panda(serial)
print(p.get_serial()) print(p.get_serial())
@test_white_and_grey @test_all_pandas
@panda_color_to_serial @panda_connect_and_init
def test_get_serial_in_flash_mode(serial=None): def test_get_serial_in_flash_mode(p):
p = Panda(serial)
p.reset(enter_bootstub=True) p.reset(enter_bootstub=True)
assert(p.bootstub) assert(p.bootstub)
print(p.get_serial()) print(p.get_serial())
p.reset() p.reset()
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_connect_wifi(serial=None): def test_connect_wifi(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_flash_wifi(serial=None): def test_flash_wifi(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
assert Panda.flash_ota_wifi(release=False), "OTA Wifi Flash Failed" assert Panda.flash_ota_wifi(release=False), "OTA Wifi Flash Failed"
connect_wifi(serial) connect_wifi(serials[0])
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_wifi_flash_st(serial=None): def test_wifi_flash_st(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
assert Panda.flash_ota_st(), "OTA ST Flash Failed" assert Panda.flash_ota_st(), "OTA ST Flash Failed"
connected = False connected = False
st = time.time() st = time.time()
while not connected and (time.time() - st) < 20: while not connected and (time.time() - st) < 20:
try: try:
p = Panda(serial=serial) p = Panda(serial=serials[0])
p.get_serial() p.get_serial()
connected = True connected = True
except: except:
@ -51,9 +49,9 @@ def test_wifi_flash_st(serial=None):
assert False, "Panda failed to connect on USB after flashing" assert False, "Panda failed to connect on USB after flashing"
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_webpage_fetch(serial=None): def test_webpage_fetch(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
r = requests.get("http://192.168.0.10/") r = requests.get("http://192.168.0.10/")
print(r.text) print(r.text)

View File

@ -1,38 +1,32 @@
from __future__ import print_function from __future__ import print_function
import time import time
from panda import Panda from panda import Panda
from helpers import time_many_sends, connect_wifi, test_white, panda_color_to_serial from helpers import time_many_sends, connect_wifi, test_white, panda_type_to_serial
from nose.tools import timed, assert_equal, assert_less, assert_greater from nose.tools import timed, assert_equal, assert_less, assert_greater
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_get_serial_wifi(serial=None): def test_get_serial_wifi(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
p = Panda("WIFI") p = Panda("WIFI")
print(p.get_serial()) print(p.get_serial())
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_throughput(serial=None): def test_throughput(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
p = Panda(serial) p = Panda(serials[0])
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# send heartbeat
p.send_heartbeat()
# enable CAN loopback mode # enable CAN loopback mode
p.set_can_loopback(True) p.set_can_loopback(True)
p = Panda("WIFI") p = Panda("WIFI")
for speed in [100,250,500,750,1000]: for speed in [100,250,500,750,1000]:
# send heartbeat
p.send_heartbeat()
# set bus 0 speed to speed # set bus 0 speed to speed
p.set_can_speed_kbps(0, speed) p.set_can_speed_kbps(0, speed)
time.sleep(0.1) time.sleep(0.1)
@ -47,23 +41,17 @@ def test_throughput(serial=None):
print("WIFI loopback 100 messages at speed %d, comp speed is %.2f, percent %.2f" % (speed, comp_kbps, saturation_pct)) print("WIFI loopback 100 messages at speed %d, comp speed is %.2f, percent %.2f" % (speed, comp_kbps, saturation_pct))
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_recv_only(serial=None): def test_recv_only(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
p = Panda(serial) p = Panda(serials[0])
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# send heartbeat
p.send_heartbeat()
p.set_can_loopback(True) p.set_can_loopback(True)
pwifi = Panda("WIFI") pwifi = Panda("WIFI")
# TODO: msg_count=1000 drops packets, is this fixable? # TODO: msg_count=1000 drops packets, is this fixable?
for msg_count in [10,100,200]: for msg_count in [10,100,200]:
# send heartbeat
p.send_heartbeat()
speed = 500 speed = 500
p.set_can_speed_kbps(0, speed) p.set_can_speed_kbps(0, speed)
comp_kbps = time_many_sends(p, 0, pwifi, msg_count) comp_kbps = time_many_sends(p, 0, pwifi, msg_count)

View File

@ -1,16 +1,16 @@
from __future__ import print_function from __future__ import print_function
import sys import sys
import time import time
from helpers import time_many_sends, connect_wifi, test_white, panda_color_to_serial from helpers import time_many_sends, connect_wifi, test_white, panda_type_to_serial
from panda import Panda, PandaWifiStreaming from panda import Panda, PandaWifiStreaming
from nose.tools import timed, assert_equal, assert_less, assert_greater from nose.tools import timed, assert_equal, assert_less, assert_greater
@test_white @test_white
@panda_color_to_serial @panda_type_to_serial
def test_udp_doesnt_drop(serial=None): def test_udp_doesnt_drop(serials=None):
connect_wifi(serial) connect_wifi(serials[0])
p = Panda(serial) p = Panda(serials[0])
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p.set_can_loopback(True) p.set_can_loopback(True)

View File

@ -1,21 +1,18 @@
from __future__ import print_function from __future__ import print_function
import os
import time import time
import random
from panda import Panda from panda import Panda
from nose.tools import assert_equal, assert_less, assert_greater from nose.tools import assert_equal, assert_less, assert_greater
from helpers import time_many_sends, test_two_panda, panda_color_to_serial from helpers import time_many_sends, test_two_panda, test_two_black_panda, panda_type_to_serial, clear_can_buffers, panda_connect_and_init
@test_two_panda @test_two_panda
@panda_color_to_serial @panda_type_to_serial
def test_send_recv(serial_sender=None, serial_reciever=None): @panda_connect_and_init
p_send = Panda(serial_sender) def test_send_recv(p_send, p_recv):
p_recv = Panda(serial_reciever)
p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p_recv.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p_send.set_can_loopback(False) p_send.set_can_loopback(False)
# send heartbeat
p_send.send_heartbeat()
p_recv.set_can_loopback(False) p_recv.set_can_loopback(False)
assert not p_send.legacy assert not p_send.legacy
@ -30,9 +27,6 @@ def test_send_recv(serial_sender=None, serial_reciever=None):
for bus in busses: for bus in busses:
for speed in [100, 250, 500, 750, 1000]: for speed in [100, 250, 500, 750, 1000]:
# send heartbeat
p_send.send_heartbeat()
p_send.set_can_speed_kbps(bus, speed) p_send.set_can_speed_kbps(bus, speed)
p_recv.set_can_speed_kbps(bus, speed) p_recv.set_can_speed_kbps(bus, speed)
time.sleep(0.05) time.sleep(0.05)
@ -46,18 +40,12 @@ def test_send_recv(serial_sender=None, serial_reciever=None):
print("two pandas bus {}, 100 messages at speed {:4d}, comp speed is {:7.2f}, percent {:6.2f}".format(bus, speed, comp_kbps, saturation_pct)) print("two pandas bus {}, 100 messages at speed {:4d}, comp speed is {:7.2f}, percent {:6.2f}".format(bus, speed, comp_kbps, saturation_pct))
@test_two_panda @test_two_panda
@panda_color_to_serial @panda_type_to_serial
def test_latency(serial_sender=None, serial_reciever=None): @panda_connect_and_init
p_send = Panda(serial_sender) def test_latency(p_send, p_recv):
p_recv = Panda(serial_reciever)
# send heartbeat
p_send.send_heartbeat()
p_recv.send_heartbeat()
p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p_recv.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p_send.set_can_loopback(False) p_send.set_can_loopback(False)
p_recv.set_can_loopback(False) p_recv.set_can_loopback(False)
assert not p_send.legacy assert not p_send.legacy
@ -72,29 +60,17 @@ def test_latency(serial_sender=None, serial_reciever=None):
p_recv.can_recv() p_recv.can_recv()
p_send.can_recv() p_send.can_recv()
# send heartbeat
p_send.send_heartbeat()
p_recv.send_heartbeat()
busses = [0,1,2] busses = [0,1,2]
for bus in busses: for bus in busses:
for speed in [100, 250, 500, 750, 1000]: for speed in [100, 250, 500, 750, 1000]:
# send heartbeat
p_send.send_heartbeat()
p_recv.send_heartbeat()
p_send.set_can_speed_kbps(bus, speed) p_send.set_can_speed_kbps(bus, speed)
p_recv.set_can_speed_kbps(bus, speed) p_recv.set_can_speed_kbps(bus, speed)
time.sleep(0.1) time.sleep(0.1)
#clear can buffers #clear can buffers
r = [1] clear_can_buffers(p_send)
while len(r) > 0: clear_can_buffers(p_recv)
r = p_send.can_recv()
r = [1]
while len(r) > 0:
r = p_recv.can_recv()
time.sleep(0.05)
latencies = [] latencies = []
comp_kbps_list = [] comp_kbps_list = []
@ -137,3 +113,83 @@ def test_latency(serial_sender=None, serial_reciever=None):
print("two pandas bus {}, {} message average at speed {:4d}, latency is {:5.3f}ms, comp speed is {:7.2f}, percent {:6.2f}"\ print("two pandas bus {}, {} message average at speed {:4d}, latency is {:5.3f}ms, comp speed is {:7.2f}, percent {:6.2f}"\
.format(bus, num_messages, speed, average_latency, average_comp_kbps, average_saturation_pct)) .format(bus, num_messages, speed, average_latency, average_comp_kbps, average_saturation_pct))
@test_two_black_panda
@panda_type_to_serial
@panda_connect_and_init
def test_black_loopback(panda0, panda1):
# disable safety modes
panda0.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
panda1.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# disable loopback
panda0.set_can_loopback(False)
panda1.set_can_loopback(False)
# clear stuff
panda0.can_send_many([(0x1ba, 0, "testmsg", 0)]*10)
time.sleep(0.05)
panda0.can_recv()
panda1.can_recv()
# test array (send bus, sender obd, reciever obd, expected busses)
test_array = [
(0, False, False, [0]),
(1, False, False, [1]),
(2, False, False, [2]),
(0, False, True, [0, 1]),
(1, False, True, []),
(2, False, True, [2]),
(0, True, False, [0]),
(1, True, False, [0]),
(2, True, False, [2]),
(0, True, True, [0, 1]),
(1, True, True, [0, 1]),
(2, True, True, [2])
]
# test functions
def get_test_string():
return b"test"+os.urandom(10)
def _test_buses(send_panda, recv_panda, _test_array):
for send_bus, send_obd, recv_obd, recv_buses in _test_array:
print("\nSend bus:", send_bus, " Send OBD:", send_obd, " Recv OBD:", recv_obd)
# set OBD on pandas
send_panda.set_gmlan(True if send_obd else None)
recv_panda.set_gmlan(True if recv_obd else None)
# clear buffers
clear_can_buffers(send_panda)
clear_can_buffers(recv_panda)
# send the characters
at = random.randint(1, 2000)
st = get_test_string()[0:8]
send_panda.can_send(at, st, send_bus)
time.sleep(0.1)
# check for receive
cans_echo = send_panda.can_recv()
cans_loop = recv_panda.can_recv()
loop_buses = []
for loop in cans_loop:
print(" Loop on bus", str(loop[3]))
loop_buses.append(loop[3])
if len(cans_loop) == 0:
print(" No loop")
# test loop buses
recv_buses.sort()
loop_buses.sort()
assert recv_buses == loop_buses
print(" TEST PASSED")
print("\n")
# test both orientations
print("***************** TESTING (0 --> 1) *****************")
_test_buses(panda0, panda1, test_array)
print("***************** TESTING (1 --> 0) *****************")
_test_buses(panda1, panda0, test_array)

View File

@ -4,43 +4,41 @@ import time
import random import random
import subprocess import subprocess
import requests import requests
import thread
from functools import wraps from functools import wraps
from panda import Panda from panda import Panda
from nose.tools import timed, assert_equal, assert_less, assert_greater from nose.tools import timed, assert_equal, assert_less, assert_greater
from parameterized import parameterized, param from parameterized import parameterized, param
test_white_and_grey = parameterized([param(panda_color="White"), SPEED_NORMAL = 500
param(panda_color="Grey")]) SPEED_GMLAN = 33.3
test_white = parameterized([param(panda_color="White")])
test_grey = parameterized([param(panda_color="Grey")])
test_two_panda = parameterized([param(panda_color=["Grey", "White"]),
param(panda_color=["White", "Grey"])])
_serials = {} test_all_types = parameterized([
def get_panda_serial(is_grey=None): param(panda_type=Panda.HW_TYPE_WHITE_PANDA),
global _serials param(panda_type=Panda.HW_TYPE_GREY_PANDA),
if is_grey not in _serials: param(panda_type=Panda.HW_TYPE_BLACK_PANDA)
for serial in Panda.list(): ])
p = Panda(serial=serial) test_all_pandas = parameterized(
if is_grey is None or p.is_grey() == is_grey: Panda.list()
_serials[is_grey] = serial )
return serial test_white_and_grey = parameterized([
raise IOError("Panda not found. is_grey: {}".format(is_grey)) param(panda_type=Panda.HW_TYPE_WHITE_PANDA),
else: param(panda_type=Panda.HW_TYPE_GREY_PANDA)
return _serials[is_grey] ])
test_white = parameterized([
def connect_wo_esp(serial=None): param(panda_type=Panda.HW_TYPE_WHITE_PANDA)
# connect to the panda ])
p = Panda(serial=serial) test_grey = parameterized([
param(panda_type=Panda.HW_TYPE_GREY_PANDA)
# power down the ESP ])
p.set_esp_power(False) test_two_panda = parameterized([
param(panda_type=[Panda.HW_TYPE_GREY_PANDA, Panda.HW_TYPE_WHITE_PANDA]),
# clear old junk param(panda_type=[Panda.HW_TYPE_WHITE_PANDA, Panda.HW_TYPE_GREY_PANDA]),
while len(p.can_recv()) > 0: param(panda_type=[Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_BLACK_PANDA])
pass ])
test_two_black_panda = parameterized([
return p param(panda_type=[Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_BLACK_PANDA])
])
def connect_wifi(serial=None): def connect_wifi(serial=None):
p = Panda(serial=serial) p = Panda(serial=serial)
@ -170,23 +168,93 @@ def time_many_sends(p, bus, precv=None, msg_count=100, msg_id=None, two_pandas=F
return comp_kbps return comp_kbps
_panda_serials = None
def panda_color_to_serial(fn): def panda_type_to_serial(fn):
@wraps(fn) @wraps(fn)
def wrapper(panda_color=None, **kwargs): def wrapper(panda_type=None, **kwargs):
pandas_is_grey = [] # Change panda_types to a list
if panda_color is not None: if panda_type is not None:
if not isinstance(panda_color, list): if not isinstance(panda_type, list):
panda_color = [panda_color] panda_type = [panda_type]
panda_color = [s.lower() for s in panda_color]
for p in panda_color: # If not done already, get panda serials and their type
if p is None: global _panda_serials
pandas_is_grey.append(None) if _panda_serials == None:
elif p in ["grey", "gray"]: _panda_serials = []
pandas_is_grey.append(True) for serial in Panda.list():
elif p in ["white"]: p = Panda(serial=serial)
pandas_is_grey.append(False) _panda_serials.append((serial, p.get_type()))
else: p.close()
raise ValueError("Invalid Panda Color {}".format(p))
return fn(*[get_panda_serial(is_grey) for is_grey in pandas_is_grey], **kwargs) # Find a panda with the correct types and add the corresponding serial
serials = []
for p_type in panda_type:
found = False
for serial, pt in _panda_serials:
# Never take the same panda twice
if (pt == p_type) and (serial not in serials):
serials.append(serial)
found = True
break
if not found:
raise IOError("No unused panda found for type: {}".format(p_type))
return fn(serials, **kwargs)
return wrapper return wrapper
def heartbeat_thread(p):
while True:
try:
p.send_heartbeat()
time.sleep(1)
except:
break
def panda_connect_and_init(fn):
@wraps(fn)
def wrapper(panda_serials=None, **kwargs):
# Change panda_serials to a list
if panda_serials is not None:
if not isinstance(panda_serials, list):
panda_serials = [panda_serials]
# Connect to pandas
pandas = []
for panda_serial in panda_serials:
pandas.append(Panda(serial=panda_serial))
# Initialize pandas
for panda in pandas:
panda.set_can_loopback(False)
panda.set_gmlan(None)
panda.set_esp_power(False)
for bus, speed in [(0, SPEED_NORMAL), (1, SPEED_NORMAL), (2, SPEED_NORMAL), (3, SPEED_GMLAN)]:
panda.set_can_speed_kbps(bus, speed)
clear_can_buffers(panda)
thread.start_new_thread(heartbeat_thread, (panda,))
# Run test function
ret = fn(*pandas, **kwargs)
# Close all connections
for panda in pandas:
panda.close()
# Return test function result
return ret
return wrapper
def clear_can_buffers(panda):
# clear tx buffers
for i in range(4):
panda.can_clear(i)
# clear rx buffers
panda.can_clear(0xFFFF)
r = [1]
st = time.time()
while len(r) > 0:
r = panda.can_recv()
time.sleep(0.05)
if (time.time() - st) > 10:
print("Unable to clear can buffers for panda ", panda.get_serial())
assert False

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# Loopback test between black panda (+ harness and power) and white/grey panda # Loopback test between two black pandas (+ harness and power)
# Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test. # Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test.
# To be sure, the test should be run with both harness orientations # To be sure, the test should be run with both harness orientations
@ -33,81 +33,70 @@ def run_test(sleep_duration):
pandas[0] = Panda(pandas[0]) pandas[0] = Panda(pandas[0])
pandas[1] = Panda(pandas[1]) pandas[1] = Panda(pandas[1])
# find out which one is black # find out the hardware types
type0 = pandas[0].get_type() type0 = pandas[0].get_type()
type1 = pandas[1].get_type() type1 = pandas[1].get_type()
black_panda = None
other_panda = None
if type0 == "\x03" and type1 != "\x03": if type0 != "\x03" or type1 != "\x03":
black_panda = pandas[0] print("Connect two black pandas to run this test!")
other_panda = pandas[1]
elif type0 != "\x03" and type1 == "\x03":
black_panda = pandas[1]
other_panda = pandas[0]
else:
print("Connect white/grey and black panda to run this test!")
assert False assert False
# disable safety modes for panda in pandas:
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT) # disable safety modes
other_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT) panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# test health packet # test health packet
print("black panda health", black_panda.health()) print("panda health", panda.health())
print("other panda health", other_panda.health())
# test black -> other # setup test array (send bus, sender obd, reciever obd, expected busses)
test_buses(black_panda, other_panda, True, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (1, True, [0])], sleep_duration) test_array = [
test_buses(black_panda, other_panda, False, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (0, True, [0, 1])], sleep_duration) (0, False, False, [0]),
(1, False, False, [1]),
(2, False, False, [2]),
(0, False, True, [0, 1]),
(1, False, True, []),
(2, False, True, [2]),
(0, True, False, [0]),
(1, True, False, [0]),
(2, True, False, [2]),
(0, True, True, [0, 1]),
(1, True, True, [0, 1]),
(2, True, True, [2])
]
# test both orientations
print("***************** TESTING (0 --> 1) *****************")
test_buses(pandas[0], pandas[1], test_array, sleep_duration)
print("***************** TESTING (1 --> 0) *****************")
test_buses(pandas[1], pandas[0], test_array, sleep_duration)
def test_buses(black_panda, other_panda, direction, test_array, sleep_duration): def test_buses(send_panda, recv_panda, test_array, sleep_duration):
if direction: for send_bus, send_obd, recv_obd, recv_buses in test_array:
print("***************** TESTING (BLACK --> OTHER) *****************") send_panda.send_heartbeat()
else: recv_panda.send_heartbeat()
print("***************** TESTING (OTHER --> BLACK) *****************") print("\nSend bus:", send_bus, " Send OBD:", send_obd, " Recv OBD:", recv_obd)
for send_bus, obd, recv_buses in test_array:
black_panda.send_heartbeat()
other_panda.send_heartbeat()
print("\ntest can: ", send_bus, " OBD: ", obd)
# set OBD on black panda # set OBD on pandas
black_panda.set_gmlan(True if obd else None) send_panda.set_gmlan(True if send_obd else None)
recv_panda.set_gmlan(True if recv_obd else None)
# clear and flush # clear and flush
if direction: send_panda.can_clear(send_bus)
black_panda.can_clear(send_bus)
else:
other_panda.can_clear(send_bus)
for recv_bus in recv_buses: for recv_bus in recv_buses:
if direction: recv_panda.can_clear(recv_bus)
other_panda.can_clear(recv_bus) send_panda.can_recv()
else: recv_panda.can_recv()
black_panda.can_clear(recv_bus)
black_panda.can_recv()
other_panda.can_recv()
# send the characters # send the characters
at = random.randint(1, 2000) at = random.randint(1, 2000)
st = get_test_string()[0:8] st = get_test_string()[0:8]
if direction: send_panda.can_send(at, st, send_bus)
black_panda.can_send(at, st, send_bus)
else:
other_panda.can_send(at, st, send_bus)
time.sleep(0.1) time.sleep(0.1)
# check for receive # check for receive
if direction: cans_echo = send_panda.can_recv()
cans_echo = black_panda.can_recv() cans_loop = recv_panda.can_recv()
cans_loop = other_panda.can_recv()
else:
cans_echo = other_panda.can_recv()
cans_loop = black_panda.can_recv()
loop_buses = [] loop_buses = []
for loop in cans_loop: for loop in cans_loop:

View File

@ -0,0 +1,169 @@
#!/usr/bin/env python
# Loopback test between black panda (+ harness and power) and white/grey panda
# Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test.
# To be sure, the test should be run with both harness orientations
from __future__ import print_function
import os
import sys
import time
import random
import argparse
from hexdump import hexdump
from itertools import permutations
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
from panda import Panda
def get_test_string():
return b"test"+os.urandom(10)
counter = 0
nonzero_bus_errors = 0
zero_bus_errors = 0
content_errors = 0
def run_test(sleep_duration):
global counter, nonzero_bus_errors, zero_bus_errors, content_errors
pandas = Panda.list()
print(pandas)
# make sure two pandas are connected
if len(pandas) != 2:
print("Connect white/grey and black panda to run this test!")
assert False
# connect
pandas[0] = Panda(pandas[0])
pandas[1] = Panda(pandas[1])
# find out which one is black
type0 = pandas[0].get_type()
type1 = pandas[1].get_type()
black_panda = None
other_panda = None
if type0 == "\x03" and type1 != "\x03":
black_panda = pandas[0]
other_panda = pandas[1]
elif type0 != "\x03" and type1 == "\x03":
black_panda = pandas[1]
other_panda = pandas[0]
else:
print("Connect white/grey and black panda to run this test!")
assert False
# disable safety modes
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
other_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# test health packet
print("black panda health", black_panda.health())
print("other panda health", other_panda.health())
# test black -> other
while True:
test_buses(black_panda, other_panda, True, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (1, True, [0])], sleep_duration)
test_buses(black_panda, other_panda, False, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (0, True, [0, 1])], sleep_duration)
counter += 1
print("Number of cycles:", counter, "Non-zero bus errors:", nonzero_bus_errors, "Zero bus errors:", zero_bus_errors, "Content errors:", content_errors)
# Toggle relay
black_panda.set_safety_mode(Panda.SAFETY_NOOUTPUT)
time.sleep(1)
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
time.sleep(1)
def test_buses(black_panda, other_panda, direction, test_array, sleep_duration):
global nonzero_bus_errors, zero_bus_errors, content_errors
if direction:
print("***************** TESTING (BLACK --> OTHER) *****************")
else:
print("***************** TESTING (OTHER --> BLACK) *****************")
for send_bus, obd, recv_buses in test_array:
black_panda.send_heartbeat()
other_panda.send_heartbeat()
print("\ntest can: ", send_bus, " OBD: ", obd)
# set OBD on black panda
black_panda.set_gmlan(True if obd else None)
# clear and flush
if direction:
black_panda.can_clear(send_bus)
else:
other_panda.can_clear(send_bus)
for recv_bus in recv_buses:
if direction:
other_panda.can_clear(recv_bus)
else:
black_panda.can_clear(recv_bus)
black_panda.can_recv()
other_panda.can_recv()
# send the characters
at = random.randint(1, 2000)
st = get_test_string()[0:8]
if direction:
black_panda.can_send(at, st, send_bus)
else:
other_panda.can_send(at, st, send_bus)
time.sleep(0.1)
# check for receive
if direction:
cans_echo = black_panda.can_recv()
cans_loop = other_panda.can_recv()
else:
cans_echo = other_panda.can_recv()
cans_loop = black_panda.can_recv()
loop_buses = []
for loop in cans_loop:
if (loop[0] != at) or (loop[2] != st):
content_errors += 1
print(" Loop on bus", str(loop[3]))
loop_buses.append(loop[3])
if len(cans_loop) == 0:
print(" No loop")
if not os.getenv("NOASSERT"):
assert False
# test loop buses
recv_buses.sort()
loop_buses.sort()
if(recv_buses != loop_buses):
if len(loop_buses) == 0:
zero_bus_errors += 1
else:
nonzero_bus_errors += 1
if not os.getenv("NOASSERT"):
assert False
else:
print(" TEST PASSED")
time.sleep(sleep_duration)
print("\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-n", type=int, help="Number of test iterations to run")
parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0)
args = parser.parse_args()
if args.n is None:
while True:
run_test(sleep_duration=args.sleep)
else:
for i in range(args.n):
run_test(sleep_duration=args.sleep)

View File

@ -0,0 +1,175 @@
#!/usr/bin/env python
# Loopback test between black panda (+ harness and power) and white/grey panda
# Tests all buses, including OBD CAN, which is on the same bus as CAN0 in this test.
# To be sure, the test should be run with both harness orientations
from __future__ import print_function
import os
import sys
import time
import random
import argparse
from hexdump import hexdump
from itertools import permutations
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
from panda import Panda
def get_test_string():
return b"test"+os.urandom(10)
counter = 0
nonzero_bus_errors = 0
zero_bus_errors = 0
content_errors = 0
def run_test(sleep_duration):
global counter, nonzero_bus_errors, zero_bus_errors, content_errors
pandas = Panda.list()
print(pandas)
# make sure two pandas are connected
if len(pandas) != 2:
print("Connect white/grey and black panda to run this test!")
assert False
# connect
pandas[0] = Panda(pandas[0])
pandas[1] = Panda(pandas[1])
# find out which one is black
type0 = pandas[0].get_type()
type1 = pandas[1].get_type()
black_panda = None
other_panda = None
if type0 == "\x03" and type1 != "\x03":
black_panda = pandas[0]
other_panda = pandas[1]
elif type0 != "\x03" and type1 == "\x03":
black_panda = pandas[1]
other_panda = pandas[0]
else:
print("Connect white/grey and black panda to run this test!")
assert False
# disable safety modes
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
other_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# test health packet
print("black panda health", black_panda.health())
print("other panda health", other_panda.health())
# test black -> other
start_time = time.time()
temp_start_time = start_time
while True:
test_buses(black_panda, other_panda, True, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (1, True, [0])], sleep_duration)
test_buses(black_panda, other_panda, False, [(0, False, [0]), (1, False, [1]), (2, False, [2]), (0, True, [0, 1])], sleep_duration)
counter += 1
runtime = time.time() - start_time
print("Number of cycles:", counter, "Non-zero bus errors:", nonzero_bus_errors, "Zero bus errors:", zero_bus_errors, "Content errors:", content_errors, "Runtime: ", runtime)
if (time.time() - temp_start_time) > 3600*6:
# Toggle relay
black_panda.set_safety_mode(Panda.SAFETY_NOOUTPUT)
time.sleep(1)
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
time.sleep(1)
temp_start_time = time.time()
def test_buses(black_panda, other_panda, direction, test_array, sleep_duration):
global nonzero_bus_errors, zero_bus_errors, content_errors
if direction:
print("***************** TESTING (BLACK --> OTHER) *****************")
else:
print("***************** TESTING (OTHER --> BLACK) *****************")
for send_bus, obd, recv_buses in test_array:
black_panda.send_heartbeat()
other_panda.send_heartbeat()
print("\ntest can: ", send_bus, " OBD: ", obd)
# set OBD on black panda
black_panda.set_gmlan(True if obd else None)
# clear and flush
if direction:
black_panda.can_clear(send_bus)
else:
other_panda.can_clear(send_bus)
for recv_bus in recv_buses:
if direction:
other_panda.can_clear(recv_bus)
else:
black_panda.can_clear(recv_bus)
black_panda.can_recv()
other_panda.can_recv()
# send the characters
at = random.randint(1, 2000)
st = get_test_string()[0:8]
if direction:
black_panda.can_send(at, st, send_bus)
else:
other_panda.can_send(at, st, send_bus)
time.sleep(0.1)
# check for receive
if direction:
cans_echo = black_panda.can_recv()
cans_loop = other_panda.can_recv()
else:
cans_echo = other_panda.can_recv()
cans_loop = black_panda.can_recv()
loop_buses = []
for loop in cans_loop:
if (loop[0] != at) or (loop[2] != st):
content_errors += 1
print(" Loop on bus", str(loop[3]))
loop_buses.append(loop[3])
if len(cans_loop) == 0:
print(" No loop")
if not os.getenv("NOASSERT"):
assert False
# test loop buses
recv_buses.sort()
loop_buses.sort()
if(recv_buses != loop_buses):
if len(loop_buses) == 0:
zero_bus_errors += 1
else:
nonzero_bus_errors += 1
if not os.getenv("NOASSERT"):
assert False
else:
print(" TEST PASSED")
time.sleep(sleep_duration)
print("\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-n", type=int, help="Number of test iterations to run")
parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0)
args = parser.parse_args()
if args.n is None:
while True:
run_test(sleep_duration=args.sleep)
else:
for i in range(args.n):
run_test(sleep_duration=args.sleep)

View File

@ -0,0 +1,145 @@
#!/usr/bin/env python
# Relay test with loopback between black panda (+ harness and power) and white/grey panda
# Tests the relay switching multiple times / second by looking at the buses on which loop occurs.
from __future__ import print_function
import os
import sys
import time
import random
import argparse
from hexdump import hexdump
from itertools import permutations
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
from panda import Panda
def get_test_string():
return b"test"+os.urandom(10)
counter = 0
open_errors = 0
closed_errors = 0
content_errors = 0
def run_test(sleep_duration):
global counter, open_errors, closed_errors, content_errors
pandas = Panda.list()
#pandas = ["540046000c51363338383037", "07801b800f51363038363036"]
print(pandas)
# make sure two pandas are connected
if len(pandas) != 2:
print("Connect white/grey and black panda to run this test!")
assert False
# connect
pandas[0] = Panda(pandas[0])
pandas[1] = Panda(pandas[1])
# find out which one is black
type0 = pandas[0].get_type()
type1 = pandas[1].get_type()
black_panda = None
other_panda = None
if type0 == "\x03" and type1 != "\x03":
black_panda = pandas[0]
other_panda = pandas[1]
elif type0 != "\x03" and type1 == "\x03":
black_panda = pandas[1]
other_panda = pandas[0]
else:
print("Connect white/grey and black panda to run this test!")
assert False
# disable safety modes
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
other_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
# test health packet
print("black panda health", black_panda.health())
print("other panda health", other_panda.health())
# test black -> other
while True:
# Switch on relay
black_panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
time.sleep(0.05)
if not test_buses(black_panda, other_panda, (0, False, [0])):
open_errors += 1
print("Open error")
assert False
# Switch off relay
black_panda.set_safety_mode(Panda.SAFETY_NOOUTPUT)
time.sleep(0.05)
if not test_buses(black_panda, other_panda, (0, False, [0, 2])):
closed_errors += 1
print("Close error")
assert False
counter += 1
print("Number of cycles:", counter, "Open errors:", open_errors, "Closed errors:", closed_errors, "Content errors:", content_errors)
def test_buses(black_panda, other_panda, test_obj):
global content_errors
send_bus, obd, recv_buses = test_obj
black_panda.send_heartbeat()
other_panda.send_heartbeat()
# Set OBD on send panda
other_panda.set_gmlan(True if obd else None)
# clear and flush
other_panda.can_clear(send_bus)
for recv_bus in recv_buses:
black_panda.can_clear(recv_bus)
black_panda.can_recv()
other_panda.can_recv()
# send the characters
at = random.randint(1, 2000)
st = get_test_string()[0:8]
other_panda.can_send(at, st, send_bus)
time.sleep(0.05)
# check for receive
cans_echo = other_panda.can_recv()
cans_loop = black_panda.can_recv()
loop_buses = []
for loop in cans_loop:
if (loop[0] != at) or (loop[2] != st):
content_errors += 1
loop_buses.append(loop[3])
# test loop buses
recv_buses.sort()
loop_buses.sort()
if(recv_buses != loop_buses):
return False
else:
return True
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-n", type=int, help="Number of test iterations to run")
parser.add_argument("-sleep", type=int, help="Sleep time between tests", default=0)
args = parser.parse_args()
if args.n is None:
while True:
run_test(sleep_duration=args.sleep)
else:
for i in range(args.n):
run_test(sleep_duration=args.sleep)

View File

@ -12,33 +12,38 @@ setcolor = ["\033[1;32;40m", "\033[1;31;40m"]
unsetcolor = "\033[00m" unsetcolor = "\033[00m"
if __name__ == "__main__": if __name__ == "__main__":
port_number = int(os.getenv("PORT", 0))
claim = os.getenv("CLAIM") is not None
serials = Panda.list()
if os.getenv("SERIAL"):
serials = filter(lambda x: x==os.getenv("SERIAL"), serials)
pandas = list(map(lambda x: Panda(x, claim=claim), serials))
if not len(pandas):
sys.exit("no pandas found")
if os.getenv("BAUD") is not None:
for panda in pandas:
panda.set_uart_baud(port_number, int(os.getenv("BAUD")))
while True: while True:
for i, panda in enumerate(pandas): try:
port_number = int(os.getenv("PORT", 0))
claim = os.getenv("CLAIM") is not None
serials = Panda.list()
if os.getenv("SERIAL"):
serials = filter(lambda x: x==os.getenv("SERIAL"), serials)
pandas = list(map(lambda x: Panda(x, claim=claim), serials))
if not len(pandas):
sys.exit("no pandas found")
if os.getenv("BAUD") is not None:
for panda in pandas:
panda.set_uart_baud(port_number, int(os.getenv("BAUD")))
while True: while True:
ret = panda.serial_read(port_number) for i, panda in enumerate(pandas):
if len(ret) > 0: while True:
sys.stdout.write(setcolor[i] + str(ret) + unsetcolor) ret = panda.serial_read(port_number)
sys.stdout.flush() if len(ret) > 0:
else: sys.stdout.write(setcolor[i] + str(ret) + unsetcolor)
break sys.stdout.flush()
if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): else:
ln = sys.stdin.readline() break
if claim: if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
panda.serial_write(port_number, ln) ln = sys.stdin.readline()
time.sleep(0.01) if claim:
panda.serial_write(port_number, ln)
time.sleep(0.01)
except:
print("panda disconnected!")
time.sleep(0.5);

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
import time
from panda import Panda
if __name__ == "__main__":
panda_serials = Panda.list()
pandas = []
for ps in panda_serials:
pandas.append(Panda(serial=ps))
if len(pandas) == 0:
print("No pandas connected")
assert False
while True:
for panda in pandas:
print(panda.health())
print("\n")
time.sleep(0.5)