import  os 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  time 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  shutil 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  datetime  import  datetime 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  collections  import  defaultdict 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  rpyc  # pylint: disable=import-error 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  rpyc . utils . server  import  ThreadedServer   # pylint: disable=import-error 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#from common.params import Params 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  cereal . messaging  as  messaging 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  selfdrive . manager . process_config  import  managed_processes 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  laika . lib . coordinates  import  ecef2geodetic 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								DELTA  =  0.001 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ALT_DELTA  =  30 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MATCH_NUM  =  10 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								REPORT_STATS  =  10 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								EPHEM_CACHE  =  " /data/params/d/LaikadEphemerisV3 " 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								DOWNLOAD_CACHE  =  " /tmp/comma_download_cache " 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								SERVER_LOG_FILE  =  " /tmp/fuzzy_server.log " 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								server_log  =  open ( SERVER_LOG_FILE ,  " w+ " ) 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  slog ( msg ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  server_log . write ( f " { datetime . now ( ) . strftime ( ' % H: % M: % S. %f ' ) }  |  { msg } \n " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  server_log . flush ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  handle_laikad ( msg ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  not  hasattr ( msg ,  ' correctedMeasurements ' ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  None 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  num_corr  =  len ( msg . correctedMeasurements ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pos_ecef  =  msg . positionECEF . value 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pos_geo  =  [ ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  len ( pos_ecef )  >  0 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pos_geo  =  ecef2geodetic ( pos_ecef ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pos_std  =  msg . positionECEF . std 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pos_valid  =  msg . positionECEF . valid 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  slog ( f " { num_corr }   { pos_geo }   { pos_ecef }   { pos_std }   { pos_valid } " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  pos_geo ,  ( num_corr ,  pos_geo ,  list ( pos_ecef ) ,  list ( msg . positionECEF . std ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								hw_msgs  =  0 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								ephem_msgs :  dict  =  defaultdict ( int ) 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  handle_ublox ( msg ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  global  hw_msgs 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  d  =  msg . to_dict ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ' hwStatus2 '  in  d : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    hw_msgs  + =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ' ephemeris '  in  d : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ephem_msgs [ msg . ephemeris . svId ]  + =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  num_meas  =  None 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ' measurementReport '  in  d : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    num_meas  =  msg . measurementReport . numMeas 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  [ hw_msgs ,  ephem_msgs ,  num_meas ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  start_procs ( procs ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  for  p  in  procs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    managed_processes [ p ] . start ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  time . sleep ( 1 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  kill_procs ( procs ,  no_retry = False ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  for  p  in  procs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    managed_processes [ p ] . stop ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  time . sleep ( 1 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  not  no_retry : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  p  in  procs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      mp  =  managed_processes [ p ] . proc 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  mp  is  not  None  and  mp . is_alive ( ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        managed_processes [ p ] . stop ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    time . sleep ( 3 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  check_alive_procs ( procs ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  for  p  in  procs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    mp  =  managed_processes [ p ] . proc 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  mp  is  None  or  not  mp . is_alive ( ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  False ,  p 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  True ,  None 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  RemoteCheckerService ( rpyc . Service ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  on_connect ( self ,  conn ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pass 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  on_disconnect ( self ,  conn ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    #kill_procs(self.procs, no_retry=False) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # this execution is delayed, it will kill the next run of laikad 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # TODO: add polling to wait for everything is killed 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pass 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  run_checker ( self ,  slat ,  slon ,  salt ,  sockets ,  procs ,  timeout ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    global  hw_msgs ,  ephem_msgs 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    hw_msgs  =  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ephem_msgs  =  defaultdict ( int ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    slog ( f " Run test:  { slat }   { slon }   { salt } " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # quectel_mod = Params().get_bool("UbloxAvailable") 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    match_cnt  =  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    msg_cnt  =  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    stats_laikad  =  [ ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    stats_ublox  =  [ ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . procs  =  procs 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    start_procs ( procs ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    sm  =  messaging . SubMaster ( sockets ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    start_time  =  time . monotonic ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  True : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      sm . update ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  sm . updated [ ' ubloxGnss ' ] : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        stats_ublox . append ( handle_ublox ( sm [ ' ubloxGnss ' ] ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  sm . updated [ ' gnssMeasurements ' ] : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        pos_geo ,  stats  =  handle_laikad ( sm [ ' gnssMeasurements ' ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  pos_geo  is  None  or  len ( pos_geo )  ==  0 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          continue 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        match   =  all ( abs ( g - s )  <  DELTA  for  g , s  in  zip ( pos_geo [ : 2 ] ,  [ slat ,  slon ] ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        match  & =  abs ( pos_geo [ 2 ]  -  salt )  <  ALT_DELTA 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  match : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          match_cnt  + =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  match_cnt  > =  MATCH_NUM : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  True ,  " MATCH " ,  f " After:  { round ( time . monotonic ( )  -  start_time ,  4 ) } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # keep some stats for error reporting 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        stats_laikad . append ( stats ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( msg_cnt  %  10 )  ==  0 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        a ,  p  =  check_alive_procs ( procs ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  not  a : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          return  False ,  " PROC CRASH " ,  f " { p } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      msg_cnt  + =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( time . monotonic ( )  -  start_time )  >  timeout : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        h  =  f " LAIKAD:  { stats_laikad [ - REPORT_STATS : ] } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  len ( h )  ==  0 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          h  =  f " UBLOX:  { stats_ublox [ - REPORT_STATS : ] } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  False ,  " TIMEOUT " ,  h 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  exposed_run_checker ( self ,  slat ,  slon ,  salt ,  timeout = 180 ,  use_laikad = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      procs  =  [ ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      sockets  =  [ ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  use_laikad : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        procs . append ( " laikad " )  # pigeond, ubloxd # might wanna keep them running 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        sockets  + =  [ ' ubloxGnss ' ,  ' gnssMeasurements ' ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  os . path . exists ( EPHEM_CACHE ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          os . remove ( EPHEM_CACHE ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        shutil . rmtree ( DOWNLOAD_CACHE ,  ignore_errors = True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ret  =  self . run_checker ( slat ,  slon ,  salt ,  sockets ,  procs ,  timeout ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      kill_procs ( procs ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ret 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    except  Exception  as  e : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # always make sure processes get killed 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      kill_procs ( procs ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  False ,  " CHECKER CRASHED " ,  f " { str ( e ) } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  exposed_kill_procs ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    kill_procs ( self . procs ,  no_retry = True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								if  __name__  ==  " __main__ " : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  print ( f " Sever Log written to:  { SERVER_LOG_FILE } " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  t  =  ThreadedServer ( RemoteCheckerService ,  port = 18861 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  t . start ( )