Merge panda subtree

pull/617/head
Vehicle Researcher 2019-04-23 01:34:19 +00:00
commit 7834995df4
37 changed files with 944 additions and 104 deletions

View File

@ -0,0 +1,3 @@
.git
.DS_Store
boardesp/esp-open-sdk

64
panda/Dockerfile 100644
View File

@ -0,0 +1,64 @@
FROM ubuntu:16.04
ENV PYTHONUNBUFFERED 1
RUN apt-get update && apt-get install -y \
autoconf \
automake \
bash \
bison \
bzip2 \
curl \
dfu-util \
flex \
g++ \
gawk \
gcc \
git \
gperf \
help2man \
iputils-ping \
libexpat-dev \
libstdc++-arm-none-eabi-newlib \
libtool \
libtool-bin \
libusb-1.0-0 \
make \
ncurses-dev \
network-manager \
python-dev \
python-serial \
sed \
texinfo \
unrar-free \
unzip \
wget \
build-essential \
python-dev \
python-pip \
screen \
vim \
wget \
wireless-tools
RUN pip install --upgrade pip==18.0
COPY requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt
RUN mkdir -p /home/batman
ENV HOME /home/batman
ENV PYTHONPATH /tmp:$PYTHONPATH
COPY ./boardesp/get_sdk_ci.sh /tmp/panda/boardesp/
RUN useradd --system -s /sbin/nologin pandauser
RUN mkdir -p /tmp/panda/boardesp/esp-open-sdk
RUN chown pandauser /tmp/panda/boardesp/esp-open-sdk
USER pandauser
RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh
USER root
COPY ./xx/pandaextra /tmp/pandaextra
ADD ./panda.tar.gz /tmp/panda

55
panda/Jenkinsfile vendored 100644
View File

@ -0,0 +1,55 @@
pipeline {
agent any
environment {
AUTHOR = """${sh(
returnStdout: true,
script: "git --no-pager show -s --format='%an' ${GIT_COMMIT}"
).trim()}"""
DOCKER_IMAGE_TAG = "panda:build-${env.BUILD_ID}"
DOCKER_NAME = "panda-test-${env.BUILD_ID}"
}
stages {
stage('Build Docker Image') {
steps {
timeout(time: 60, unit: 'MINUTES') {
script {
sh 'git clone --no-checkout --depth 1 git@github.com:commaai/xx.git || true'
sh 'cd xx && git fetch origin && git checkout origin/master -- pandaextra && cd ..' // Needed for certs for panda flashing
sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD'
dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}")
}
}
}
}
stage('Test Dev Build') {
steps {
lock(resource: "Pandas", inversePrecedence: true, quantity:1){
timeout(time: 60, unit: 'MINUTES') {
sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'cd /tmp/panda; ./run_automated_tests.sh '"
}
}
}
}
stage('Test EON Build') {
steps {
lock(resource: "Pandas", inversePrecedence: true, quantity:1){
timeout(time: 60, unit: 'MINUTES') {
sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_dev.xml"
sh "touch EON && docker cp EON ${env.DOCKER_NAME}:/EON"
sh "docker start -a ${env.DOCKER_NAME}"
}
}
}
}
}
post {
always {
script {
sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_EON.xml"
sh "docker rm ${env.DOCKER_NAME}"
}
junit "test_results*.xml"
}
}
}

View File

@ -1 +1 @@
v1.2.0 v1.2.1

View File

