# include  "selfdrive/pandad/pandad.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <algorithm> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <array> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <bitset> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <cassert> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <cerrno> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <memory> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <thread> 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								# include  <utility> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "cereal/gen/cpp/car.capnp.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "cereal/messaging/messaging.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "common/ratekeeper.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "common/swaglog.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "common/timing.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "common/util.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "system/hardware/hw.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// -- Multi-panda conventions --
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Ordering:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - The internal panda will always be the first panda
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - Consecutive pandas will be sorted based on panda type, and then serial number
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Connecting:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - If a panda connection is dropped, pandad will reconnect to all pandas
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - If a panda is added, we will only reconnect when we are offroad
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// CAN buses:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - Each panda will have it's block of 4 buses. E.g.: the second panda will use
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//   bus numbers 4, 5, 6 and 7
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - The internal panda will always be used for accessing the OBD2 port,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//   and thus firmware queries
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Safety:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - SafetyConfig is a list, which is mapped to the connected pandas
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - If there are more pandas connected than there are SafetyConfigs,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//   the excess pandas will remain in "silent" or "noOutput" mode
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Ignition:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// - If any of the ignition sources in any panda is high, ignition is high
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define MAX_IR_POWER 0.5f 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define MIN_IR_POWER 0.0f 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define CUTOFF_IL 400 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define SATURATE_IL 1000 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								ExitHandler  do_exit ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								bool  check_all_connected ( const  std : : vector < Panda  * >  & pandas )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( const  auto &  panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! panda - > connected ( ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      do_exit  =  true ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      return  false ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  return  true ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								Panda  * connect ( std : : string  serial = " " ,  uint32_t  index = 0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : unique_ptr < Panda >  panda ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  try  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    panda  =  std : : make_unique < Panda > ( serial ,  ( index  *  PANDA_BUS_OFFSET ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  }  catch  ( std : : exception  & e )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  nullptr ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // common panda config
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( getenv ( " BOARDD_LOOPBACK " ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    panda - > set_loopback ( true ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  //panda->enable_deepsleep();
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  for  ( int  i  =  0 ;  i  <  PANDA_BUS_CNT ;  i + + )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    panda - > set_can_fd_auto ( i ,  true ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( ! panda - > up_to_date ( )  & &  ! getenv ( " BOARDD_SKIP_FW_CHECK " ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    throw  std : : runtime_error ( " Panda firmware out of date. Run pandad.py to update. " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  return  panda . release ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  can_send_thread ( std : : vector < Panda  * >  pandas ,  bool  fake_send )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  util : : set_thread_name ( " pandad_can_send " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  AlignedBuffer  aligned_buf ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : unique_ptr < Context >  context ( Context : : create ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : unique_ptr < SubSocket >  subscriber ( SubSocket : : create ( context . get ( ) ,  " sendcan " ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  assert ( subscriber  ! =  NULL ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  subscriber - > setTimeout ( 100 ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // run as fast as messages come in
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  while  ( ! do_exit  & &  check_all_connected ( pandas ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    std : : unique_ptr < Message >  msg ( subscriber - > receive ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! msg )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      continue ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    capnp : : FlatArrayMessageReader  cmsg ( aligned_buf . align ( msg . get ( ) ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    cereal : : Event : : Reader  event  =  cmsg . getRoot < cereal : : Event > ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Don't send if older than 1 second
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ( nanos_since_boot ( )  -  event . getLogMonoTime ( )  <  1e9 )  & &  ! fake_send )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      for  ( const  auto &  panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        LOGT ( " sending sendcan to panda: %s " ,  ( panda - > hw_serial ( ) ) . c_str ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        panda - > can_send ( event . getSendcan ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        LOGT ( " sendcan sent to panda: %s " ,  ( panda - > hw_serial ( ) ) . c_str ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    }  else  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      LOGE ( " sendcan too old to send: % "  PRIu64  " , % "  PRIu64 ,  nanos_since_boot ( ) ,  event . getLogMonoTime ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  can_recv ( std : : vector < Panda  * >  & pandas ,  PubMaster  * pm )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  static  std : : vector < can_frame >  raw_can_data ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    bool  comms_healthy  =  true ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    raw_can_data . clear ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( const  auto &  panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      comms_healthy  & =  panda - > can_receive ( raw_can_data ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    MessageBuilder  msg ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  evt  =  msg . initEvent ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    evt . setValid ( comms_healthy ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  canData  =  evt . initCan ( raw_can_data . size ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    for  ( size_t  i  =  0 ;  i  <  raw_can_data . size ( ) ;  + + i )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      canData [ i ] . setAddress ( raw_can_data [ i ] . address ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      canData [ i ] . setDat ( kj : : arrayPtr ( ( uint8_t * ) raw_can_data [ i ] . dat . data ( ) ,  raw_can_data [ i ] . dat . size ( ) ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      canData [ i ] . setSrc ( raw_can_data [ i ] . src ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pm - > send ( " can " ,  msg ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  fill_panda_state ( cereal : : PandaState : : Builder  & ps ,  cereal : : PandaState : : PandaType  hw_type ,  const  health_t  & health )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setVoltage ( health . voltage_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setCurrent ( health . current_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setUptime ( health . uptime_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSafetyTxBlocked ( health . safety_tx_blocked_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSafetyRxInvalid ( health . safety_rx_invalid_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setIgnitionLine ( health . ignition_line_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setIgnitionCan ( health . ignition_can_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setControlsAllowed ( health . controls_allowed_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setTxBufferOverflow ( health . tx_buffer_overflow_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setRxBufferOverflow ( health . rx_buffer_overflow_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setPandaType ( hw_type ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSafetyModel ( cereal : : CarParams : : SafetyModel ( health . safety_mode_pkt ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSafetyParam ( health . safety_param_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setFaultStatus ( cereal : : PandaState : : FaultStatus ( health . fault_status_pkt ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setPowerSaveEnabled ( ( bool ) ( health . power_save_enabled_pkt ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setHeartbeatLost ( ( bool ) ( health . heartbeat_lost_pkt ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setAlternativeExperience ( health . alternative_experience_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setHarnessStatus ( cereal : : PandaState : : HarnessStatus ( health . car_harness_status_pkt ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setInterruptLoad ( health . interrupt_load_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setFanPower ( health . fan_power ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setFanStallCount ( health . fan_stall_count ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSafetyRxChecksInvalid ( ( bool ) ( health . safety_rx_checks_invalid_pkt ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSpiChecksumErrorCount ( health . spi_checksum_error_count_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSbu1Voltage ( health . sbu1_voltage_mV  /  1000.0f ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setSbu2Voltage ( health . sbu2_voltage_mV  /  1000.0f ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  fill_panda_can_state ( cereal : : PandaState : : PandaCanState : : Builder  & cs ,  const  can_health_t  & can_health )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setBusOff ( ( bool ) can_health . bus_off ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setBusOffCnt ( can_health . bus_off_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setErrorWarning ( ( bool ) can_health . error_warning ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setErrorPassive ( ( bool ) can_health . error_passive ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setLastError ( cereal : : PandaState : : PandaCanState : : LecErrorCode ( can_health . last_error ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setLastStoredError ( cereal : : PandaState : : PandaCanState : : LecErrorCode ( can_health . last_stored_error ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setLastDataError ( cereal : : PandaState : : PandaCanState : : LecErrorCode ( can_health . last_data_error ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setLastDataStoredError ( cereal : : PandaState : : PandaCanState : : LecErrorCode ( can_health . last_data_stored_error ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setReceiveErrorCnt ( can_health . receive_error_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTransmitErrorCnt ( can_health . transmit_error_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTotalErrorCnt ( can_health . total_error_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTotalTxLostCnt ( can_health . total_tx_lost_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTotalRxLostCnt ( can_health . total_rx_lost_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTotalTxCnt ( can_health . total_tx_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTotalRxCnt ( can_health . total_rx_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setTotalFwdCnt ( can_health . total_fwd_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setCanSpeed ( can_health . can_speed ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setCanDataSpeed ( can_health . can_data_speed ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setCanfdEnabled ( can_health . canfd_enabled ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setBrsEnabled ( can_health . brs_enabled ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setCanfdNonIso ( can_health . canfd_non_iso ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setIrq0CallRate ( can_health . irq0_call_rate ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setIrq1CallRate ( can_health . irq1_call_rate ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setIrq2CallRate ( can_health . irq2_call_rate ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  cs . setCanCoreResetCnt ( can_health . can_core_reset_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								std : : optional < bool >  send_panda_states ( PubMaster  * pm ,  const  std : : vector < Panda  * >  & pandas ,  bool  spoofing_started )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  bool  ignition_local  =  false ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  uint32_t  pandas_cnt  =  pandas . size ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // build msg
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  MessageBuilder  msg ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  auto  evt  =  msg . initEvent ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  auto  pss  =  evt . initPandaStates ( pandas_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : vector < health_t >  pandaStates ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pandaStates . reserve ( pandas_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : vector < std : : array < can_health_t ,  PANDA_CAN_CNT > >  pandaCanStates ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pandaCanStates . reserve ( pandas_cnt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  bool  red_panda_comma_three  =  ( pandas . size ( )  = =  2 )  & & 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                     ( pandas [ 0 ] - > hw_type  = =  cereal : : PandaState : : PandaType : : DOS )  & & 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                     ( pandas [ 1 ] - > hw_type  = =  cereal : : PandaState : : PandaType : : RED_PANDA ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( const  auto &  panda  :  pandas ) { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  health_opt  =  panda - > get_state ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! health_opt )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      return  std : : nullopt ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    health_t  health  =  * health_opt ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    std : : array < can_health_t ,  PANDA_CAN_CNT >  can_health { } ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( uint32_t  i  =  0 ;  i  <  PANDA_CAN_CNT ;  i + + )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      auto  can_health_opt  =  panda - > get_can_state ( i ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( ! can_health_opt )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  std : : nullopt ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      can_health [ i ]  =  * can_health_opt ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pandaCanStates . push_back ( can_health ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( spoofing_started )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      health . ignition_line_pkt  =  1 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // on comma three setups with a red panda, the dos can
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // get false positive ignitions due to the harness box
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // without a harness connector, so ignore it
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( red_panda_comma_three  & &  ( panda - > hw_type  = =  cereal : : PandaState : : PandaType : : DOS ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      health . ignition_line_pkt  =  0 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ignition_local  | =  ( ( health . ignition_line_pkt  ! =  0 )  | |  ( health . ignition_can_pkt  ! =  0 ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pandaStates . push_back ( health ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( uint32_t  i  =  0 ;  i  <  pandas_cnt ;  i + + )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  panda  =  pandas [ i ] ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    const  auto  & health  =  pandaStates [ i ] ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // 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  ( health . safety_mode_pkt  = =  ( uint8_t ) ( cereal : : CarParams : : SafetyModel : : SILENT ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    bool  power_save_desired  =  ! ignition_local ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( health . power_save_enabled_pkt  ! =  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_local  & &  ( health . safety_mode_pkt  ! =  ( uint8_t ) ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! panda - > comms_healthy ( ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      evt . setValid ( false ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  ps  =  pss [ i ] ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    fill_panda_state ( ps ,  panda - > hw_type ,  health ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    auto  cs  =  std : : array { ps . initCanState0 ( ) ,  ps . initCanState1 ( ) ,  ps . initCanState2 ( ) } ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( uint32_t  j  =  0 ;  j  <  PANDA_CAN_CNT ;  j + + )  { 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								      fill_panda_can_state ( cs [ j ] ,  pandaCanStates [ i ] [ j ] ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert faults bitset to capnp list
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    std : : bitset < sizeof ( health . faults_pkt )  *  8 >  fault_bits ( health . faults_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  faults  =  ps . initFaults ( fault_bits . count ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    size_t  j  =  0 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( size_t  f  =  size_t ( cereal : : PandaState : : FaultType : : RELAY_MALFUNCTION ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								         f  < =  size_t ( cereal : : PandaState : : FaultType : : HEARTBEAT_LOOP_WATCHDOG ) ;  f + + )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( fault_bits . test ( f ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        faults . set ( j ,  cereal : : PandaState : : FaultType ( f ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        j + + ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pm - > send ( " pandaStates " ,  msg ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  return  ignition_local ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  send_peripheral_state ( Panda  * panda ,  PubMaster  * pm )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // build msg
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  MessageBuilder  msg ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  auto  evt  =  msg . initEvent ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  evt . setValid ( panda - > comms_healthy ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  auto  ps  =  evt . initPeripheralState ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setPandaType ( panda - > hw_type ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  read_time  =  millis_since_boot ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setVoltage ( Hardware : : get_voltage ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setCurrent ( Hardware : : get_current ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  read_time  =  millis_since_boot ( )  -  read_time ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( read_time  >  50 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    LOGW ( " reading hwmon took %lfms " ,  read_time ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  // fall back to panda's voltage and current measurement
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( ps . getVoltage ( )  = =  0  & &  ps . getCurrent ( )  = =  0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  health_opt  =  panda - > get_state ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( health_opt )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      health_t  health  =  * health_opt ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      ps . setVoltage ( health . voltage_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      ps . setCurrent ( health . current_pkt ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  uint16_t  fan_speed_rpm  =  panda - > get_fan_speed ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ps . setFanSpeedRpm ( fan_speed_rpm ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pm - > send ( " peripheralState " ,  msg ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  process_panda_state ( std : : vector < Panda  * >  & pandas ,  PubMaster  * pm ,  bool  engaged ,  bool  spoofing_started )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : vector < std : : string >  connected_serials ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( Panda  * p  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    connected_serials . push_back ( p - > hw_serial ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  ignition_opt  =  send_panda_states ( pm ,  pandas ,  spoofing_started ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! ignition_opt )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      LOGE ( " Failed to get ignition_opt " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								      return ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // check if we should have pandad reconnect
  
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    if  ( ! ignition_opt . value ( ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      bool  comms_healthy  =  true ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      for  ( const  auto  & panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        comms_healthy  & =  panda - > comms_healthy ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( ! comms_healthy )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        LOGE ( " Reconnecting, communication to pandas not healthy " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        do_exit  =  true ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      }  else  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        // check for new pandas
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        for  ( std : : string  & s  :  Panda : : list ( true ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          if  ( ! std : : count ( connected_serials . begin ( ) ,  connected_serials . end ( ) ,  s ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            LOGW ( " Reconnecting to new panda: %s " ,  s . c_str ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            do_exit  =  true ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            break ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( const  auto  & panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      panda - > send_heartbeat ( engaged ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  process_peripheral_state ( Panda  * panda ,  PubMaster  * pm ,  bool  no_fan_control )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  static  SubMaster  sm ( { " deviceState " ,  " driverCameraState " } ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  static  uint64_t  last_driver_camera_t  =  0 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  static  uint16_t  prev_fan_speed  =  999 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  static  uint16_t  ir_pwr  =  0 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  static  uint16_t  prev_ir_pwr  =  999 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  static  FirstOrderFilter  integ_lines_filter ( 0 ,  30.0 ,  0.05 ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    sm . update ( 0 ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( sm . updated ( " deviceState " )  & &  ! no_fan_control )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      // Fan speed
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      uint16_t  fan_speed  =  sm [ " deviceState " ] . getDeviceState ( ) . getFanSpeedPercentDesired ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( fan_speed  ! =  prev_fan_speed  | |  sm . frame  %  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 ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      cur_integ_lines  =  integ_lines_filter . update ( cur_integ_lines ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      last_driver_camera_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 on input timeout
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( nanos_since_boot ( )  -  last_driver_camera_t  >  1e9 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      ir_pwr  =  0 ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ir_pwr  ! =  prev_ir_pwr  | |  sm . frame  %  100  = =  0  | |  ir_pwr  > =  50.0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      panda - > set_ir_pwr ( ir_pwr ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								      Hardware : : set_ir_power ( ir_pwr ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      prev_ir_pwr  =  ir_pwr ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  pandad_run ( std : : vector < Panda  * >  & pandas )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  bool  no_fan_control  =  getenv ( " NO_FAN_CONTROL " )  ! =  nullptr ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  bool  spoofing_started  =  getenv ( " STARTED " )  ! =  nullptr ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  bool  fake_send  =  getenv ( " FAKESEND " )  ! =  nullptr ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // Start the CAN send thread
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : thread  send_thread ( can_send_thread ,  pandas ,  fake_send ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  RateKeeper  rk ( " pandad " ,  100 ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  SubMaster  sm ( { " selfdriveState " } ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  PubMaster  pm ( { " can " ,  " pandaStates " ,  " peripheralState " } ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  PandaSafety  panda_safety ( pandas ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  Panda  * peripheral_panda  =  pandas [ 0 ] ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  bool  engaged  =  false ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // Main loop: receive CAN data and process states
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  while  ( ! do_exit  & &  check_all_connected ( pandas ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    can_recv ( pandas ,  & pm ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Process peripheral state at 20 Hz
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( rk . frame ( )  %  5  = =  0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      process_peripheral_state ( peripheral_panda ,  & pm ,  no_fan_control ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Process panda state at 10 Hz
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( rk . frame ( )  %  10  = =  0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								      sm . update ( 0 ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      engaged  =  sm . allAliveAndValid ( { " selfdriveState " } )  & &  sm [ " selfdriveState " ] . getSelfdriveState ( ) . getEnabled ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      process_panda_state ( pandas ,  & pm ,  engaged ,  spoofing_started ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								      panda_safety . configureSafetyMode ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Send out peripheralState at 2Hz
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( rk . frame ( )  %  50  = =  0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      send_peripheral_state ( peripheral_panda ,  & pm ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    // Forward logs from pandas to cloudlog if available
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( auto  * panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      std : : string  log  =  panda - > serial_read ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( ! log . empty ( ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        LOGD ( " %s " ,  log . c_str ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    rk . keepTime ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  // Close relay on exit to prevent a fault
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  bool  is_onroad  =  Params ( ) . getBool ( " IsOnroad " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( is_onroad  & &  ! engaged )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  ( auto  & p  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( p - > connected ( ) )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        p - > set_safety_model ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								  send_thread . join ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  pandad_main_thread ( std : : vector < std : : string >  serials )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( serials . size ( )  = =  0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    serials  =  Panda : : list ( ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( serials . size ( )  = =  0 )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      LOGW ( " no pandas found, exiting " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      return ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : string  serials_str ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( int  i  =  0 ;  i  <  serials . size ( ) ;  i + + )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    serials_str  + =  serials [ i ] ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( i  <  serials . size ( )  -  1 )  serials_str  + =  " ,  " ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  LOGW ( " connecting to pandas: %s " ,  serials_str . c_str ( ) ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  // connect to all provided serials
  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  std : : vector < Panda  * >  pandas ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( int  i  =  0 ;  i  <  serials . size ( )  & &  ! do_exit ;  /**/ )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    Panda  * p  =  connect ( serials [ i ] ,  i ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! p )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      util : : sleep_for ( 100 ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      continue ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pandas . push_back ( p ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    + + i ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( ! do_exit )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    LOGW ( " connected to all pandas " ) ; 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    pandad_run ( pandas ) ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( Panda  * panda  :  pandas )  { 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    delete  panda ; 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}