# include  <sched.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <sys/cdefs.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <sys/resource.h> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <sys/types.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <unistd.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <algorithm> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <atomic> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <bitset> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <cassert> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <cerrno> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <cstdint> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <cstdio> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <cstdlib> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <thread> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <unordered_map> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <libusb-1.0/libusb.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "cereal/gen/cpp/car.capnp.h" 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "cereal/messaging/messaging.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "selfdrive/common/params.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "selfdrive/common/swaglog.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "selfdrive/common/timing.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "selfdrive/common/util.h" 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "selfdrive/hardware/hw.h" 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "selfdrive/locationd/ublox_msg.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "selfdrive/boardd/panda.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "selfdrive/boardd/pigeon.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define MAX_IR_POWER 0.5f 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define MIN_IR_POWER 0.0f 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# define CUTOFF_IL 200 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define SATURATE_IL 1600 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a') 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								Panda  *  panda  =  nullptr ; 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								std : : atomic < bool >  safety_setter_thread_running ( false ) ; 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								std : : atomic < bool >  ignition ( false ) ; 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								ExitHandler  do_exit ; 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  safety_setter_thread ( )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGD ( " Starting safety setter thread " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // diagnostic only is the default, needed for VIN query
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : ELM327 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  Params  p  =  Params ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // switch to SILENT when CarVin param is read
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  while  ( true )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( do_exit  | |  ! panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      safety_setter_thread_running  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    std : : string  value_vin  =  p . get ( " CarVin " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( value_vin . size ( )  >  0 )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // sanity check VIN format
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      assert ( value_vin . size ( )  = =  17 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      LOGW ( " got CarVin %s " ,  value_vin . c_str ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      break ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    util : : sleep_for ( 100 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // VIN query done, stop listening to OBDII
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : ELM327 ,  1 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  std : : string  params ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGW ( " waiting for params to set safety model " ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( true )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( do_exit  | |  ! panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      safety_setter_thread_running  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( p . getBool ( " ControlsReady " ) )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      params  =  p . get ( " CarParams " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( params . size ( )  >  0 )  break ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    util : : sleep_for ( 100 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  LOGW ( " got %d bytes CarParams " ,  params . size ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  AlignedBuffer  aligned_buf ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  capnp : : FlatArrayMessageReader  cmsg ( aligned_buf . align ( params . data ( ) ,  params . size ( ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  cereal : : CarParams : : Reader  car_params  =  cmsg . getRoot < cereal : : CarParams > ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  cereal : : CarParams : : SafetyModel  safety_model  =  car_params . getSafetyModel ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  panda - > set_unsafe_mode ( 0 ) ;   // see safety_declarations.h for allowed values
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  auto  safety_param  =  car_params . getSafetyParam ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  LOGW ( " setting safety model: %d with param %d " ,  ( int ) safety_model ,  safety_param ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  panda - > set_safety_model ( safety_model ,  safety_param ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  safety_setter_thread_running  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								bool  usb_connect ( )  { 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  static  bool  connected_once  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  std : : unique_ptr < Panda >  tmp_panda ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  try  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    assert ( panda  = =  nullptr ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    tmp_panda  =  std : : make_unique < Panda > ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  }  catch  ( std : : exception  & e )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  Params  params  =  Params ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  if  ( getenv ( " BOARDD_LOOPBACK " ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    tmp_panda - > set_loopback ( true ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  if  ( auto  fw_sig  =  tmp_panda - > get_firmware_version ( ) ;  fw_sig )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    params . put ( " PandaFirmware " ,  ( const  char  * ) fw_sig - > data ( ) ,  fw_sig - > size ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Convert to hex for offroad
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    char  fw_sig_hex_buf [ 16 ]  =  { 0 } ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    const  uint8_t  * fw_sig_buf  =  fw_sig - > data ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( size_t  i  =  0 ;  i  <  8 ;  i + + )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      fw_sig_hex_buf [ 2 * i ]  =  NIBBLE_TO_HEX ( ( uint8_t ) fw_sig_buf [ i ]  > >  4 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      fw_sig_hex_buf [ 2 * i + 1 ]  =  NIBBLE_TO_HEX ( ( uint8_t ) fw_sig_buf [ i ]  &  0xF ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    params . put ( " PandaFirmwareHex " ,  fw_sig_hex_buf ,  16 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    LOGW ( " fw signature: %.*s " ,  16 ,  fw_sig_hex_buf ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  else  {  return  false ;  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // get panda serial
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  if  ( auto  serial  =  tmp_panda - > get_serial ( ) ;  serial )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    params . put ( " PandaDongleId " ,  serial - > c_str ( ) ,  serial - > length ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    LOGW ( " panda serial: %s " ,  serial - > c_str ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  }  else  {  return  false ;  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // power on charging, only the first time. Panda can also change mode and it causes a brief disconneciton
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# ifndef __x86_64__ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( ! connected_once )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    tmp_panda - > set_usb_power_mode ( cereal : : PandaState : : UsbPowerMode : : CDP ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  if  ( tmp_panda - > has_rtc )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    setenv ( " TZ " , " UTC " , 1 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    struct  tm  sys_time  =  util : : get_time ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    struct  tm  rtc_time  =  tmp_panda - > get_rtc ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! util : : time_valid ( sys_time )  & &  util : : time_valid ( rtc_time ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      LOGE ( " System time wrong, setting from RTC.  " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           " System: %d-%02d-%02d %02d:%02d:%02d RTC: %d-%02d-%02d %02d:%02d:%02d " , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           sys_time . tm_year  +  1900 ,  sys_time . tm_mon  +  1 ,  sys_time . tm_mday , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           sys_time . tm_hour ,  sys_time . tm_min ,  sys_time . tm_sec , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           rtc_time . tm_year  +  1900 ,  rtc_time . tm_mon  +  1 ,  rtc_time . tm_mday , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           rtc_time . tm_hour ,  rtc_time . tm_min ,  rtc_time . tm_sec ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      const  struct  timeval  tv  =  { mktime ( & rtc_time ) ,  0 } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      settimeofday ( & tv ,  0 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  connected_once  =  true ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  panda  =  tmp_panda . release ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  true ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								// must be called before threads or with mutex
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  usb_retry_connect ( )  { 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  LOGW ( " attempting to connect " ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  ! usb_connect ( ) )  {  util : : sleep_for ( 100 ) ;  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( panda )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    LOGW ( " connected to board " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  ! do_exit ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  can_recv ( PubMaster  & pm )  { 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  kj : : Array < capnp : : word >  can_data ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  panda - > can_receive ( can_data ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  auto  bytes  =  can_data . asBytes ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pm . send ( " can " ,  bytes . begin ( ) ,  bytes . size ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  can_send_thread ( bool  fake_send )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGD ( " start send thread " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  AlignedBuffer  aligned_buf ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  Context  *  context  =  Context : : create ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  SubSocket  *  subscriber  =  SubSocket : : create ( context ,  " sendcan " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  assert ( subscriber  ! =  NULL ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  subscriber - > setTimeout ( 100 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // run as fast as messages come in
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Message  *  msg  =  subscriber - > receive ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! msg )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( errno  = =  EINTR )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        do_exit  =  true ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      continue ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    capnp : : FlatArrayMessageReader  cmsg ( aligned_buf . align ( msg ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    cereal : : Event : : Reader  event  =  cmsg . getRoot < cereal : : Event > ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    //Dont send if older than 1 second
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( nanos_since_boot ( )  -  event . getLogMonoTime ( )  <  1e9 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( ! fake_send )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        panda - > can_send ( event . getSendcan ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    delete  msg ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  delete  subscriber ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  delete  context ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  can_recv_thread ( )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGD ( " start recv thread " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // can = 8006
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  PubMaster  pm ( { " can " } ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // run at 100hz
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  uint64_t  dt  =  10000000ULL ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  uint64_t  next_frame_time  =  nanos_since_boot ( )  +  dt ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    can_recv ( pm ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    uint64_t  cur_time  =  nanos_since_boot ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    int64_t  remaining  =  next_frame_time  -  cur_time ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( remaining  >  0 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      std : : this_thread : : sleep_for ( std : : chrono : : nanoseconds ( remaining ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( ignition )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        LOGW ( " missed cycles (%d) %lld " ,  ( int ) - 1 * remaining / dt ,  remaining ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      next_frame_time  =  cur_time ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    next_frame_time  + =  dt ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  panda_state_thread ( bool  spoofing_started )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGD ( " start panda state thread " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  PubMaster  pm ( { " pandaState " } ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  uint32_t  no_ignition_cnt  =  0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  bool  ignition_last  =  false ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  Params  params  =  Params ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // Broadcast empty pandaState message when panda is not yet connected
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  ! panda )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    MessageBuilder  msg ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  pandaState   =  msg . initEvent ( ) . initPandaState ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    pandaState . setPandaType ( cereal : : PandaState : : PandaType : : UNKNOWN ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pm . send ( " pandaState " ,  msg ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    util : : sleep_for ( 500 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // run at 2hz
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    health_t  pandaState  =  panda - > get_state ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( spoofing_started )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      pandaState . ignition_line  =  1 ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( pandaState . safety_model  = =  ( uint8_t ) ( cereal : : CarParams : : SafetyModel : : SILENT ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ignition  =  ( ( pandaState . ignition_line  ! =  0 )  | |  ( pandaState . ignition_can  ! =  0 ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ignition )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      no_ignition_cnt  =  0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      no_ignition_cnt  + =  1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# ifndef __x86_64__ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    bool  power_save_desired  =  ! ignition ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( pandaState . power_save_enabled  ! =  power_save_desired )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      panda - > set_power_saving ( power_save_desired ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! ignition  & &  ( pandaState . safety_model  ! =  ( uint8_t ) ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // clear VIN, CarParams, and set new safety on car start
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ignition  & &  ! ignition_last )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      params . clearAll ( CLEAR_ON_IGNITION_ON ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! safety_setter_thread_running )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        safety_setter_thread_running  =  true ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        std : : thread ( safety_setter_thread ) . detach ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        LOGW ( " Safety setter thread already running " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  if  ( ! ignition  & &  ignition_last )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      params . clearAll ( CLEAR_ON_IGNITION_OFF ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Write to rtc once per minute when no ignition present
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ( panda - > has_rtc )  & &  ! ignition  & &  ( no_ignition_cnt  %  120  = =  1 ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Write time to RTC if it looks reasonable
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      setenv ( " TZ " , " UTC " , 1 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      struct  tm  sys_time  =  util : : get_time ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( util : : time_valid ( sys_time ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        struct  tm  rtc_time  =  panda - > get_rtc ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        double  seconds  =  difftime ( mktime ( & rtc_time ) ,  mktime ( & sys_time ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( std : : abs ( seconds )  >  1.1 )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          panda - > set_rtc ( sys_time ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          LOGW ( " Updating panda RTC. dt = %.2f  " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               " System: %d-%02d-%02d %02d:%02d:%02d RTC: %d-%02d-%02d %02d:%02d:%02d " , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               seconds , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               sys_time . tm_year  +  1900 ,  sys_time . tm_mon  +  1 ,  sys_time . tm_mday , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               sys_time . tm_hour ,  sys_time . tm_min ,  sys_time . tm_sec , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               rtc_time . tm_year  +  1900 ,  rtc_time . tm_mon  +  1 ,  rtc_time . tm_mday , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               rtc_time . tm_hour ,  rtc_time . tm_min ,  rtc_time . tm_sec ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ignition_last  =  ignition ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    uint16_t  fan_speed_rpm  =  panda - > get_fan_speed ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // build msg
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    MessageBuilder  msg ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  evt  =  msg . initEvent ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    evt . setValid ( panda - > comms_healthy ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  ps  =  evt . initPandaState ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setUptime ( pandaState . uptime ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( Hardware : : TICI ( ) )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      double  read_time  =  millis_since_boot ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ps . setVoltage ( std : : stoi ( util : : read_file ( " /sys/class/hwmon/hwmon1/in1_input " ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ps . setCurrent ( std : : stoi ( util : : read_file ( " /sys/class/hwmon/hwmon1/curr1_input " ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      read_time  =  millis_since_boot ( )  -  read_time ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( read_time  >  50 )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        LOGW ( " reading hwmon took %lfms " ,  read_time ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ps . setVoltage ( pandaState . voltage ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ps . setCurrent ( pandaState . current ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setIgnitionLine ( pandaState . ignition_line ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setIgnitionCan ( pandaState . ignition_can ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setControlsAllowed ( pandaState . controls_allowed ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setGasInterceptorDetected ( pandaState . gas_interceptor_detected ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setHasGps ( true ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setCanRxErrs ( pandaState . can_rx_errs ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setCanSendErrs ( pandaState . can_send_errs ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setCanFwdErrs ( pandaState . can_fwd_errs ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setGmlanSendErrs ( pandaState . gmlan_send_errs ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setPandaType ( panda - > hw_type ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setUsbPowerMode ( cereal : : PandaState : : UsbPowerMode ( pandaState . usb_power_mode ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setSafetyModel ( cereal : : CarParams : : SafetyModel ( pandaState . safety_model ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setSafetyParam ( pandaState . safety_param ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setFanSpeedRpm ( fan_speed_rpm ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setFaultStatus ( cereal : : PandaState : : FaultStatus ( pandaState . fault_status ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ps . setPowerSaveEnabled ( ( bool ) ( pandaState . power_save_enabled ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setHeartbeatLost ( ( bool ) ( pandaState . heartbeat_lost ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ps . setHarnessStatus ( cereal : : PandaState : : HarnessStatus ( pandaState . car_harness_status ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Convert faults bitset to capnp list
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    std : : bitset < sizeof ( pandaState . faults )  *  8 >  fault_bits ( pandaState . faults ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  faults  =  ps . initFaults ( fault_bits . count ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    size_t  i  =  0 ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( size_t  f  =  size_t ( cereal : : PandaState : : FaultType : : RELAY_MALFUNCTION ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        f  < =  size_t ( cereal : : PandaState : : FaultType : : INTERRUPT_RATE_TICK ) ;  f + + )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( fault_bits . test ( f ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        faults . set ( i ,  cereal : : PandaState : : FaultType ( f ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        i + + ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    pm . send ( " pandaState " ,  msg ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    panda - > send_heartbeat ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    util : : sleep_for ( 500 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  hardware_control_thread ( )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGD ( " start hardware control thread " ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  SubMaster  sm ( { " deviceState " ,  " driverCameraState " } ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  uint64_t  last_front_frame_t  =  0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  uint16_t  prev_fan_speed  =  999 ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  uint16_t  ir_pwr  =  0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  uint16_t  prev_ir_pwr  =  999 ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  bool  prev_charging_disabled  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  unsigned  int  cnt  =  0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  FirstOrderFilter  integ_lines_filter ( 0 ,  30.0 ,  0.05 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    cnt + + ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    sm . update ( 1000 ) ;  // TODO: what happens if EINTR is sent while in sm.update?
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! Hardware : : PC ( )  & &  sm . updated ( " deviceState " ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Charging mode
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      bool  charging_disabled  =  sm [ " deviceState " ] . getDeviceState ( ) . getChargingDisabled ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( charging_disabled  ! =  prev_charging_disabled )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( charging_disabled )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								          panda - > set_usb_power_mode ( cereal : : PandaState : : UsbPowerMode : : CLIENT ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								          LOGW ( " TURN OFF CHARGING! \n " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  else  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								          panda - > set_usb_power_mode ( cereal : : PandaState : : UsbPowerMode : : CDP ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								          LOGW ( " TURN ON CHARGING! \n " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        prev_charging_disabled  =  charging_disabled ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Other pandas don't have fan/IR to control
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( panda - > hw_type  ! =  cereal : : PandaState : : PandaType : : UNO  & &  panda - > hw_type  ! =  cereal : : PandaState : : PandaType : : DOS )  continue ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( sm . updated ( " deviceState " ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Fan speed
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      uint16_t  fan_speed  =  sm [ " deviceState " ] . getDeviceState ( ) . getFanSpeedPercentDesired ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( fan_speed  ! =  prev_fan_speed  | |  cnt  %  100  = =  0 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        panda - > set_fan_speed ( fan_speed ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        prev_fan_speed  =  fan_speed ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( sm . updated ( " driverCameraState " ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      auto  event  =  sm [ " driverCameraState " ] ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int  cur_integ_lines  =  event . getDriverCameraState ( ) . getIntegLines ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( Hardware : : TICI ( ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        cur_integ_lines  =  integ_lines_filter . update ( cur_integ_lines ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      last_front_frame_t  =  event . getLogMonoTime ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( cur_integ_lines  < =  CUTOFF_IL )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        ir_pwr  =  100.0  *  MIN_IR_POWER ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      }  else  if  ( cur_integ_lines  >  SATURATE_IL )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        ir_pwr  =  100.0  *  MAX_IR_POWER ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        ir_pwr  =  100.0  *  ( MIN_IR_POWER  +  ( ( cur_integ_lines  -  CUTOFF_IL )  *  ( MAX_IR_POWER  -  MIN_IR_POWER )  /  ( SATURATE_IL  -  CUTOFF_IL ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Disable ir_pwr on front frame timeout
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    uint64_t  cur_t  =  nanos_since_boot ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( cur_t  -  last_front_frame_t  >  1e9 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      ir_pwr  =  0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ir_pwr  ! =  prev_ir_pwr  | |  cnt  %  100  = =  0  | |  ir_pwr  > =  50.0 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      panda - > set_ir_pwr ( ir_pwr ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      prev_ir_pwr  =  ir_pwr ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  pigeon_publish_raw ( PubMaster  & pm ,  const  std : : string  & dat )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // create message
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  MessageBuilder  msg ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  msg . initEvent ( ) . setUbloxRaw ( capnp : : Data : : Reader ( ( uint8_t * ) dat . data ( ) ,  dat . length ( ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  pm . send ( " ubloxRaw " ,  msg ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  pigeon_thread ( )  { 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  PubMaster  pm ( { " ubloxRaw " } ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  bool  ignition_last  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  Pigeon  * pigeon  =  Hardware : : TICI ( )  ?  Pigeon : : connect ( " /dev/ttyHS0 " )  :  Pigeon : : connect ( panda ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  std : : unordered_map < char ,  uint64_t >  last_recv_time ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  std : : unordered_map < char ,  int64_t >  cls_max_dt  =  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    { ( char ) ublox : : CLASS_NAV ,  int64_t ( 900000000ULL ) } ,  // 0.9s
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { ( char ) ublox : : CLASS_RXM ,  int64_t ( 900000000ULL ) } ,  // 0.9s
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit  & &  panda - > connected )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    bool  need_reset  =  false ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    std : : string  recv  =  pigeon - > receive ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Parse message header
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ignition  & &  recv . length ( )  > =  3 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( recv [ 0 ]  = =  ( char ) ublox : : PREAMBLE1  & &  recv [ 1 ]  = =  ( char ) ublox : : PREAMBLE2 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        const  char  msg_cls  =  recv [ 2 ] ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        uint64_t  t  =  nanos_since_boot ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( t  >  last_recv_time [ msg_cls ] )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								          last_recv_time [ msg_cls ]  =  t ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Check based on message frequency
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( const  auto &  [ msg_cls ,  max_dt ]  :  cls_max_dt )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int64_t  dt  =  ( int64_t ) nanos_since_boot ( )  -  ( int64_t ) last_recv_time [ msg_cls ] ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ignition_last  & &  ignition  & &  dt  >  max_dt )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        LOG ( " ublox receive timeout, msg class: 0x%02x, dt %llu " ,  msg_cls ,  dt ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // TODO: turn on reset after verification of logs
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // need_reset = true;
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Check based on null bytes
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ignition  & &  recv . length ( )  >  0  & &  recv [ 0 ]  = =  ( char ) 0x00 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      need_reset  =  true ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      LOGW ( " received invalid ublox message while onroad, resetting panda GPS " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( recv . length ( )  >  0 )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      pigeon_publish_raw ( pm ,  recv ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // init pigeon on rising ignition edge
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // since it was turned off in low power mode
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if ( ( ignition  & &  ! ignition_last )  | |  need_reset )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      pigeon - > init ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Set receive times to current time
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      uint64_t  t  =  nanos_since_boot ( )  +  10000000000ULL ;  // Give ublox 10 seconds to start
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  ( const  auto &  [ msg_cls ,  dt ]  :  cls_max_dt )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        last_recv_time [ msg_cls ]  =  t ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  if  ( ! ignition  & &  ignition_last )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // power off on falling edge of ignition
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      LOGD ( " powering off pigeon \n " ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      pigeon - > stop ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      pigeon - > set_power ( false ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ignition_last  =  ignition ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 10ms - 100 Hz
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    util : : sleep_for ( 10 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  delete  pigeon ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								int  main ( )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  int  err ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOGW ( " starting boardd " ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // set process priority and affinity
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  err  =  set_realtime_priority ( 54 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOG ( " set priority returns %d " ,  err ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  err  =  set_core_affinity ( Hardware : : TICI ( )  ?  4  :  3 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  LOG ( " set affinity returns %d " ,  err ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  while  ( ! do_exit )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    std : : vector < std : : thread >  threads ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    threads . push_back ( std : : thread ( panda_state_thread ,  getenv ( " STARTED " )  ! =  nullptr ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // connect to the board
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( usb_retry_connect ( ) )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      threads . push_back ( std : : thread ( can_send_thread ,  getenv ( " FAKESEND " )  ! =  nullptr ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      threads . push_back ( std : : thread ( can_recv_thread ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      threads . push_back ( std : : thread ( hardware_control_thread ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      threads . push_back ( std : : thread ( pigeon_thread ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( auto  & t  :  threads )  t . join ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    delete  panda ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    panda  =  nullptr ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}