@ -3,6 +3,8 @@
#define ALL_CAN_BUT_MAIN_SILENT 0xFE #define ALL_CAN_BUT_MAIN_SILENT 0xFE
#define ALL_CAN_LIVE 0 #define ALL_CAN_LIVE 0
#include "lline_relay.h"
int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT; int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT;
// ********************* instantiate queues ********************* // ********************* instantiate queues *********************
@ -23,6 +25,11 @@ can_buffer(tx2_q, 0x100)
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q}; can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q};
#endif #endif
#ifdef PANDA
// Forward declare
void power_save_reset_timer();
#endif
// ********************* interrupt safe queue ********************* // ********************* interrupt safe queue *********************
int can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { int can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) {
@ -213,7 +220,7 @@ void can_init(uint8_t can_number) {
CAN->FMR &= ~(CAN_FMR_FINIT); CAN->FMR &= ~(CAN_FMR_FINIT);
// enable certain CAN interrupts // enable certain CAN interrupts
CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0; CAN->IER |= CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE;
switch (can_number) { switch (can_number) {
case 0: case 0:
@ -293,7 +300,6 @@ void can_set_gmlan(int bus) {
void can_sce(CAN_TypeDef *CAN) { void can_sce(CAN_TypeDef *CAN) {
enter_critical_section(); enter_critical_section();
can_err_cnt += 1;
#ifdef DEBUG #ifdef DEBUG
if (CAN==CAN1) puts("CAN1: "); if (CAN==CAN1) puts("CAN1: ");
if (CAN==CAN2) puts("CAN2: "); if (CAN==CAN2) puts("CAN2: ");
@ -315,16 +321,32 @@ void can_sce(CAN_TypeDef *CAN) {
uint8_t can_number = CAN_NUM_FROM_CANIF(CAN); uint8_t can_number = CAN_NUM_FROM_CANIF(CAN);
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
if (can_autobaud_enabled[bus_number] && (CAN->ESR & CAN_ESR_LEC)) {
can_autobaud_speed_increment(can_number); if (CAN->MSR & CAN_MSR_WKUI) {
can_set_speed(can_number); //Waking from sleep
#ifdef DEBUG
puts("WAKE\n");
#endif
set_can_enable(CAN, 1);
CAN->MSR &= ~(CAN_MSR_WKUI);
CAN->MSR = CAN->MSR;
#ifdef PANDA
power_save_reset_timer();
#endif
} else {
can_err_cnt += 1;
if (can_autobaud_enabled[bus_number] && (CAN->ESR & CAN_ESR_LEC)) {
can_autobaud_speed_increment(can_number);
can_set_speed(can_number);
}
// clear current send
CAN->TSR |= CAN_TSR_ABRQ0;
CAN->MSR &= ~(CAN_MSR_ERRI);
CAN->MSR = CAN->MSR;
} }
// clear current send
CAN->TSR |= CAN_TSR_ABRQ0;
CAN->MSR &= ~(CAN_MSR_ERRI);
CAN->MSR = CAN->MSR;
exit_critical_section(); exit_critical_section();
} }
@ -332,6 +354,9 @@ void can_sce(CAN_TypeDef *CAN) {
void process_can(uint8_t can_number) { void process_can(uint8_t can_number) {
if (can_number == 0xff) return; if (can_number == 0xff) return;
#ifdef PANDA
power_save_reset_timer();
#endif
enter_critical_section(); enter_critical_section();
@ -375,6 +400,13 @@ void process_can(uint8_t can_number) {
} }
if (can_pop(can_queues[bus_number], &to_send)) { if (can_pop(can_queues[bus_number], &to_send)) {
if (CAN->MCR & CAN_MCR_SLEEP) {
set_can_enable(CAN, 1);
CAN->MCR &= ~(CAN_MCR_SLEEP);
CAN->MCR |= CAN_MCR_INRQ;
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
CAN->MCR &= ~(CAN_MCR_INRQ);
}
can_tx_cnt += 1; can_tx_cnt += 1;
// only send if we have received a packet // only send if we have received a packet
CAN->sTxMailBox[0].TDLR = to_send.RDLR; CAN->sTxMailBox[0].TDLR = to_send.RDLR;
@ -390,6 +422,9 @@ void process_can(uint8_t can_number) {
// CAN receive handlers // CAN receive handlers
// blink blue when we are receiving CAN messages // blink blue when we are receiving CAN messages
void can_rx(uint8_t can_number) { void can_rx(uint8_t can_number) {
#ifdef PANDA
power_save_reset_timer();
#endif
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
while (CAN->RF0R & CAN_RF0R_FMP0) { while (CAN->RF0R & CAN_RF0R_FMP0) {
@ -420,14 +455,16 @@ void can_rx(uint8_t can_number) {
// forwarding (panda only) // forwarding (panda only)
#ifdef PANDA #ifdef PANDA
int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push); if ((get_lline_status() != 0) || !relay_control) { //Relay engaged or relay isn't controlled, allow fwd
if (bus_fwd_num != -1) { int bus_fwd_num = can_forwarding[bus_number] != -1 ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push);
CAN_FIFOMailBox_TypeDef to_send; if (bus_fwd_num != -1) {
to_send.RIR = to_push.RIR | 1; // TXRQ CAN_FIFOMailBox_TypeDef to_send;
to_send.RDTR = to_push.RDTR; to_send.RIR = to_push.RIR | 1; // TXRQ
to_send.RDLR = to_push.RDLR; to_send.RDTR = to_push.RDTR;
to_send.RDHR = to_push.RDHR; to_send.RDLR = to_push.RDLR;
can_send(&to_send, bus_fwd_num); to_send.RDHR = to_push.RDHR;
can_send(&to_send, bus_fwd_num);
}
} }
#endif #endif

View File

@ -0,0 +1,88 @@
#ifdef PANDA
int relay_control = 0; // True if relay is controlled through l-line
/* Conrol a relay connected to l-line pin */
// 160us cycles, 1 high, 25 low
volatile int turn_on_relay = 0;
volatile int on_cycles = 25;
//5s timeout
#define LLINE_TIMEOUT_CYCLES 31250
volatile int timeout_cycles = LLINE_TIMEOUT_CYCLES;
void TIM5_IRQHandler(void) {
if (TIM5->SR & TIM_SR_UIF) {
on_cycles--;
timeout_cycles--;
if (timeout_cycles == 0) {
turn_on_relay = 0;
}
if (on_cycles > 0) {
if (turn_on_relay) {
set_gpio_output(GPIOC, 10, 0);
}
}
else {
set_gpio_output(GPIOC, 10, 1);
on_cycles = 25;
}
}
TIM5->ARR = 160-1;
TIM5->SR = 0;
}
void lline_relay_init (void) {
set_lline_output(0);
relay_control = 1;
set_gpio_output(GPIOC, 10, 1);
// setup
TIM5->PSC = 48-1; // tick on 1 us
TIM5->CR1 = TIM_CR1_CEN; // enable
TIM5->ARR = 50-1; // 50 us
TIM5->DIER = TIM_DIER_UIE; // update interrupt
TIM5->CNT = 0;
NVIC_EnableIRQ(TIM5_IRQn);
#ifdef DEBUG
puts("INIT LLINE\n");
puts(" SR ");
putui(TIM5->SR);
puts(" PSC ");
putui(TIM5->PSC);
puts(" CR1 ");
putui(TIM5->CR1);
puts(" ARR ");
putui(TIM5->ARR);
puts(" DIER ");
putui(TIM5->DIER);
puts(" SR ");
putui(TIM5->SR);
puts(" CNT ");
putui(TIM5->CNT);
puts("\n");
#endif
}
void lline_relay_release (void) {
set_lline_output(0);
relay_control = 0;
puts("RELEASE LLINE\n");
set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3);
NVIC_DisableIRQ(TIM5_IRQn);
}
void set_lline_output(int to_set) {
timeout_cycles = LLINE_TIMEOUT_CYCLES;
turn_on_relay = to_set;
}
int get_lline_status() {
return turn_on_relay;
}
#endif

View File

@ -120,6 +120,8 @@ void periph_init() {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
@ -390,7 +392,9 @@ void gpio_init() {
set_gpio_output(GPIOA, 14, 1); set_gpio_output(GPIOA, 14, 1);
// C10,C11: L-Line setup on USART 3 // C10,C11: L-Line setup on USART 3
set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); // LLine now used for relay output
set_gpio_output(GPIOC, 10, 1);
//set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3);
set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3);
set_gpio_pullup(GPIOC, 11, PULL_UP); set_gpio_pullup(GPIOC, 11, PULL_UP);
#endif #endif
@ -475,4 +479,3 @@ void early() {
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
} }
} }

View File

@ -20,6 +20,8 @@
#include "drivers/spi.h" #include "drivers/spi.h"
#include "drivers/timer.h" #include "drivers/timer.h"
#include "power_saving.h"
// ***************************** fan ***************************** // ***************************** fan *****************************
@ -141,6 +143,7 @@ void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {
uart_ring *ur = get_ring_by_number(usbdata[0]); uart_ring *ur = get_ring_by_number(usbdata[0]);
if (!ur) return; if (!ur) return;
if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) { if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) {
if (ur == &esp_ring) power_save_reset_timer();
for (int i = 1; i < len; i++) while (!putc(ur, usbdata[i])); for (int i = 1; i < len; i++) while (!putc(ur, usbdata[i]));
} }
} }
@ -160,6 +163,14 @@ void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {
uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK; uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK;
can_send(&to_push, bus_number); can_send(&to_push, bus_number);
#ifdef PANDA
// Enable relay on can message if allowed.
// Temporary until OP has support for relay
if (safety_relay_hook()) {
set_lline_output(1);
}
#endif
} }
} }
@ -441,6 +452,16 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
} }
break; break;
} }
// **** 0xf3: set l-line relay
case 0xf3:
{
#ifdef PANDA
if (safety_relay_hook()) {
set_lline_output(setup->b.wValue.w == 1);
}
#endif
break;
}
default: default:
puts("NO HANDLER "); puts("NO HANDLER ");
puth(setup->b.bRequest); puth(setup->b.bRequest);
@ -572,6 +593,9 @@ int main() {
#ifdef PANDA #ifdef PANDA
spi_init(); spi_init();
#endif #endif
#ifdef DEBUG
puts("DEBUG ENABLED\n");
#endif
// set PWM // set PWM
fan_init(); fan_init();
@ -581,6 +605,8 @@ int main() {
__enable_irq(); __enable_irq();
power_save_init();
// if the error interrupt is enabled to quickly when the CAN bus is active // if the error interrupt is enabled to quickly when the CAN bus is active
// something bad happens and you can't connect to the device over USB // something bad happens and you can't connect to the device over USB
delay(10000000); delay(10000000);

View File

@ -295,6 +295,7 @@ int main() {
puts("**** INTERRUPTS ON ****\n"); puts("**** INTERRUPTS ON ****\n");
__enable_irq(); __enable_irq();
// main pedal loop // main pedal loop
while (1) { while (1) {
pedal(); pedal();
@ -302,4 +303,3 @@ int main() {
return 0; return 0;
} }

View File

@ -0,0 +1,157 @@
#define POWER_SAVE_STATUS_DISABLED 0
//Moving to enabled, but can wakeup not yet enabled
#define POWER_SAVE_STATUS_SWITCHING 1
#define POWER_SAVE_STATUS_ENABLED 2
volatile int power_save_status = POWER_SAVE_STATUS_DISABLED;
void power_save_enable(void) {
power_save_status = POWER_SAVE_STATUS_SWITCHING;
puts("Saving power\n");
//Turn off can transciever
set_can_enable(CAN1, 0);
set_can_enable(CAN2, 0);
#ifdef PANDA
set_can_enable(CAN3, 0);
#endif
//Turn off GMLAN
set_gpio_output(GPIOB, 14, 0);
set_gpio_output(GPIOB, 15, 0);
#ifdef PANDA
//Turn off LIN K
if (revision == PANDA_REV_C) {
set_gpio_output(GPIOB, 7, 0); // REV C
} else {
set_gpio_output(GPIOB, 4, 0); // REV AB
}
// LIN L
set_gpio_output(GPIOA, 14, 0);
#endif
if (is_grey_panda) {
char* UBLOX_SLEEP_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78";
int len = 12;
uart_ring *ur = get_ring_by_number(1);
for (int i = 0; i < len; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i]));
}
//Setup timer for can enable
TIM6->PSC = 48-1; // tick on 1 us
TIM6->ARR = 12; // 12us
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
TIM6->CR1 |= TIM_CR1_CEN;
}
void power_save_enable_can_wake(void) {
// CAN Automatic Wake must be done a little while after the sleep
// On some cars turning off the can transciver can trigger the wakeup
power_save_status = POWER_SAVE_STATUS_ENABLED;
puts("Turning can off\n");
CAN1->MCR |= CAN_MCR_SLEEP;
CAN1->MCR |= CAN_MCR_AWUM;
CAN2->MCR |= CAN_MCR_SLEEP;
CAN2->MCR |= CAN_MCR_AWUM;
#ifdef PANDA
CAN3->MCR |= CAN_MCR_SLEEP;
CAN3->MCR |= CAN_MCR_AWUM;
#endif
//set timer back
TIM6->PSC = 48000-1; // tick on 1 ms
TIM6->ARR = 10000; // 10s
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
}
void power_save_disable(void) {
power_save_status = POWER_SAVE_STATUS_DISABLED;
puts("not Saving power\n");
TIM6->CR1 |= TIM_CR1_CEN; //Restart timer
TIM6->CNT = 0;
//Turn on can
set_can_enable(CAN1, 1);
set_can_enable(CAN2, 1);
#ifdef PANDA
set_can_enable(CAN3, 1);
#endif
//Turn on GMLAN
set_gpio_output(GPIOB, 14, 1);
set_gpio_output(GPIOB, 15, 1);
#ifdef PANDA
//Turn on LIN K
if (revision == PANDA_REV_C) {
set_gpio_output(GPIOB, 7, 1); // REV C
} else {
set_gpio_output(GPIOB, 4, 1); // REV AB
}
// LIN L
set_gpio_output(GPIOA, 14, 1);
#endif
if (is_grey_panda) {
char* UBLOX_WAKE_MSG = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a";
int len = 12;
uart_ring *ur = get_ring_by_number(1);
for (int i = 0; i < len; i++) while (!putc(ur, UBLOX_WAKE_MSG[i]));
}
//set timer back
TIM6->PSC = 48000-1; // tick on 1 ms
TIM6->ARR = 10000; // 10s
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
TIM6->CR1 |= TIM_CR1_CEN;
}
// Reset timer when activity
void power_save_reset_timer() {
TIM6->CNT = 0;
if (power_save_status != POWER_SAVE_STATUS_DISABLED){
power_save_disable();
}
}
void power_save_init(void) {
puts("Saving power init\n");
TIM6->PSC = 48000-1; // tick on 1 ms
TIM6->ARR = 10000; // 10s
// Enable, One-Pulse Mode, Only overflow interrupt
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS;
TIM6->EGR = TIM_EGR_UG;
NVIC_EnableIRQ(TIM6_DAC_IRQn);
puts("Saving power init done\n");
TIM6->DIER = TIM_DIER_UIE;
TIM6->CR1 |= TIM_CR1_CEN;
}
void TIM6_DAC_IRQHandler(void) {
//Timeout switch to power saving mode.
if (TIM6->SR & TIM_SR_UIF) {
TIM6->SR = 0;
#ifdef EON
if (power_save_status == POWER_SAVE_STATUS_DISABLED) {
power_save_enable();
} else if (power_save_status == POWER_SAVE_STATUS_SWITCHING) {
power_save_enable_can_wake();
}
#endif
} else {
TIM6->CR1 |= TIM_CR1_CEN;
}
}

View File

@ -29,6 +29,10 @@ int driver_limit_check(int val, int val_last, struct sample_t *val_driver,
int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA); int rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA);
#ifdef PANDA #ifdef PANDA
float interpolate(struct lookup_t xy, float x); float interpolate(struct lookup_t xy, float x);
void lline_relay_init (void);
void lline_relay_release (void);
void set_lline_output(int to_set);
#endif #endif
typedef void (*safety_hook_init)(int16_t param); typedef void (*safety_hook_init)(int16_t param);
@ -37,6 +41,7 @@ typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send);
typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len); typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len);
typedef int (*ign_hook)(); typedef int (*ign_hook)();
typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd); typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd);
typedef int (*relay_hook)();
typedef struct { typedef struct {
safety_hook_init init; safety_hook_init init;
@ -45,6 +50,7 @@ typedef struct {
tx_hook tx; tx_hook tx;
tx_lin_hook tx_lin; tx_lin_hook tx_lin;
fwd_hook fwd; fwd_hook fwd;
relay_hook relay;
} safety_hooks; } safety_hooks;
// This can be set by the safety hooks. // This can be set by the safety hooks.
@ -91,6 +97,10 @@ int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return current_hooks->fwd(bus_num, to_fwd); return current_hooks->fwd(bus_num, to_fwd);
} }
int safety_relay_hook(void) {
return current_hooks->relay();
}
typedef struct { typedef struct {
uint16_t id; uint16_t id;
const safety_hooks *hooks; const safety_hooks *hooks;

View File

@ -115,6 +115,9 @@ static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void cadillac_init(int16_t param) { static void cadillac_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
cadillac_ign = 0; cadillac_ign = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int cadillac_ign_hook() { static int cadillac_ign_hook() {
@ -128,4 +131,5 @@ const safety_hooks cadillac_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = cadillac_ign_hook, .ignition = cadillac_ign_hook,
.fwd = alloutput_fwd_hook, .fwd = alloutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -127,6 +127,9 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void chrysler_init(int16_t param) { static void chrysler_init(int16_t param) {
chrysler_camera_detected = 0; chrysler_camera_detected = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
@ -150,4 +153,5 @@ const safety_hooks chrysler_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = chrysler_fwd_hook, .fwd = chrysler_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -8,6 +8,9 @@ int default_ign_hook() {
static void nooutput_init(int16_t param) { static void nooutput_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
@ -22,6 +25,10 @@ static int nooutput_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return -1; return -1;
} }
static int nooutput_relay_hook(int to_set) {
return false;
}
const safety_hooks nooutput_hooks = { const safety_hooks nooutput_hooks = {
.init = nooutput_init, .init = nooutput_init,
.rx = default_rx_hook, .rx = default_rx_hook,
@ -29,12 +36,16 @@ const safety_hooks nooutput_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = nooutput_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };
// *** all output safety mode *** // *** all output safety mode ***
static void alloutput_init(int16_t param) { static void alloutput_init(int16_t param) {
controls_allowed = 1; controls_allowed = 1;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
@ -49,6 +60,10 @@ static int alloutput_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
return -1; return -1;
} }
static int alloutput_relay_hook(int to_set) {
return true;
}
const safety_hooks alloutput_hooks = { const safety_hooks alloutput_hooks = {
.init = alloutput_init, .init = alloutput_init,
.rx = default_rx_hook, .rx = default_rx_hook,
@ -56,4 +71,5 @@ const safety_hooks alloutput_hooks = {
.tx_lin = alloutput_tx_lin_hook, .tx_lin = alloutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = alloutput_fwd_hook, .fwd = alloutput_fwd_hook,
.relay = alloutput_relay_hook,
}; };

View File

@ -42,4 +42,5 @@ const safety_hooks elm327_hooks = {
.tx_lin = elm327_tx_lin_hook, .tx_lin = elm327_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = elm327_fwd_hook, .fwd = elm327_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -90,4 +90,5 @@ const safety_hooks ford_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = nooutput_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -228,6 +228,9 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
static void gm_init(int16_t param) { static void gm_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
gm_ignition_started = 0; gm_ignition_started = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int gm_ign_hook() { static int gm_ign_hook() {
@ -241,5 +244,5 @@ const safety_hooks gm_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = gm_ign_hook, .ignition = gm_ign_hook,
.fwd = nooutput_fwd_hook, .fwd = nooutput_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -48,5 +48,6 @@ const safety_hooks gm_ascm_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = gm_ascm_fwd_hook, .fwd = gm_ascm_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -136,6 +136,9 @@ static void honda_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
bosch_hardware = false; bosch_hardware = false;
honda_alt_brake_msg = false; honda_alt_brake_msg = false;
#ifdef PANDA
lline_relay_release();
#endif
} }
static void honda_bosch_init(int16_t param) { static void honda_bosch_init(int16_t param) {
@ -143,6 +146,9 @@ static void honda_bosch_init(int16_t param) {
bosch_hardware = true; bosch_hardware = true;
// Checking for alternate brake override from safety parameter // Checking for alternate brake override from safety parameter
honda_alt_brake_msg = param == 1 ? true : false; honda_alt_brake_msg = param == 1 ? true : false;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
@ -176,6 +182,7 @@ const safety_hooks honda_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = honda_fwd_hook, .fwd = honda_fwd_hook,
.relay = nooutput_relay_hook,
}; };
const safety_hooks honda_bosch_hooks = { const safety_hooks honda_bosch_hooks = {
@ -185,4 +192,5 @@ const safety_hooks honda_bosch_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = honda_bosch_fwd_hook, .fwd = honda_bosch_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -152,6 +152,9 @@ static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
static void hyundai_init(int16_t param) { static void hyundai_init(int16_t param) {
controls_allowed = 0; controls_allowed = 0;
hyundai_giraffe_switch_2 = 0; hyundai_giraffe_switch_2 = 0;
#ifdef PANDA
lline_relay_release();
#endif
} }
const safety_hooks hyundai_hooks = { const safety_hooks hyundai_hooks = {
@ -161,4 +164,5 @@ const safety_hooks hyundai_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = hyundai_fwd_hook, .fwd = hyundai_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -14,6 +14,11 @@ int subaru_desired_torque_last = 0;
uint32_t subaru_ts_last = 0; uint32_t subaru_ts_last = 0;
struct sample_t subaru_torque_driver; // last few driver torques measured struct sample_t subaru_torque_driver; // last few driver torques measured
static void subaru_init(int16_t param) {
#ifdef PANDA
lline_relay_init();
#endif
}
static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int bus_number = (to_push->RDTR >> 4) & 0xFF; int bus_number = (to_push->RDTR >> 4) & 0xFF;
@ -100,6 +105,7 @@ static int subaru_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
// forward CAN 0 > 1 // forward CAN 0 > 1
if (bus_num == 0) { if (bus_num == 0) {
return 2; // ES CAN return 2; // ES CAN
} }
// forward CAN 1 > 0, except ES_LKAS // forward CAN 1 > 0, except ES_LKAS
@ -113,6 +119,10 @@ static int subaru_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
if (addr == 0x122) { if (addr == 0x122) {
return -1; return -1;
} }
// ES Distance
if (addr == 545) {
return -1;
}
return 0; // Main CAN return 0; // Main CAN
} }
@ -122,10 +132,11 @@ static int subaru_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
} }
const safety_hooks subaru_hooks = { const safety_hooks subaru_hooks = {
.init = nooutput_init, .init = subaru_init,
.rx = subaru_rx_hook, .rx = subaru_rx_hook,
.tx = subaru_tx_hook, .tx = subaru_tx_hook,
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = subaru_fwd_hook, .fwd = subaru_fwd_hook,
.relay = alloutput_relay_hook,
}; };

View File

@ -230,6 +230,9 @@ static void tesla_init(int16_t param)
controls_allowed = 0; controls_allowed = 0;
tesla_ignition_started = 0; tesla_ignition_started = 0;
gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled
#ifdef PANDA
lline_relay_release();
#endif
} }
static int tesla_ign_hook() static int tesla_ign_hook()
@ -284,4 +287,5 @@ const safety_hooks tesla_hooks = {
.tx_lin = tesla_tx_lin_hook, .tx_lin = tesla_tx_lin_hook,
.ignition = tesla_ign_hook, .ignition = tesla_ign_hook,
.fwd = tesla_fwd_hook, .fwd = tesla_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -160,6 +160,9 @@ static void toyota_init(int16_t param) {
toyota_giraffe_switch_1 = 0; toyota_giraffe_switch_1 = 0;
toyota_camera_forwarded = 0; toyota_camera_forwarded = 0;
toyota_dbc_eps_torque_factor = param; toyota_dbc_eps_torque_factor = param;
#ifdef PANDA
lline_relay_release();
#endif
} }
static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
@ -181,6 +184,7 @@ const safety_hooks toyota_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = toyota_fwd_hook, .fwd = toyota_fwd_hook,
.relay = nooutput_relay_hook,
}; };
static void toyota_nolimits_init(int16_t param) { static void toyota_nolimits_init(int16_t param) {
@ -189,6 +193,9 @@ static void toyota_nolimits_init(int16_t param) {
toyota_giraffe_switch_1 = 0; toyota_giraffe_switch_1 = 0;
toyota_camera_forwarded = 0; toyota_camera_forwarded = 0;
toyota_dbc_eps_torque_factor = param; toyota_dbc_eps_torque_factor = param;
#ifdef PANDA
lline_relay_release();
#endif
} }
const safety_hooks toyota_nolimits_hooks = { const safety_hooks toyota_nolimits_hooks = {
@ -198,4 +205,5 @@ const safety_hooks toyota_nolimits_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = toyota_fwd_hook, .fwd = toyota_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -152,5 +152,5 @@ const safety_hooks toyota_ipas_hooks = {
.tx_lin = nooutput_tx_lin_hook, .tx_lin = nooutput_tx_lin_hook,
.ignition = default_ign_hook, .ignition = default_ign_hook,
.fwd = toyota_fwd_hook, .fwd = toyota_fwd_hook,
.relay = nooutput_relay_hook,
}; };

View File

@ -0,0 +1,5 @@
#!/bin/bash
git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
cd esp-open-sdk
git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec
LD_LIBRARY_PATH="" make STANDALONE=y

View File

@ -182,6 +182,7 @@ class Panda(object):
traceback.print_exc() traceback.print_exc()
if wait == False or self._handle != None: if wait == False or self._handle != None:
break break
context = usb1.USBContext() #New context needed so new devices show up
assert(self._handle != None) assert(self._handle != None)
print("connected") print("connected")
@ -280,11 +281,14 @@ class Panda(object):
if reconnect: if reconnect:
self.reconnect() self.reconnect()
def recover(self): def recover(self, timeout=None):
self.reset(enter_bootloader=True) self.reset(enter_bootloader=True)
t_start = time.time()
while len(PandaDFU.list()) == 0: while len(PandaDFU.list()) == 0:
print("waiting for DFU...") print("waiting for DFU...")
time.sleep(0.1) time.sleep(0.1)
if timeout is not None and (time.time() - t_start) > timeout:
return False
dfu = PandaDFU(PandaDFU.st_serial_to_dfu_serial(self._serial)) dfu = PandaDFU(PandaDFU.st_serial_to_dfu_serial(self._serial))
dfu.recover() dfu.recover()
@ -292,6 +296,7 @@ class Panda(object):
# reflash after recover # reflash after recover
self.connect(True, True) self.connect(True, True)
self.flash() self.flash()
return True
@staticmethod @staticmethod
def flash_ota_st(): def flash_ota_st():
@ -300,8 +305,9 @@ class Panda(object):
return ret==0 return ret==0
@staticmethod @staticmethod
def flash_ota_wifi(): def flash_ota_wifi(release=False):
ret = os.system("cd %s && make clean && make ota" % (os.path.join(BASEDIR, "boardesp"))) release_str = "RELEASE=1" if release else ""
ret = os.system("cd {} && make clean && {} make ota".format(os.path.join(BASEDIR, "boardesp"),release_str))
time.sleep(1) time.sleep(1)
return ret==0 return ret==0
@ -386,10 +392,17 @@ class Panda(object):
elif bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]: elif bus in [Panda.GMLAN_CAN2, Panda.GMLAN_CAN3]:
self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, 1, bus, b'') self._handle.controlWrite(Panda.REQUEST_OUT, 0xdb, 1, bus, b'')
def set_lline_relay(self, enable):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, int(enable), 0, b'')
def set_can_loopback(self, enable): def set_can_loopback(self, enable):
# set can loopback mode for all buses # set can loopback mode for all buses
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'') self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'')
def set_can_enable(self, bus_num, enable):
# sets the can transciever enable pin
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf4, int(bus_num), int(enable), b'')
def set_can_speed_kbps(self, bus, speed): def set_can_speed_kbps(self, bus, speed):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xde, bus, int(speed*10), b'') self._handle.controlWrite(Panda.REQUEST_OUT, 0xde, bus, int(speed*10), b'')

View File

@ -1,4 +1,7 @@
libusb1 libusb1 == 1.6.6
hexdump hexdump
pycrypto pycrypto
tqdm tqdm
nose
parameterized
requests

View File

@ -1,3 +1,9 @@
#!/bin/bash #!/bin/bash
PYTHONPATH="." nosetests -x -s tests/automated/$1*.py TEST_FILENAME=${TEST_FILENAME:-nosetests.xml}
if [ ! -f "/EON" ]; then
TESTSUITE_NAME="Panda_Test-EON"
else
TESTSUITE_NAME="Panda_Test-DEV"
fi
PYTHONPATH="." nosetests -v --with-xunit --xunit-file=./$TEST_FILENAME --xunit-testsuite-name=$TESTSUITE_NAME -s tests/automated/$1*.py

View File

@ -46,7 +46,7 @@ setup(
platforms='any', platforms='any',
license='MIT', license='MIT',
install_requires=[ install_requires=[
'libusb1 >= 1.6.4', 'libusb1 == 1.6.6',
'hexdump >= 3.3', 'hexdump >= 3.3',
'pycrypto >= 2.6.1', 'pycrypto >= 2.6.1',
'tqdm >= 4.14.0', 'tqdm >= 4.14.0',

View File

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

View File

@ -3,14 +3,16 @@ import os
import sys import sys
import time import time
from panda import Panda from panda import Panda
from nose.tools import timed, 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 from helpers import time_many_sends, connect_wo_esp, test_white_and_grey, panda_color_to_serial
SPEED_NORMAL = 500 SPEED_NORMAL = 500
SPEED_GMLAN = 33.3 SPEED_GMLAN = 33.3
def test_can_loopback(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_can_loopback(serial=None):
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)
@ -42,8 +44,10 @@ def test_can_loopback():
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]
def test_safety_nooutput(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_safety_nooutput(serial=None):
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)
@ -59,8 +63,10 @@ def test_safety_nooutput():
r = p.can_recv() r = p.can_recv()
assert len(r) == 0 assert len(r) == 0
def test_reliability(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_reliability(serial=None):
p = connect_wo_esp(serial)
LOOP_COUNT = 100 LOOP_COUNT = 100
MSG_COUNT = 100 MSG_COUNT = 100
@ -97,8 +103,10 @@ def test_reliability():
sys.stdout.write("P") sys.stdout.write("P")
sys.stdout.flush() sys.stdout.flush()
def test_throughput(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_throughput(serial=None):
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)
@ -120,8 +128,10 @@ def test_throughput():
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))
def test_gmlan(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_gmlan(serial=None):
p = connect_wo_esp(serial)
if p.legacy: if p.legacy:
return return
@ -135,7 +145,7 @@ def test_gmlan():
p.set_can_speed_kbps(1, SPEED_NORMAL) p.set_can_speed_kbps(1, SPEED_NORMAL)
p.set_can_speed_kbps(2, SPEED_NORMAL) p.set_can_speed_kbps(2, SPEED_NORMAL)
p.set_can_speed_kbps(3, SPEED_GMLAN) p.set_can_speed_kbps(3, SPEED_GMLAN)
# 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]:
p.set_gmlan(bus) p.set_gmlan(bus)
@ -150,8 +160,10 @@ def test_gmlan():
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))
def test_gmlan_bad_toggle(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_gmlan_bad_toggle(serial=None):
p = connect_wo_esp(serial)
if p.legacy: if p.legacy:
return return
@ -178,9 +190,10 @@ def test_gmlan_bad_toggle():
# this will fail if you have hardware serial connected # this will fail if you have hardware serial connected
def test_serial_debug(): @test_white_and_grey
p = connect_wo_esp() @panda_color_to_serial
def test_serial_debug(serial=None):
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

@ -1,33 +1,60 @@
from __future__ import print_function from __future__ import print_function
import os import os
import time
from panda import Panda from panda import Panda
from helpers import connect_wifi from helpers import connect_wifi, test_white, test_white_and_grey, panda_color_to_serial
import requests import requests
def test_get_serial(): @test_white_and_grey
p = Panda() @panda_color_to_serial
def test_get_serial(serial=None):
p = Panda(serial)
print(p.get_serial()) print(p.get_serial())
def test_get_serial_in_flash_mode(): @test_white_and_grey
p = Panda() @panda_color_to_serial
def test_get_serial_in_flash_mode(serial=None):
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()
def test_connect_wifi(): @test_white
connect_wifi() @panda_color_to_serial
def test_connect_wifi(serial=None):
connect_wifi(serial)
def test_flash_wifi(): @test_white
Panda.flash_ota_wifi() @panda_color_to_serial
connect_wifi() def test_flash_wifi(serial=None):
connect_wifi(serial)
assert Panda.flash_ota_wifi(release=True), "OTA Wifi Flash Failed"
connect_wifi(serial)
def test_wifi_flash_st(): @test_white
Panda.flash_ota_st() @panda_color_to_serial
def test_wifi_flash_st(serial=None):
connect_wifi(serial)
assert Panda.flash_ota_st(), "OTA ST Flash Failed"
connected = False
st = time.time()
while not connected and (time.time() - st) < 20:
try:
p = Panda(serial=serial)
p.get_serial()
connected = True
except:
time.sleep(1)
def test_webpage_fetch(): if not connected:
assert False, "Panda failed to connect on USB after flashing"
@test_white
@panda_color_to_serial
def test_webpage_fetch(serial=None):
connect_wifi(serial)
r = requests.get("http://192.168.0.10/") r = requests.get("http://192.168.0.10/")
print(r.text) print(r.text)
assert "This is your comma.ai panda" in r.text assert "This is your comma.ai panda" in r.text

View File

@ -1,17 +1,22 @@
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 from helpers import time_many_sends, connect_wifi, test_white, panda_color_to_serial
from nose.tools import timed, assert_equal, assert_less, assert_greater from nose.tools import timed, assert_equal, assert_less, assert_greater
def test_get_serial_wifi(): @test_white
connect_wifi() @panda_color_to_serial
def test_get_serial_wifi(serial=None):
connect_wifi(serial)
p = Panda("WIFI") p = Panda("WIFI")
print(p.get_serial()) print(p.get_serial())
def test_throughput(): @test_white
p = Panda() @panda_color_to_serial
def test_throughput(serial=None):
connect_wifi(serial)
p = Panda(serial)
# enable output mode # enable output mode
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
@ -24,7 +29,7 @@ def test_throughput():
for speed in [100,250,500,750,1000]: for speed in [100,250,500,750,1000]:
# 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.05) time.sleep(0.1)
comp_kbps = time_many_sends(p, 0) comp_kbps = time_many_sends(p, 0)
@ -35,8 +40,11 @@ def test_throughput():
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))
def test_recv_only(): @test_white
p = Panda() @panda_color_to_serial
def test_recv_only(serial=None):
connect_wifi(serial)
p = Panda(serial)
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p.set_can_loopback(True) p.set_can_loopback(True)
pwifi = Panda("WIFI") pwifi = Panda("WIFI")
@ -49,4 +57,3 @@ def test_recv_only():
saturation_pct = (comp_kbps/speed) * 100.0 saturation_pct = (comp_kbps/speed) * 100.0
print("HT WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct)) print("HT WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct))

View File

@ -1,14 +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 from helpers import time_many_sends, connect_wifi, test_white, panda_color_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
def test_udp_doesnt_drop(): @test_white
connect_wifi() @panda_color_to_serial
def test_udp_doesnt_drop(serial=None):
connect_wifi(serial)
p = Panda() p = Panda(serial)
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p.set_can_loopback(True) p.set_can_loopback(True)
@ -18,6 +20,7 @@ def test_udp_doesnt_drop():
break break
for msg_count in [1, 100]: for msg_count in [1, 100]:
saturation_pcts = []
for i in range({1: 0x80, 100: 0x20}[msg_count]): for i in range({1: 0x80, 100: 0x20}[msg_count]):
pwifi.kick() pwifi.kick()
@ -31,9 +34,33 @@ def test_udp_doesnt_drop():
sys.stdout.flush() sys.stdout.flush()
else: else:
print("UDP WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct)) print("UDP WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct))
assert_greater(saturation_pct, 40) assert_greater(saturation_pct, 20) #sometimes the wifi can be slow...
assert_less(saturation_pct, 100) assert_less(saturation_pct, 100)
print("") saturation_pcts.append(saturation_pct)
if len(saturation_pcts) > 0:
assert_greater(sum(saturation_pcts)/len(saturation_pcts), 60)
time.sleep(5)
usb_ok_cnt = 0
REQ_USB_OK_CNT = 500
st = time.time()
msg_id = 0x1bb
bus = 0
last_missing_msg = 0
while usb_ok_cnt < REQ_USB_OK_CNT and (time.time() - st) < 40:
p.can_send(msg_id, "message", bus)
time.sleep(0.01)
r = [1]
missing = True
while len(r) > 0:
r = p.can_recv()
r = filter(lambda x: x[3] == bus and x[0] == msg_id, r)
if len(r) > 0:
missing = False
usb_ok_cnt += len(r)
if missing:
last_missing_msg = time.time()
et = time.time() - st
last_missing_msg = last_missing_msg - st
print("waited {} for panda to recv can on usb, {} msgs, last missing at {}".format(et, usb_ok_cnt, last_missing_msg))
assert usb_ok_cnt >= REQ_USB_OK_CNT, "Unable to recv can on USB after UDP"

