You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
3.7 KiB
106 lines
3.7 KiB
import os
|
|
import time
|
|
import numpy as np
|
|
import pytest
|
|
import random
|
|
|
|
import cereal.messaging as messaging
|
|
from cereal.services import SERVICE_LIST
|
|
from openpilot.system.hardware import HARDWARE
|
|
from openpilot.selfdrive.test.helpers import phone_only, with_processes
|
|
from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
|
|
|
|
JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ
|
|
|
|
@pytest.mark.tici
|
|
class TestBoarddSpi:
|
|
@classmethod
|
|
def setup_class(cls):
|
|
if HARDWARE.get_device_type() == 'tici':
|
|
pytest.skip("only for spi pandas")
|
|
os.environ['STARTED'] = '1'
|
|
os.environ['SPI_ERR_PROB'] = '0.001'
|
|
if not JUNGLE_SPAM:
|
|
os.environ['BOARDD_LOOPBACK'] = '1'
|
|
|
|
@phone_only
|
|
@with_processes(['pandad'])
|
|
def test_spi_corruption(self, subtests):
|
|
setup_pandad(1)
|
|
|
|
sendcan = messaging.pub_sock('sendcan')
|
|
socks = {s: messaging.sub_sock(s, conflate=False, timeout=100) for s in ('can', 'pandaStates', 'peripheralState')}
|
|
time.sleep(2)
|
|
for s in socks.values():
|
|
messaging.drain_sock_raw(s)
|
|
|
|
total_recv_count = 0
|
|
total_sent_count = 0
|
|
sent_msgs = {bus: list() for bus in range(3)}
|
|
|
|
st = time.monotonic()
|
|
ts = {s: list() for s in socks.keys()}
|
|
for _ in range(int(os.getenv("TEST_TIME", "20"))):
|
|
# send some CAN messages
|
|
if not JUNGLE_SPAM:
|
|
sent = send_random_can_messages(sendcan, random.randrange(2, 20))
|
|
for k, v in sent.items():
|
|
sent_msgs[k].extend(list(v))
|
|
total_sent_count += len(v)
|
|
|
|
for service, sock in socks.items():
|
|
for m in messaging.drain_sock(sock):
|
|
ts[service].append(m.logMonoTime)
|
|
|
|
# sanity check for corruption
|
|
assert m.valid or (service == "can")
|
|
if service == "can":
|
|
for msg in m.can:
|
|
if JUNGLE_SPAM:
|
|
# PandaJungle.set_generated_can(True)
|
|
i = msg.address - 0x200
|
|
assert msg.address >= 0x200
|
|
assert msg.src == (i%3)
|
|
assert msg.dat == b"\xff"*(i%8)
|
|
total_recv_count += 1
|
|
continue
|
|
|
|
if msg.src > 4:
|
|
continue
|
|
key = (msg.address, msg.dat)
|
|
assert key in sent_msgs[msg.src], f"got unexpected msg: {msg.src=} {msg.address=} {msg.dat=}"
|
|
# TODO: enable this
|
|
#sent_msgs[msg.src].remove(key)
|
|
total_recv_count += 1
|
|
elif service == "pandaStates":
|
|
assert len(m.pandaStates) == 1
|
|
ps = m.pandaStates[0]
|
|
assert ps.uptime < 1000
|
|
assert ps.pandaType == "tres"
|
|
assert ps.ignitionLine
|
|
assert not ps.ignitionCan
|
|
assert 4000 < ps.voltage < 14000
|
|
elif service == "peripheralState":
|
|
ps = m.peripheralState
|
|
assert ps.pandaType == "tres"
|
|
assert 4000 < ps.voltage < 14000
|
|
assert 100 < ps.current < 1000
|
|
assert ps.fanSpeedRpm < 8000
|
|
|
|
time.sleep(0.5)
|
|
et = time.monotonic() - st
|
|
|
|
print("\n======== timing report ========")
|
|
for service, times in ts.items():
|
|
dts = np.diff(times)/1e6
|
|
print(service.ljust(17), f"{np.mean(dts):7.2f} {np.min(dts):7.2f} {np.max(dts):7.2f}")
|
|
with subtests.test(msg="timing check", service=service):
|
|
edt = 1e3 / SERVICE_LIST[service].frequency
|
|
assert edt*0.9 < np.mean(dts) < edt*1.1
|
|
assert np.max(dts) < edt*8
|
|
assert np.min(dts) < edt
|
|
assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8)
|
|
|
|
with subtests.test(msg="CAN traffic"):
|
|
print(f"Sent {total_sent_count} CAN messages, got {total_recv_count} back. {total_recv_count/(total_sent_count+1e-4):.2%} received")
|
|
assert total_recv_count > 20
|
|
|