Skip to content

Commit 7e79f63

Browse files
authored
CI: add hardware reflasher (commaai#1041)
* like that * don't need that * cln * one lock like that? * or that * rename * guard with __name__ check * lib import * 20 min is on the edge
1 parent 451d630 commit 7e79f63

File tree

3 files changed

+147
-45
lines changed

3 files changed

+147
-45
lines changed

Jenkinsfile

+60-45
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,74 @@ pipeline {
44
DOCKER_IMAGE_TAG = "panda:build-${env.GIT_COMMIT}"
55
}
66
stages {
7-
stage('Build Docker Image') {
8-
steps {
9-
timeout(time: 60, unit: 'MINUTES') {
10-
script {
11-
sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD'
12-
dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}")
7+
stage ('Acquire resource locks') {
8+
options {
9+
lock(resource: "pandas")
10+
}
11+
stages {
12+
stage('Build Docker Image') {
13+
steps {
14+
timeout(time: 60, unit: 'MINUTES') {
15+
script {
16+
sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD'
17+
dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}")
18+
}
19+
}
1320
}
1421
}
15-
}
16-
}
17-
stage('pedal tests') {
18-
steps {
19-
lock(resource: "pedal", inversePrecedence: true, quantity: 1) {
20-
timeout(time: 10, unit: 'MINUTES') {
21-
script {
22-
sh "docker run --rm --privileged \
23-
--volume /dev/bus/usb:/dev/bus/usb \
24-
--volume /var/run/dbus:/var/run/dbus \
25-
--net host \
26-
${env.DOCKER_IMAGE_TAG} \
27-
bash -c 'cd /tmp/panda && PEDAL_JUNGLE=058010800f51363038363036 python ./tests/pedal/test_pedal.py'"
22+
stage('reset hardware') {
23+
steps {
24+
timeout(time: 10, unit: 'MINUTES') {
25+
script {
26+
sh "docker run --rm --privileged \
27+
--volume /dev/bus/usb:/dev/bus/usb \
28+
--volume /var/run/dbus:/var/run/dbus \
29+
--net host \
30+
${env.DOCKER_IMAGE_TAG} \
31+
bash -c 'cd /tmp/panda && scons -j8 && python ./tests/ci_reset_hw.py'"
32+
}
2833
}
2934
}
3035
}
31-
}
32-
}
33-
stage('HITL tests') {
34-
steps {
35-
lock(resource: "pandas", inversePrecedence: true, quantity: 1) {
36-
timeout(time: 20, unit: 'MINUTES') {
37-
script {
38-
sh "docker run --rm --privileged \
39-
--volume /dev/bus/usb:/dev/bus/usb \
40-
--volume /var/run/dbus:/var/run/dbus \
41-
--net host \
42-
${env.DOCKER_IMAGE_TAG} \
43-
bash -c 'cd /tmp/panda && scons -j8 && PANDAS_JUNGLE=23002d000851393038373731 PANDAS_EXCLUDE=\"1d0002000c51303136383232 2f002e000c51303136383232\" ./tests/automated/test.sh'"
36+
stage('pedal tests') {
37+
steps {
38+
timeout(time: 10, unit: 'MINUTES') {
39+
script {
40+
sh "docker run --rm --privileged \
41+
--volume /dev/bus/usb:/dev/bus/usb \
42+
--volume /var/run/dbus:/var/run/dbus \
43+
--net host \
44+
${env.DOCKER_IMAGE_TAG} \
45+
bash -c 'cd /tmp/panda && PEDAL_JUNGLE=058010800f51363038363036 python ./tests/pedal/test_pedal.py'"
46+
}
4447
}
4548
}
4649
}
47-
}
48-
}
49-
stage('CANFD tests') {
50-
steps {
51-
lock(resource: "pedal", inversePrecedence: true, quantity: 1) {
52-
timeout(time: 10, unit: 'MINUTES') {
53-
script {
54-
sh "docker run --rm --privileged \
55-
--volume /dev/bus/usb:/dev/bus/usb \
56-
--volume /var/run/dbus:/var/run/dbus \
57-
--net host \
58-
${env.DOCKER_IMAGE_TAG} \
59-
bash -c 'cd /tmp/panda && scons -j8 && JUNGLE=058010800f51363038363036 H7_PANDAS_EXCLUDE=\"080021000c51303136383232\" ./tests/canfd/test_canfd.py'"
50+
stage('HITL tests') {
51+
steps {
52+
timeout(time: 30, unit: 'MINUTES') {
53+
script {
54+
sh "docker run --rm --privileged \
55+
--volume /dev/bus/usb:/dev/bus/usb \
56+
--volume /var/run/dbus:/var/run/dbus \
57+
--net host \
58+
${env.DOCKER_IMAGE_TAG} \
59+
bash -c 'cd /tmp/panda && scons -j8 && PANDAS_JUNGLE=23002d000851393038373731 PANDAS_EXCLUDE=\"1d0002000c51303136383232 2f002e000c51303136383232\" ./tests/automated/test.sh'"
60+
}
61+
}
62+
}
63+
}
64+
stage('CANFD tests') {
65+
steps {
66+
timeout(time: 10, unit: 'MINUTES') {
67+
script {
68+
sh "docker run --rm --privileged \
69+
--volume /dev/bus/usb:/dev/bus/usb \
70+
--volume /var/run/dbus:/var/run/dbus \
71+
--net host \
72+
${env.DOCKER_IMAGE_TAG} \
73+
bash -c 'cd /tmp/panda && scons -j8 && JUNGLE=058010800f51363038363036 H7_PANDAS_EXCLUDE=\"080021000c51303136383232\" ./tests/canfd/test_canfd.py'"
74+
}
6075
}
6176
}
6277
}

tests/ci_reset_hw.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from panda import Panda, PandaDFU
2+
from panda.tests.libs.resetter import Resetter
3+
4+
5+
if __name__ == "__main__":
6+
r = Resetter()
7+
8+
r.enable_boot(True)
9+
r.cycle_power(5)
10+
r.enable_boot(False)
11+
12+
pandas = PandaDFU.list()
13+
print(pandas)
14+
assert len(pandas) == 7
15+
16+
for serial in pandas:
17+
p = PandaDFU(serial)
18+
p.recover()
19+
20+
r.cycle_power(5)
21+
22+
pandas = Panda.list()
23+
print(pandas)
24+
assert len(pandas) == 7
25+
26+
for serial in pandas:
27+
pf = Panda(serial)
28+
if pf.bootstub:
29+
pf.flash()
30+
pf.close()
31+
32+
r.cycle_power(0)
33+
r.close()

tests/libs/resetter.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import time
2+
import usb1
3+
4+
5+
class Resetter():
6+
def __init__(self):
7+
self._handle = None
8+
self.connect()
9+
10+
def close(self):
11+
self._handle.close()
12+
self._handle = None
13+
14+
def connect(self):
15+
if self._handle:
16+
self.close()
17+
18+
context = usb1.USBContext()
19+
self._handle = None
20+
21+
while True:
22+
try:
23+
for device in context.getDeviceList(skip_on_error=True):
24+
if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddc0:
25+
try:
26+
self._handle = device.open()
27+
self._handle.claimInterface(0)
28+
break
29+
except Exception as e:
30+
print(e)
31+
continue
32+
except Exception as e:
33+
print(e)
34+
if self._handle:
35+
break
36+
context = usb1.USBContext()
37+
assert self._handle
38+
39+
def enable_power(self, port, enabled):
40+
self._handle.controlWrite((usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE), 0xff, port, enabled, b'')
41+
42+
def enable_boot(self, enabled):
43+
self._handle.controlWrite((usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE), 0xff, 0, enabled, b'')
44+
45+
def cycle_power(self, delay=5):
46+
self.enable_power(1, False)
47+
self.enable_power(2, False)
48+
self.enable_power(3, False)
49+
time.sleep(1)
50+
self.enable_power(1, True)
51+
self.enable_power(2, True)
52+
self.enable_power(3, True)
53+
if delay > 0:
54+
time.sleep(delay)

0 commit comments

Comments
 (0)