commit
7834995df4
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" |
||||
} |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
v1.2.0 |
||||
v1.2.1 |
@ -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