View File

@ -0,0 +1,121 @@
from __future__ import print_function
import time
from panda import Panda
from nose.tools import assert_equal, assert_less, assert_greater
from helpers import time_many_sends, test_two_panda, panda_color_to_serial
@test_two_panda
@panda_color_to_serial
def test_send_recv(serial_sender=None, serial_reciever=None):
p_send = Panda(serial_sender)
p_recv = Panda(serial_reciever)
p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p_send.set_can_loopback(False)
p_recv.set_can_loopback(False)
assert not p_send.legacy
assert not p_recv.legacy
p_send.can_send_many([(0x1ba, 0, "message", 0)]*2)
time.sleep(0.05)
p_recv.can_recv()
p_send.can_recv()
busses = [0,1,2]
for bus in busses:
for speed in [100, 250, 500, 750, 1000]:
p_send.set_can_speed_kbps(bus, speed)
p_recv.set_can_speed_kbps(bus, speed)
time.sleep(0.05)
comp_kbps = time_many_sends(p_send, bus, p_recv, two_pandas=True)
saturation_pct = (comp_kbps/speed) * 100.0
assert_greater(saturation_pct, 80)
assert_less(saturation_pct, 100)
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
@panda_color_to_serial
def test_latency(serial_sender=None, serial_reciever=None):
p_send = Panda(serial_sender)
p_recv = Panda(serial_reciever)
p_send.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
p_send.set_can_loopback(False)
p_recv.set_can_loopback(False)
assert not p_send.legacy
assert not p_recv.legacy
p_send.set_can_speed_kbps(0, 100)
p_recv.set_can_speed_kbps(0, 100)
time.sleep(0.05)
p_send.can_send_many([(0x1ba, 0, "testmsg", 0)]*10)
time.sleep(0.05)
p_recv.can_recv()
p_send.can_recv()
busses = [0,1,2]
for bus in busses:
for speed in [100, 250, 500, 750, 1000]:
p_send.set_can_speed_kbps(bus, speed)
p_recv.set_can_speed_kbps(bus, speed)
time.sleep(0.1)
#clear can buffers
r = [1]
while len(r) > 0:
r = p_send.can_recv()
r = [1]
while len(r) > 0:
r = p_recv.can_recv()
time.sleep(0.05)
latencies = []
comp_kbps_list = []
saturation_pcts = []
num_messages = 100
for i in range(num_messages):
st = time.time()
p_send.can_send(0x1ab, "message", bus)
r = []
while len(r) < 1 and (time.time() - st) < 5:
r = p_recv.can_recv()
et = time.time()
r_echo = []
while len(r_echo) < 1 and (time.time() - st) < 10:
r_echo = p_send.can_recv()
if len(r) == 0 or len(r_echo) == 0:
print("r: {}, r_echo: {}".format(r, r_echo))
assert_equal(len(r),1)
assert_equal(len(r_echo),1)
et = (et - st)*1000.0
comp_kbps = (1+11+1+1+1+4+8*8+15+1+1+1+7) / et
latency = et - ((1+11+1+1+1+4+8*8+15+1+1+1+7) / speed)
assert_less(latency, 5.0)
saturation_pct = (comp_kbps/speed) * 100.0
latencies.append(latency)
comp_kbps_list.append(comp_kbps)
saturation_pcts.append(saturation_pct)
average_latency = sum(latencies)/num_messages
assert_less(average_latency, 1.0)
average_comp_kbps = sum(comp_kbps_list)/num_messages
average_saturation_pct = sum(saturation_pcts)/num_messages
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))

