|  |  |  | #!/usr/bin/env python3
 | 
					
						
							|  |  |  | import os
 | 
					
						
							|  |  |  | import pytest
 | 
					
						
							|  |  |  | import time
 | 
					
						
							|  |  |  | import subprocess
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import cereal.messaging as messaging
 | 
					
						
							|  |  |  | from openpilot.common.basedir import BASEDIR
 | 
					
						
							|  |  |  | from openpilot.common.timeout import Timeout
 | 
					
						
							|  |  |  | from openpilot.selfdrive.test.helpers import set_params_enabled
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @pytest.mark.tici
 | 
					
						
							|  |  |  | def test_time_to_onroad():
 | 
					
						
							|  |  |  |   # launch
 | 
					
						
							|  |  |  |   set_params_enabled()
 | 
					
						
							|  |  |  |   manager_path = os.path.join(BASEDIR, "selfdrive/manager/manager.py")
 | 
					
						
							|  |  |  |   proc = subprocess.Popen(["python", manager_path])
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   start_time = time.monotonic()
 | 
					
						
							|  |  |  |   sm = messaging.SubMaster(['controlsState', 'deviceState', 'onroadEvents', 'sendcan'])
 | 
					
						
							|  |  |  |   try:
 | 
					
						
							|  |  |  |     # wait for onroad. timeout assumes panda is up to date
 | 
					
						
							|  |  |  |     with Timeout(10, "timed out waiting to go onroad"):
 | 
					
						
							|  |  |  |       while not sm['deviceState'].started:
 | 
					
						
							|  |  |  |         sm.update(100)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # wait for engageability
 | 
					
						
							|  |  |  |     try:
 | 
					
						
							|  |  |  |       with Timeout(10, "timed out waiting for engageable"):
 | 
					
						
							|  |  |  |         sendcan_frame = None
 | 
					
						
							|  |  |  |         while True:
 | 
					
						
							|  |  |  |           sm.update(100)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           # sendcan is only sent once we're initialized
 | 
					
						
							|  |  |  |           if sm.seen['controlsState'] and sendcan_frame is None:
 | 
					
						
							|  |  |  |             sendcan_frame = sm.frame
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if sendcan_frame is not None and sm.recv_frame['sendcan'] > sendcan_frame:
 | 
					
						
							|  |  |  |             sm.update(100)
 | 
					
						
							|  |  |  |             assert sm['controlsState'].engageable, f"events: {sm['onroadEvents']}"
 | 
					
						
							|  |  |  |             break
 | 
					
						
							|  |  |  |     finally:
 | 
					
						
							|  |  |  |       print(f"onroad events: {sm['onroadEvents']}")
 | 
					
						
							|  |  |  |     print(f"engageable after {time.monotonic() - start_time:.2f}s")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # once we're enageable, must stay for the next few seconds
 | 
					
						
							|  |  |  |     st = time.monotonic()
 | 
					
						
							|  |  |  |     while (time.monotonic() - st) < 10.:
 | 
					
						
							|  |  |  |       sm.update(100)
 | 
					
						
							|  |  |  |       assert sm.all_alive(), sm.alive
 | 
					
						
							|  |  |  |       assert sm['controlsState'].engageable, f"events: {sm['onroadEvents']}"
 | 
					
						
							|  |  |  |       assert sm['controlsState'].cumLagMs < 10.
 | 
					
						
							|  |  |  |   finally:
 | 
					
						
							|  |  |  |     proc.terminate()
 | 
					
						
							|  |  |  |     if proc.wait(20) is None:
 | 
					
						
							|  |  |  |       proc.kill()
 |