@ -20,6 +20,7 @@ from openpilot.common.swaglog import cloudlog 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					from  openpilot . selfdrive . boardd . boardd  import  can_list_to_can_capnp  
			
		
	
		
			
				
					from  openpilot . selfdrive . car . car_helpers  import  get_car ,  get_startup_event ,  get_one_can  
			
		
	
		
			
				
					from  openpilot . selfdrive . car . interfaces  import  CarInterfaceBase  
			
		
	
		
			
				
					from  openpilot . selfdrive . controls . lib . alertmanager  import  AlertManager ,  set_offroad_alert  
			
		
	
		
			
				
					from  openpilot . selfdrive . controls . lib . drive_helpers  import  VCruiseHelper ,  clip_curvature  
			
		
	
		
			
				
					from  openpilot . selfdrive . controls . lib . events  import  Events ,  ET  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -60,22 +61,111 @@ ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding) 
			
		
	
		
			
				
					ENABLED_STATES  =  ( State . preEnabled ,  * ACTIVE_STATES )  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					class  CarD :  
			
		
	
		
			
				
					  CI :  CarInterfaceBase   
			
		
	
		
			
				
					  CS :  car . CarState   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  def  __init__ ( self ,  CI = None ) :   
			
		
	
		
			
				
					    self . can_sock  =  messaging . sub_sock ( ' can ' ,  timeout = 20 )   
			
		
	
		
			
				
					    self . sm  =  messaging . SubMaster ( [ ' pandaStates ' ] )   
			
		
	
		
			
				
					    self . pm  =  messaging . PubMaster ( [ ' sendcan ' ,  ' carState ' ,  ' carParams ' ] )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . can_rcv_timeout_counter  =  0       # conseuctive timeout count   
			
		
	
		
			
				
					    self . can_rcv_cum_timeout_counter  =  0   # cumulative timeout count   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . params  =  Params ( )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  CI  is  None :   
			
		
	
		
			
				
					      # wait for one pandaState and one CAN packet   
			
		
	
		
			
				
					      print ( " Waiting for CAN messages... " )   
			
		
	
		
			
				
					      get_one_can ( self . can_sock )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      num_pandas  =  len ( messaging . recv_one_retry ( self . sm . sock [ ' pandaStates ' ] ) . pandaStates )   
			
		
	
		
			
				
					      experimental_long_allowed  =  self . params . get_bool ( " ExperimentalLongitudinalEnabled " )   
			
		
	
		
			
				
					      self . CI ,  self . CP  =  get_car ( self . can_sock ,  self . pm . sock [ ' sendcan ' ] ,  experimental_long_allowed ,  num_pandas )   
			
		
	
		
			
				
					    else :   
			
		
	
		
			
				
					      self . CI ,  self . CP  =  CI ,  CI . CP   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  def  initialize ( self ) :   
			
		
	
		
			
				
					    """ Initialize CarInterface, once controls are ready """   
			
		
	
		
			
				
					    self . CI . init ( self . CP ,  self . can_sock ,  self . pm . sock [ ' sendcan ' ] )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  def  state_update ( self ,  CC :  car . CarControl ) :   
			
		
	
		
			
				
					    """ carState update loop, driven by can """   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # TODO: This should not depend on carControl   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # Update carState from CAN   
			
		
	
		
			
				
					    can_strs  =  messaging . drain_sock_raw ( self . can_sock ,  wait_for_one = True )   
			
		
	
		
			
				
					    self . CS  =  self . CI . update ( CC ,  can_strs )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . sm . update ( 0 )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    can_rcv_valid  =  len ( can_strs )  >  0   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # Check for CAN timeout   
			
		
	
		
			
				
					    if  not  can_rcv_valid :   
			
		
	
		
			
				
					      self . can_rcv_timeout_counter  + =  1   
			
		
	
		
			
				
					      self . can_rcv_cum_timeout_counter  + =  1   
			
		
	
		
			
				
					    else :   
			
		
	
		
			
				
					      self . can_rcv_timeout_counter  =  0   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . can_rcv_timeout  =  self . can_rcv_timeout_counter  > =  5   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  can_rcv_valid  and  REPLAY :   
			
		
	
		
			
				
					      self . can_log_mono_time  =  messaging . log_from_bytes ( can_strs [ 0 ] ) . logMonoTime   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    return  self . CS   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  def  state_publish ( self ,  car_events ) :   
			
		
	
		
			
				
					    """ carState and carParams publish loop """   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # TODO: carState should be independent of the event loop   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # carState   
			
		
	
		
			
				
					    cs_send  =  messaging . new_message ( ' carState ' )   
			
		
	
		
			
				
					    cs_send . valid  =  self . CS . canValid   
			
		
	
		
			
				
					    cs_send . carState  =  self . CS   
			
		
	
		
			
				
					    cs_send . carState . events  =  car_events   
			
		
	
		
			
				
					    self . pm . send ( ' carState ' ,  cs_send )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # carParams - logged every 50 seconds (> 1 per segment)   
			
		
	
		
			
				
					    if  ( self . sm . frame  %  int ( 50.  /  DT_CTRL )  ==  0 ) :   
			
		
	
		
			
				
					      cp_send  =  messaging . new_message ( ' carParams ' )   
			
		
	
		
			
				
					      cp_send . valid  =  True   
			
		
	
		
			
				
					      cp_send . carParams  =  self . CP   
			
		
	
		
			
				
					      self . pm . send ( ' carParams ' ,  cp_send )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  def  controls_update ( self ,  CC :  car . CarControl ) :   
			
		
	
		
			
				
					    """ control update loop, driven by carControl """   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # send car controls over can   
			
		
	
		
			
				
					    now_nanos  =  self . can_log_mono_time  if  REPLAY  else  int ( time . monotonic ( )  *  1e9 )   
			
		
	
		
			
				
					    actuators_output ,  can_sends  =  self . CI . apply ( CC ,  now_nanos )   
			
		
	
		
			
				
					    self . pm . send ( ' sendcan ' ,  can_list_to_can_capnp ( can_sends ,  msgtype = ' sendcan ' ,  valid = self . CS . canValid ) )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    return  actuators_output   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					class  Controls :  
			
		
	
		
			
				
					  def  __init__ ( self ,  CI = None ) :   
			
		
	
		
			
				
					    self . card  =  CarD ( CI )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . CP  =  self . card . CP   
			
		
	
		
			
				
					    self . CI  =  self . card . CI   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    config_realtime_process ( 4 ,  Priority . CTRL_HIGH )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # Ensure the current branch is cached, otherwise the first iteration of controlsd lags   
			
		
	
		
			
				
					    self . branch  =  get_short_branch ( )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # Setup sockets   
			
		
	
		
			
				
					    self . pm  =  messaging . PubMaster ( [ ' sendcan ' ,  ' controlsState ' ,  ' carState ' ,   
			
		
	
		
			
				
					                                   ' carControl ' ,  ' onroadEvents ' ,  ' carParams ' ] )   
			
		
	
		
			
				
					    self . pm  =  messaging . PubMaster ( [ ' controlsState ' ,  ' carControl ' ,  ' onroadEvents ' ] )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . sensor_packets  =  [ " accelerometer " ,  " gyroscope " ]   
			
		
	
		
			
				
					    self . camera_packets  =  [ " roadCameraState " ,  " driverCameraState " ,  " wideRoadCameraState " ]   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . log_sock  =  messaging . sub_sock ( ' androidLog ' )   
			
		
	
		
			
				
					    self . can_sock  =  messaging . sub_sock ( ' can ' ,  timeout = 20 )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . params  =  Params ( )   
			
		
	
		
			
				
					    ignore  =  self . sensor_packets  +  [ ' testJoystick ' ]   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -88,17 +178,6 @@ class Controls: 
			
		
	
		
			
				
					                                  ignore_alive = ignore ,  ignore_avg_freq = ignore + [ ' radarState ' ,  ' testJoystick ' ] ,  ignore_valid = [ ' testJoystick ' ,  ] ,   
			
		
	
		
			
				
					                                  frequency = int ( 1 / DT_CTRL ) )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  CI  is  None :   
			
		
	
		
			
				
					      # wait for one pandaState and one CAN packet   
			
		
	
		
			
				
					      print ( " Waiting for CAN messages... " )   
			
		
	
		
			
				
					      get_one_can ( self . can_sock )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      num_pandas  =  len ( messaging . recv_one_retry ( self . sm . sock [ ' pandaStates ' ] ) . pandaStates )   
			
		
	
		
			
				
					      experimental_long_allowed  =  self . params . get_bool ( " ExperimentalLongitudinalEnabled " )   
			
		
	
		
			
				
					      self . CI ,  self . CP  =  get_car ( self . can_sock ,  self . pm . sock [ ' sendcan ' ] ,  experimental_long_allowed ,  num_pandas )   
			
		
	
		
			
				
					    else :   
			
		
	
		
			
				
					      self . CI ,  self . CP  =  CI ,  CI . CP   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . joystick_mode  =  self . params . get_bool ( " JoystickDebugMode " )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # set alternative experiences from parameters   
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -164,8 +243,6 @@ class Controls: 
			
		
	
		
			
				
					    self . soft_disable_timer  =  0   
			
		
	
		
			
				
					    self . mismatch_counter  =  0   
			
		
	
		
			
				
					    self . cruise_mismatch_counter  =  0   
			
		
	
		
			
				
					    self . can_rcv_timeout_counter  =  0       # conseuctive timeout count   
			
		
	
		
			
				
					    self . can_rcv_cum_timeout_counter  =  0   # cumulative timeout count   
			
		
	
		
			
				
					    self . last_blinker_frame  =  0   
			
		
	
		
			
				
					    self . last_steering_pressed_frame  =  0   
			
		
	
		
			
				
					    self . distance_traveled  =  0   
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -353,10 +430,9 @@ class Controls: 
			
		
	
		
			
				
					      self . events . add ( EventName . canError )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # generic catch-all. ideally, a more specific event should be added above instead   
			
		
	
		
			
				
					    can_rcv_timeout  =  self . can_rcv_timeout_counter  > =  5   
			
		
	
		
			
				
					    has_disable_events  =  self . events . contains ( ET . NO_ENTRY )  and  ( self . events . contains ( ET . SOFT_DISABLE )  or  self . events . contains ( ET . IMMEDIATE_DISABLE ) )   
			
		
	
		
			
				
					    no_system_errors  =  ( not  has_disable_events )  or  ( len ( self . events )  ==  num_events )   
			
		
	
		
			
				
					    if  ( not  self . sm . all_checks ( )  or  can_rcv_timeout )  and  no_system_errors :   
			
		
	
		
			
				
					    if  ( not  self . sm . all_checks ( )  or  self . card . can_rcv_timeout )  and  no_system_errors :   
			
		
	
		
			
				
					      if  not  self . sm . all_alive ( ) :   
			
		
	
		
			
				
					        self . events . add ( EventName . commIssue )   
			
		
	
		
			
				
					      elif  not  self . sm . all_freq_ok ( ) :   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -368,7 +444,7 @@ class Controls: 
			
		
	
		
			
				
					        ' invalid ' :  [ s  for  s ,  valid  in  self . sm . valid . items ( )  if  not  valid ] ,   
			
		
	
		
			
				
					        ' not_alive ' :  [ s  for  s ,  alive  in  self . sm . alive . items ( )  if  not  alive ] ,   
			
		
	
		
			
				
					        ' not_freq_ok ' :  [ s  for  s ,  freq_ok  in  self . sm . freq_ok . items ( )  if  not  freq_ok ] ,   
			
		
	
		
			
				
					        ' can_rcv_timeout ' :  can_rcv_timeout ,   
			
		
	
		
			
				
					        ' can_rcv_timeout ' :  self . card . can_rcv_timeout ,   
			
		
	
		
			
				
					      }   
			
		
	
		
			
				
					      if  logs  !=  self . logged_comm_issue :   
			
		
	
		
			
				
					        cloudlog . event ( " commIssue " ,  error = True ,  * * logs )   
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -430,11 +506,7 @@ class Controls: 
			
		
	
		
			
				
					  def  data_sample ( self ) :   
			
		
	
		
			
				
					    """ Receive data from sockets and update carState """   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # Update carState from CAN   
			
		
	
		
			
				
					    can_strs  =  messaging . drain_sock_raw ( self . can_sock ,  wait_for_one = True )   
			
		
	
		
			
				
					    CS  =  self . CI . update ( self . CC ,  can_strs )   
			
		
	
		
			
				
					    if  len ( can_strs )  and  REPLAY :   
			
		
	
		
			
				
					      self . can_log_mono_time  =  messaging . log_from_bytes ( can_strs [ 0 ] ) . logMonoTime   
			
		
	
		
			
				
					    CS  =  self . card . state_update ( self . CC )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . sm . update ( 0 )   
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -449,7 +521,7 @@ class Controls: 
			
		
	
		
			
				
					          self . sm . ignore_alive . append ( ' wideRoadCameraState ' )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        if  not  self . CP . passive :   
			
		
	
		
			
				
					          self . CI . init ( self . CP ,  self . can_sock ,  self . pm . sock [ ' sendcan ' ] )   
			
		
	
		
			
				
					          self . card . initialize ( )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . initialized  =  True   
			
		
	
		
			
				
					        self . set_initial_state ( )   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -466,13 +538,6 @@ class Controls: 
			
		
	
		
			
				
					          error = True ,   
			
		
	
		
			
				
					        )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # Check for CAN timeout   
			
		
	
		
			
				
					    if  not  can_strs :   
			
		
	
		
			
				
					      self . can_rcv_timeout_counter  + =  1   
			
		
	
		
			
				
					      self . can_rcv_cum_timeout_counter  + =  1   
			
		
	
		
			
				
					    else :   
			
		
	
		
			
				
					      self . can_rcv_timeout_counter  =  0   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # When the panda and controlsd do not agree on controls_allowed   
			
		
	
		
			
				
					    # we want to disengage openpilot. However the status from the panda goes through   
			
		
	
		
			
				
					    # another socket other than the CAN messages and one can arrive earlier than the other.   
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -761,10 +826,7 @@ class Controls: 
			
		
	
		
			
				
					      hudControl . visualAlert  =  current_alert . visual_alert   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  not  self . CP . passive  and  self . initialized :   
			
		
	
		
			
				
					      # send car controls over can   
			
		
	
		
			
				
					      now_nanos  =  self . can_log_mono_time  if  REPLAY  else  int ( time . monotonic ( )  *  1e9 )   
			
		
	
		
			
				
					      self . last_actuators ,  can_sends  =  self . CI . apply ( CC ,  now_nanos )   
			
		
	
		
			
				
					      self . pm . send ( ' sendcan ' ,  can_list_to_can_capnp ( can_sends ,  msgtype = ' sendcan ' ,  valid = CS . canValid ) )   
			
		
	
		
			
				
					      self . last_actuators  =  self . card . controls_update ( CC )   
			
		
	
		
			
				
					      CC . actuatorsOutput  =  self . last_actuators   
			
		
	
		
			
				
					      if  self . CP . steerControlType  ==  car . CarParams . SteerControlType . angle :   
			
		
	
		
			
				
					        self . steer_limited  =  abs ( CC . actuators . steeringAngleDeg  -  CC . actuatorsOutput . steeringAngleDeg )  >  \  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -812,7 +874,7 @@ class Controls: 
			
		
	
		
			
				
					    controlsState . cumLagMs  =  - self . rk . remaining  *  1000.   
			
		
	
		
			
				
					    controlsState . startMonoTime  =  int ( start_time  *  1e9 )   
			
		
	
		
			
				
					    controlsState . forceDecel  =  bool ( force_decel )   
			
		
	
		
			
				
					    controlsState . canErrorCounter  =  self . can_rcv_cum_timeout_counter   
			
		
	
		
			
				
					    controlsState . canErrorCounter  =  self . card . ca n_rcv_cum_timeout_counter   
			
		
	
		
			
				
					    controlsState . experimentalMode  =  self . experimental_mode   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    lat_tuning  =  self . CP . lateralTuning . which ( )   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -827,13 +889,9 @@ class Controls: 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . pm . send ( ' controlsState ' ,  dat )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # carState   
			
		
	
		
			
				
					    car_events  =  self . events . to_msg ( )   
			
		
	
		
			
				
					    cs_send  =  messaging . new_message ( ' carState ' )   
			
		
	
		
			
				
					    cs_send . valid  =  CS . canValid   
			
		
	
		
			
				
					    cs_send . carState  =  CS   
			
		
	
		
			
				
					    cs_send . carState . events  =  car_events   
			
		
	
		
			
				
					    self . pm . send ( ' carState ' ,  cs_send )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    self . card . state_publish ( car_events )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # onroadEvents - logged every second or on change   
			
		
	
		
			
				
					    if  ( self . sm . frame  %  int ( 1.  /  DT_CTRL )  ==  0 )  or  ( self . events . names  !=  self . events_prev ) :   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -843,13 +901,6 @@ class Controls: 
			
		
	
		
			
				
					      self . pm . send ( ' onroadEvents ' ,  ce_send )   
			
		
	
		
			
				
					    self . events_prev  =  self . events . names . copy ( )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # carParams - logged every 50 seconds (> 1 per segment)   
			
		
	
		
			
				
					    if  ( self . sm . frame  %  int ( 50.  /  DT_CTRL )  ==  0 ) :   
			
		
	
		
			
				
					      cp_send  =  messaging . new_message ( ' carParams ' )   
			
		
	
		
			
				
					      cp_send . valid  =  True   
			
		
	
		
			
				
					      cp_send . carParams  =  self . CP   
			
		
	
		
			
				
					      self . pm . send ( ' carParams ' ,  cp_send )   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # carControl   
			
		
	
		
			
				
					    cc_send  =  messaging . new_message ( ' carControl ' )   
			
		
	
		
			
				
					    cc_send . valid  =  CS . canValid