View File

@ -4,12 +4,34 @@ import time
import random import random
import subprocess import subprocess
import requests import requests
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
def connect_wo_esp(): test_white_and_grey = parameterized([param(panda_color="White"),
param(panda_color="Grey")])
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 = {}
def get_panda_serial(is_grey=None):
global _serials
if is_grey not in _serials:
for serial in Panda.list():
p = Panda(serial=serial)
if is_grey is None or p.is_grey() == is_grey:
_serials[is_grey] = serial
return serial
raise IOError("Panda not found. is_grey: {}".format(is_grey))
else:
return _serials[is_grey]
def connect_wo_esp(serial=None):
# connect to the panda # connect to the panda
p = Panda() p = Panda(serial=serial)
# power down the ESP # power down the ESP
p.set_esp_power(False) p.set_esp_power(False)
@ -20,15 +42,28 @@ def connect_wo_esp():
return p return p
def connect_wifi(): def connect_wifi(serial=None):
p = Panda() p = Panda(serial=serial)
p.set_esp_power(True)
dongle_id, pw = p.get_serial() dongle_id, pw = p.get_serial()
assert(dongle_id.isalnum()) assert(dongle_id.isalnum())
_connect_wifi(dongle_id, pw) _connect_wifi(dongle_id, pw)
FNULL = open(os.devnull, 'w')
def _connect_wifi(dongle_id, pw, insecure_okay=False): def _connect_wifi(dongle_id, pw, insecure_okay=False):
ssid = str("panda-" + dongle_id) ssid = str("panda-" + dongle_id)
r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT)
if not r:
#Can already ping, try connecting on wifi
try:
p = Panda("WIFI")
p.get_serial()
print("Already connected")
return
except:
pass
print("WIFI: connecting to %s" % ssid) print("WIFI: connecting to %s" % ssid)
while 1: while 1:
@ -39,8 +74,8 @@ def _connect_wifi(dongle_id, pw, insecure_okay=False):
cnt = 0 cnt = 0
MAX_TRIES = 10 MAX_TRIES = 10
while cnt < MAX_TRIES: while cnt < MAX_TRIES:
print "WIFI: scanning %d" % cnt print("WIFI: scanning %d" % cnt)
os.system("sudo iwlist %s scanning > /dev/null" % wlan_interface) os.system("iwlist %s scanning > /dev/null" % wlan_interface)
os.system("nmcli device wifi rescan") os.system("nmcli device wifi rescan")
wifi_scan = filter(lambda x: ssid in x, subprocess.check_output(["nmcli","dev", "wifi", "list"]).split("\n")) wifi_scan = filter(lambda x: ssid in x, subprocess.check_output(["nmcli","dev", "wifi", "list"]).split("\n"))
if len(wifi_scan) != 0: if len(wifi_scan) != 0:
@ -51,45 +86,107 @@ def _connect_wifi(dongle_id, pw, insecure_okay=False):
assert cnt < MAX_TRIES assert cnt < MAX_TRIES
if "-pair" in wifi_scan[0]: if "-pair" in wifi_scan[0]:
os.system("nmcli d wifi connect %s-pair" % (ssid)) os.system("nmcli d wifi connect %s-pair" % (ssid))
connect_cnt = 0
MAX_TRIES = 20
while connect_cnt < MAX_TRIES:
connect_cnt += 1
r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT)
if r:
print("Waiting for panda to ping...")
time.sleep(0.1)
else:
break
if insecure_okay: if insecure_okay:
break break
# fetch webpage # fetch webpage
print "connecting to insecure network to secure" print("connecting to insecure network to secure")
r = requests.get("http://192.168.0.10/") try:
r = requests.get("http://192.168.0.10/")
except requests.ConnectionError:
r = requests.get("http://192.168.0.10/")
assert r.status_code==200 assert r.status_code==200
print "securing" print("securing")
try: try:
r = requests.get("http://192.168.0.10/secure", timeout=0.01) r = requests.get("http://192.168.0.10/secure", timeout=0.01)
except requests.exceptions.Timeout: except requests.exceptions.Timeout:
print("timeout http request to secure")
pass pass
else: else:
os.system("nmcli d wifi connect %s password %s" % (ssid, pw)) ret = os.system("nmcli d wifi connect %s password %s" % (ssid, pw))
break if os.WEXITSTATUS(ret) == 0:
#check ping too
ping_ok = False
connect_cnt = 0
MAX_TRIES = 10
while connect_cnt < MAX_TRIES:
connect_cnt += 1
r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT)
if r:
print("Waiting for panda to ping...")
time.sleep(0.1)
else:
ping_ok = True
break
if ping_ok:
break
# TODO: confirm that it's connected to the right panda # TODO: confirm that it's connected to the right panda
def time_many_sends(p, bus, precv=None, msg_count=100, msg_id=None): def time_many_sends(p, bus, precv=None, msg_count=100, msg_id=None, two_pandas=False):
if precv == None: if precv == None:
precv = p precv = p
if msg_id == None: if msg_id == None:
msg_id = random.randint(0x100, 0x200) msg_id = random.randint(0x100, 0x200)
if p == precv and two_pandas:
raise ValueError("Cannot have two pandas that are the same panda")
st = time.time() st = time.time()
p.can_send_many([(msg_id, 0, "\xaa"*8, bus)]*msg_count) p.can_send_many([(msg_id, 0, "\xaa"*8, bus)]*msg_count)
r = [] r = []
r_echo = []
r_len_expected = msg_count if two_pandas else msg_count*2
r_echo_len_exected = msg_count if two_pandas else 0
while len(r) < (msg_count*2) and (time.time() - st) < 3: while len(r) < r_len_expected and (time.time() - st) < 5:
r.extend(precv.can_recv()) r.extend(precv.can_recv())
et = time.time()
if two_pandas:
while len(r_echo) < r_echo_len_exected and (time.time() - st) < 10:
r_echo.extend(p.can_recv())
sent_echo = filter(lambda x: x[3] == 0x80 | bus and x[0] == msg_id, r) sent_echo = filter(lambda x: x[3] == 0x80 | bus and x[0] == msg_id, r)
loopback_resp = filter(lambda x: x[3] == bus and x[0] == msg_id, r) sent_echo.extend(filter(lambda x: x[3] == 0x80 | bus and x[0] == msg_id, r_echo))
resp = filter(lambda x: x[3] == bus and x[0] == msg_id, r)
leftovers = filter(lambda x: (x[3] != 0x80 | bus and x[3] != bus) or x[0] != msg_id, r)
assert_equal(len(leftovers), 0)
assert_equal(len(resp), msg_count)
assert_equal(len(sent_echo), msg_count) assert_equal(len(sent_echo), msg_count)
assert_equal(len(loopback_resp), msg_count)
et = (time.time()-st)*1000.0 et = (et-st)*1000.0
comp_kbps = (1+11+1+1+1+4+8*8+15+1+1+1+7)*msg_count / et comp_kbps = (1+11+1+1+1+4+8*8+15+1+1+1+7)*msg_count / et
return comp_kbps return comp_kbps
def panda_color_to_serial(fn):
@wraps(fn)
def wrapper(panda_color=None, **kwargs):
pandas_is_grey = []
if panda_color is not None:
if not isinstance(panda_color, list):
panda_color = [panda_color]
panda_color = [s.lower() for s in panda_color]
for p in panda_color:
if p is None:
pandas_is_grey.append(None)
elif p in ["grey", "gray"]:
pandas_is_grey.append(True)
elif p in ["white"]:
pandas_is_grey.append(False)
else:
raise ValueError("Invalid Panda Color {}".format(p))
return fn(*[get_panda_serial(is_grey) for is_grey in pandas_is_grey], **kwargs)
return wrapper

View File

@ -246,3 +246,12 @@ void reset_gmlan_switch_timeout(void){
void gmlan_switch_init(int timeout_enable){ void gmlan_switch_init(int timeout_enable){
} }
void lline_relay_init (void) {
}
void lline_relay_release (void) {
}
void set_lline_output(int to_set) {
}