|
|
@ -14,17 +14,19 @@ from common.timeout import Timeout |
|
|
|
from panda import Panda |
|
|
|
from panda import Panda |
|
|
|
from selfdrive.boardd.boardd import can_list_to_can_capnp |
|
|
|
from selfdrive.boardd.boardd import can_list_to_can_capnp |
|
|
|
from selfdrive.car import make_can_msg |
|
|
|
from selfdrive.car import make_can_msg |
|
|
|
|
|
|
|
from selfdrive.hardware import TICI |
|
|
|
from selfdrive.test.helpers import phone_only, with_processes |
|
|
|
from selfdrive.test.helpers import phone_only, with_processes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reset_panda(f): |
|
|
|
def reset_pandas(f): |
|
|
|
@wraps(f) |
|
|
|
@wraps(f) |
|
|
|
def wrapper(*args, **kwargs): |
|
|
|
def wrapper(*args, **kwargs): |
|
|
|
p = Panda() |
|
|
|
for serial in Panda.list(): |
|
|
|
for i in [0, 1, 2, 0xFFFF]: |
|
|
|
p = Panda(serial) |
|
|
|
p.can_clear(i) |
|
|
|
for i in [0, 1, 2, 3, 0xFFFF]: |
|
|
|
p.reset() |
|
|
|
p.can_clear(i) |
|
|
|
p.close() |
|
|
|
p.reset() |
|
|
|
|
|
|
|
p.close() |
|
|
|
f(*args, **kwargs) |
|
|
|
f(*args, **kwargs) |
|
|
|
return wrapper |
|
|
|
return wrapper |
|
|
|
|
|
|
|
|
|
|
@ -42,7 +44,7 @@ class TestBoardd(unittest.TestCase): |
|
|
|
cls.spinner.close() |
|
|
|
cls.spinner.close() |
|
|
|
|
|
|
|
|
|
|
|
@phone_only |
|
|
|
@phone_only |
|
|
|
@reset_panda |
|
|
|
@reset_pandas |
|
|
|
@with_processes(['pandad']) |
|
|
|
@with_processes(['pandad']) |
|
|
|
def test_loopback(self): |
|
|
|
def test_loopback(self): |
|
|
|
# wait for boardd to init |
|
|
|
# wait for boardd to init |
|
|
@ -50,15 +52,19 @@ class TestBoardd(unittest.TestCase): |
|
|
|
|
|
|
|
|
|
|
|
with Timeout(60, "boardd didn't start"): |
|
|
|
with Timeout(60, "boardd didn't start"): |
|
|
|
sm = messaging.SubMaster(['pandaStates']) |
|
|
|
sm = messaging.SubMaster(['pandaStates']) |
|
|
|
while sm.rcv_frame['pandaStates'] < 1: |
|
|
|
while sm.rcv_frame['pandaStates'] < 1 and len(sm['pandaStates']) == 0: |
|
|
|
sm.update(1000) |
|
|
|
sm.update(1000) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
num_pandas = len(sm['pandaStates']) |
|
|
|
|
|
|
|
if TICI: |
|
|
|
|
|
|
|
self.assertGreater(num_pandas, 1, "connect another panda for multipanda tests") |
|
|
|
|
|
|
|
|
|
|
|
# boardd blocks on CarVin and CarParams |
|
|
|
# boardd blocks on CarVin and CarParams |
|
|
|
cp = car.CarParams.new_message() |
|
|
|
cp = car.CarParams.new_message() |
|
|
|
|
|
|
|
|
|
|
|
safety_config = car.CarParams.SafetyConfig.new_message() |
|
|
|
safety_config = car.CarParams.SafetyConfig.new_message() |
|
|
|
safety_config.safetyModel = car.CarParams.SafetyModel.allOutput |
|
|
|
safety_config.safetyModel = car.CarParams.SafetyModel.allOutput |
|
|
|
cp.safetyConfigs = [safety_config] |
|
|
|
cp.safetyConfigs = [safety_config]*num_pandas |
|
|
|
|
|
|
|
|
|
|
|
params = Params() |
|
|
|
params = Params() |
|
|
|
params.put("CarVin", b"0"*17) |
|
|
|
params.put("CarVin", b"0"*17) |
|
|
@ -67,8 +73,7 @@ class TestBoardd(unittest.TestCase): |
|
|
|
|
|
|
|
|
|
|
|
sendcan = messaging.pub_sock('sendcan') |
|
|
|
sendcan = messaging.pub_sock('sendcan') |
|
|
|
can = messaging.sub_sock('can', conflate=False, timeout=100) |
|
|
|
can = messaging.sub_sock('can', conflate=False, timeout=100) |
|
|
|
|
|
|
|
time.sleep(0.2) |
|
|
|
time.sleep(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
n = 1000 |
|
|
|
n = 1000 |
|
|
|
for i in range(n): |
|
|
|
for i in range(n): |
|
|
@ -78,26 +83,27 @@ class TestBoardd(unittest.TestCase): |
|
|
|
for _ in range(random.randrange(10)): |
|
|
|
for _ in range(random.randrange(10)): |
|
|
|
to_send = [] |
|
|
|
to_send = [] |
|
|
|
for __ in range(random.randrange(100)): |
|
|
|
for __ in range(random.randrange(100)): |
|
|
|
bus = random.randrange(3) |
|
|
|
bus = random.choice([b for b in range(3*num_pandas) if b % 4 != 3]) |
|
|
|
addr = random.randrange(1, 1<<29) |
|
|
|
addr = random.randrange(1, 1<<29) |
|
|
|
dat = bytes([random.getrandbits(8) for _ in range(random.randrange(1, 9))]) |
|
|
|
dat = bytes([random.getrandbits(8) for _ in range(random.randrange(1, 9))]) |
|
|
|
sent_msgs[bus].add((addr, dat)) |
|
|
|
sent_msgs[bus].add((addr, dat)) |
|
|
|
to_send.append(make_can_msg(addr, dat, bus)) |
|
|
|
to_send.append(make_can_msg(addr, dat, bus)) |
|
|
|
sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan')) |
|
|
|
sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan')) |
|
|
|
|
|
|
|
|
|
|
|
max_recv = 10 |
|
|
|
for _ in range(100 * 2): |
|
|
|
while max_recv > 0 and any(len(sent_msgs[bus]) for bus in range(3)): |
|
|
|
|
|
|
|
recvd = messaging.drain_sock(can, wait_for_one=True) |
|
|
|
recvd = messaging.drain_sock(can, wait_for_one=True) |
|
|
|
for msg in recvd: |
|
|
|
for msg in recvd: |
|
|
|
for m in msg.can: |
|
|
|
for m in msg.can: |
|
|
|
if m.src >= 128: |
|
|
|
if m.src >= 128: |
|
|
|
k = (m.address, m.dat) |
|
|
|
key = (m.address, m.dat) |
|
|
|
assert k in sent_msgs[m.src-128] |
|
|
|
assert key in sent_msgs[m.src-128], f"got unexpected msg: {m.src=} {m.address=} {m.dat=}" |
|
|
|
sent_msgs[m.src-128].discard(k) |
|
|
|
sent_msgs[m.src-128].discard(key) |
|
|
|
max_recv -= 1 |
|
|
|
|
|
|
|
|
|
|
|
if all(len(v) == 0 for v in sent_msgs.values()): |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
# if a set isn't empty, messages got dropped |
|
|
|
# if a set isn't empty, messages got dropped |
|
|
|
for bus in range(3): |
|
|
|
for bus in sent_msgs.keys(): |
|
|
|
assert not len(sent_msgs[bus]), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages" |
|
|
|
assert not len(sent_msgs[bus]), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|