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.
121 lines
3.7 KiB
121 lines
3.7 KiB
#!/usr/bin/env python3
|
|
import argparse
|
|
import os
|
|
import time
|
|
import threading
|
|
import multiprocessing
|
|
from tqdm import tqdm
|
|
|
|
os.environ['FILEREADER_CACHE'] = '1'
|
|
|
|
from common.basedir import BASEDIR
|
|
from common.realtime import config_realtime_process, Ratekeeper, DT_CTRL
|
|
from selfdrive.boardd.boardd import can_capnp_to_can_list
|
|
from tools.plotjuggler.juggle import load_segment
|
|
from tools.lib.logreader import logreader_from_route_or_segment
|
|
from panda import Panda
|
|
|
|
try:
|
|
# this bool can be replaced when mypy understands this pattern
|
|
panda_jungle_imported = True
|
|
from panda_jungle import PandaJungle # pylint: disable=import-error # type: ignore
|
|
except ImportError:
|
|
PandaJungle = None
|
|
panda_jungle_imported = False
|
|
|
|
|
|
def send_thread(s, flock):
|
|
if "Jungle" in str(type(s)):
|
|
if "FLASH" in os.environ:
|
|
with flock:
|
|
s.flash()
|
|
|
|
for i in [0, 1, 2, 3, 0xFFFF]:
|
|
s.can_clear(i)
|
|
s.set_ignition(False)
|
|
time.sleep(5)
|
|
s.set_ignition(True)
|
|
s.set_panda_power(True)
|
|
else:
|
|
s.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
|
|
s.set_can_loopback(False)
|
|
|
|
idx = 0
|
|
ign = True
|
|
rk = Ratekeeper(1 / DT_CTRL, print_delay_threshold=None)
|
|
while True:
|
|
# handle ignition cycling
|
|
if ENABLE_IGN:
|
|
i = (rk.frame*DT_CTRL) % (IGN_ON + IGN_OFF) < IGN_ON
|
|
if i != ign:
|
|
ign = i
|
|
s.set_ignition(ign)
|
|
|
|
snd = CAN_MSGS[idx]
|
|
snd = list(filter(lambda x: x[-1] <= 2, snd))
|
|
s.can_send_many(snd)
|
|
idx = (idx + 1) % len(CAN_MSGS)
|
|
|
|
# Drain panda message buffer
|
|
s.can_recv()
|
|
rk.keep_time()
|
|
|
|
|
|
def connect():
|
|
config_realtime_process(3, 55)
|
|
|
|
serials = {}
|
|
flashing_lock = threading.Lock()
|
|
while True:
|
|
# look for new devices
|
|
for p in [Panda, PandaJungle]:
|
|
if p is None:
|
|
continue
|
|
|
|
for s in p.list():
|
|
if s not in serials:
|
|
print("starting send thread for", s)
|
|
serials[s] = threading.Thread(target=send_thread, args=(p(s), flashing_lock))
|
|
serials[s].start()
|
|
|
|
# try to join all send threads
|
|
cur_serials = serials.copy()
|
|
for s, t in cur_serials.items():
|
|
t.join(0.01)
|
|
if not t.is_alive():
|
|
del serials[s]
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="Replay CAN messages from a route to all connected pandas and jungles in a loop.",
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to replay. If not specified, a default public route will be used.")
|
|
args = parser.parse_args()
|
|
|
|
if not panda_jungle_imported:
|
|
print("\33[31m", "WARNING: cannot connect to jungles. Clone the jungle library to enable support:", "\033[0m")
|
|
print("\033[34m", f"cd {BASEDIR} && git clone https://github.com/commaai/panda_jungle", "\033[0m")
|
|
|
|
print("Loading log...")
|
|
if args.route_or_segment_name is None:
|
|
ROUTE = "77611a1fac303767/2020-03-24--09-50-38"
|
|
REPLAY_SEGS = list(range(10, 16)) # route has 82 segments available
|
|
CAN_MSGS = []
|
|
logs = [f"https://commadataci.blob.core.windows.net/openpilotci/{ROUTE}/{i}/rlog.bz2" for i in REPLAY_SEGS]
|
|
with multiprocessing.Pool(24) as pool:
|
|
for lr in tqdm(pool.map(load_segment, logs)):
|
|
CAN_MSGS += [can_capnp_to_can_list(m.can) for m in lr if m.which() == 'can']
|
|
else:
|
|
lr = logreader_from_route_or_segment(args.route_or_segment_name)
|
|
CAN_MSGS = [can_capnp_to_can_list(m.can) for m in lr if m.which() == 'can']
|
|
|
|
# set both to cycle ignition
|
|
IGN_ON = int(os.getenv("ON", "0"))
|
|
IGN_OFF = int(os.getenv("OFF", "0"))
|
|
ENABLE_IGN = IGN_ON > 0 and IGN_OFF > 0
|
|
if ENABLE_IGN:
|
|
print(f"Cycling ignition: on for {IGN_ON}s, off for {IGN_OFF}s")
|
|
|
|
connect()
|
|
|