can_replay.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #!/usr/bin/env python3
  2. import argparse
  3. import os
  4. import time
  5. import usb1
  6. import threading
  7. os.environ['FILEREADER_CACHE'] = '1'
  8. from openpilot.common.realtime import config_realtime_process, Ratekeeper, DT_CTRL
  9. from openpilot.selfdrive.pandad import can_capnp_to_can_list
  10. from openpilot.tools.lib.logreader import LogReader
  11. from panda import PandaJungle
  12. # set both to cycle power or ignition
  13. PWR_ON = int(os.getenv("PWR_ON", "0"))
  14. PWR_OFF = int(os.getenv("PWR_OFF", "0"))
  15. IGN_ON = int(os.getenv("ON", "0"))
  16. IGN_OFF = int(os.getenv("OFF", "0"))
  17. ENABLE_IGN = IGN_ON > 0 and IGN_OFF > 0
  18. ENABLE_PWR = PWR_ON > 0 and PWR_OFF > 0
  19. def send_thread(j: PandaJungle, flock):
  20. if "FLASH" in os.environ:
  21. with flock:
  22. j.flash()
  23. j.reset()
  24. for i in [0, 1, 2, 3, 0xFFFF]:
  25. j.can_clear(i)
  26. j.set_can_speed_kbps(i, 500)
  27. j.set_ignition(True)
  28. j.set_panda_power(True)
  29. j.set_can_loopback(False)
  30. rk = Ratekeeper(1 / DT_CTRL, print_delay_threshold=None)
  31. while True:
  32. # handle cycling
  33. if ENABLE_PWR:
  34. i = (rk.frame*DT_CTRL) % (PWR_ON + PWR_OFF) < PWR_ON
  35. j.set_panda_power(i)
  36. if ENABLE_IGN:
  37. i = (rk.frame*DT_CTRL) % (IGN_ON + IGN_OFF) < IGN_ON
  38. j.set_ignition(i)
  39. send = CAN_MSGS[rk.frame % len(CAN_MSGS)]
  40. send = list(filter(lambda x: x[-1] <= 2, send))
  41. try:
  42. j.can_send_many(send)
  43. except usb1.USBErrorTimeout:
  44. # timeout is fine, just means the CAN TX buffer is full
  45. pass
  46. # Drain panda message buffer
  47. j.can_recv()
  48. rk.keep_time()
  49. def connect():
  50. config_realtime_process(3, 55)
  51. serials = {}
  52. flashing_lock = threading.Lock()
  53. while True:
  54. # look for new devices
  55. for s in PandaJungle.list():
  56. if s not in serials:
  57. print("starting send thread for", s)
  58. serials[s] = threading.Thread(target=send_thread, args=(PandaJungle(s), flashing_lock))
  59. serials[s].start()
  60. # try to join all send threads
  61. cur_serials = serials.copy()
  62. for s, t in cur_serials.items():
  63. if t is not None:
  64. t.join(0.01)
  65. if not t.is_alive():
  66. del serials[s]
  67. time.sleep(1)
  68. def process(lr):
  69. return [can_capnp_to_can_list(m.can) for m in lr if m.which() == 'can']
  70. def load_route(route_or_segment_name):
  71. print("Loading log...")
  72. sr = LogReader(route_or_segment_name)
  73. CP = sr.first("carParams")
  74. print(f"carFingerprint (for hardcoding fingerprint): '{CP.carFingerprint}'")
  75. CAN_MSGS = sr.run_across_segments(24, process)
  76. print("Finished loading...")
  77. return CAN_MSGS
  78. if __name__ == "__main__":
  79. parser = argparse.ArgumentParser(description="Replay CAN messages from a route to all connected pandas and jungles in a loop.",
  80. formatter_class=argparse.ArgumentDefaultsHelpFormatter)
  81. 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.")
  82. args = parser.parse_args()
  83. if args.route_or_segment_name is None:
  84. args.route_or_segment_name = "77611a1fac303767/2020-03-24--09-50-38/1:3"
  85. CAN_MSGS = load_route(args.route_or_segment_name)
  86. if ENABLE_PWR:
  87. print(f"Cycling power: on for {PWR_ON}s, off for {PWR_OFF}s")
  88. if ENABLE_IGN:
  89. print(f"Cycling ignition: on for {IGN_ON}s, off for {IGN_OFF}s")
  90. connect()