-
Notifications
You must be signed in to change notification settings - Fork 895
Expand file tree
/
Copy pathtest_bootkick.py
More file actions
155 lines (124 loc) · 4.22 KB
/
test_bootkick.py
File metadata and controls
155 lines (124 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import time
import pytest
from opendbc.car.structs import CarParams
from panda import Panda, PandaJungle
# NOTE: this test's thresholds are designed for a comma 3X with 2/4 supercaps removed (for speed)
PANDA_SERIAL = "300008001851333037333932"
JUNGLE_SERIAL = "26001c001451313236343430"
OBDC_PORT = 1
@pytest.fixture(autouse=True, scope="function")
def pj():
jungle = PandaJungle(JUNGLE_SERIAL)
jungle.flash()
jungle.reset()
jungle.set_ignition(False)
yield jungle
#jungle.set_panda_power(False)
jungle.close()
@pytest.fixture(scope="function")
def p(pj):
# note that the 3X's panda lib isn't updated, which
# shold be fine since it only uses stable APIs
pj.set_panda_power(True)
assert Panda.wait_for_panda(PANDA_SERIAL, 10)
p = Panda(PANDA_SERIAL)
p.flash()
p.reset()
yield p
p.close()
def setup_state(panda, jungle, state):
jungle.set_panda_power(False)
if state == "off":
wait_for_full_poweroff(jungle)
elif state == "normal boot":
jungle.set_panda_individual_power(OBDC_PORT, 1)
elif state == "QDL":
time.sleep(0.5)
jungle.set_panda_individual_power(OBDC_PORT, 1)
elif state == "ready to bootkick":
wait_for_full_poweroff(jungle)
jungle.set_panda_individual_power(OBDC_PORT, 1)
wait_for_boot(panda, jungle)
set_som_shutdown_flag(panda)
panda.set_safety_mode(CarParams.SafetyModel.silent)
panda.send_heartbeat()
wait_for_som_shutdown(panda, jungle)
else:
raise ValueError(f"unkown state: {state}")
def wait_for_som_shutdown(panda, jungle):
st = time.monotonic()
while panda.read_som_gpio():
# can take a while for the SOM to fully shutdown
if time.monotonic() - st > 120:
raise Exception("SOM didn't shutdown in time")
if check_som_boot_flag(panda):
raise Exception(f"SOM rebooted instead of shutdown: {time.monotonic() - st}s")
time.sleep(0.5)
dt = time.monotonic() - st
print("waiting for shutdown", round(dt))
dt = time.monotonic() - st
print(f"took {dt:.2f}s for SOM to shutdown")
def wait_for_full_poweroff(jungle, timeout=30):
st = time.monotonic()
time.sleep(3)
while PANDA_SERIAL in Panda.list():
if time.monotonic() - st > timeout:
raise Exception("took too long for device to turn off")
health = jungle.health()
assert all(health[f"ch{i}_power"] < 0.1 for i in range(1, 7))
def check_som_boot_flag(panda):
h = panda.health()
return h['safety_mode'] == CarParams.SafetyModel.elm327 and h['safety_param'] == 30
def set_som_shutdown_flag(panda):
panda.set_can_data_speed_kbps(0, 1000)
def wait_for_boot(panda, jungle, reset_expected=False, bootkick=False, timeout=120):
st = time.monotonic()
Panda.wait_for_panda(PANDA_SERIAL, timeout)
panda.reconnect()
if bootkick:
assert panda.health()['uptime'] > 20
else:
assert panda.health()['uptime'] < 3
for i in range(3):
assert not check_som_boot_flag(panda)
time.sleep(1)
# wait for SOM to bootup
while not check_som_boot_flag(panda):
if time.monotonic() - st > timeout:
raise Exception("SOM didn't boot in time")
time.sleep(1.0)
assert panda.health()['som_reset_triggered'] == reset_expected
def test_cold_boot(p, pj):
setup_state(p, pj, "off")
setup_state(p, pj, "normal boot")
wait_for_boot(p, pj)
def test_bootkick_ignition_line(p, pj):
setup_state(p, pj, "ready to bootkick")
pj.set_ignition(True)
wait_for_boot(p, pj, bootkick=True)
@pytest.mark.skip("test isn't reliable yet")
def test_bootkick_can_ignition(p, pj):
setup_state(p, pj, "ready to bootkick")
for _ in range(10):
# Mazda ignition signal
pj.can_send(0x9E, b'\xc0\x00\x00\x00\x00\x00\x00\x00', 0)
time.sleep(0.5)
wait_for_boot(p, pj, bootkick=True)
def test_recovery_from_qdl(p, pj):
setup_state(p, pj, "ready to bootkick")
# put into QDL using the FORCE_USB_BOOT pin
for i in range(10):
pj.set_header_pin(i, 1)
# try to boot
time.sleep(1)
pj.set_ignition(True)
time.sleep(3)
# release FORCE_USB_BOOT
for i in range(10):
pj.set_header_pin(i, 0)
# normally, this GPIO is set immediately since it's first enabled in the ABL
for i in range(17):
assert not p.read_som_gpio()
time.sleep(1)
# should boot after 45s
wait_for_boot(p, pj, reset_expected=True, bootkick=True, timeout=120)