1282e8f5a cap libusb1 version in setup (#183) 64bcc89a9 Subaru: 545 msg must be generated 9159df9a5 Merge branch '0.5.10-chyrsler' f8ab74a1c L-line relay (#166) 11c4cdcc4 Cleanup leftover jenkins command 22572d949 Fix Jenkins build dockerfiles with same name 1d2f8f0ab Jenkins (#179) f383eee96 Power saving: wake on RX and don't print durint IRQ 9540db744 Chrysler safety: better to mention messages we don't want to forward 104950264 chrysler: forward bus 0 to bus 2 (#177) 4276c380e Additional Power saving (#170) git-subtree-dir: panda git-subtree-split: 1282e8f5a0904b1aaa50f382db2e27f20e74a154pull/3/head
							parent
							
								
									27ef9f2236
								
							
						
					
					
						commit
						3c25760cc9
					
				
				 37 changed files with 947 additions and 107 deletions
			
			
		@ -0,0 +1,3 @@ | 
				
			||||
.git | 
				
			||||
.DS_Store | 
				
			||||
boardesp/esp-open-sdk | 
				
			||||
@ -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 | 
				
			||||
@ -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" | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -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 | 
				
			||||
@ -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; | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -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 | 
				
			||||
@ -1,4 +1,7 @@ | 
				
			||||
libusb1 | 
				
			||||
libusb1 == 1.6.6 | 
				
			||||
hexdump | 
				
			||||
pycrypto | 
				
			||||
tqdm | 
				
			||||
nose | 
				
			||||
parameterized | 
				
			||||
requests | 
				
			||||
 | 
				
			||||
@ -1,3 +1,9 @@ | 
				
			||||
#!/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 | 
				
			||||
 | 
				
			||||
@ -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)) | 
				
			||||
					Loading…
					
					
				
		Reference in new issue