### old can parser just used by plant.py for regression tests 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								import  os 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								import  opendbc 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								from  collections  import  defaultdict 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								from  selfdrive . car . honda . hondacan  import  fix 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								from  common . realtime  import  sec_since_boot 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								from  common . dbc  import  dbc 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								class  CANParser ( object ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  def  __init__ ( self ,  dbc_f ,  signals ,  checks = None ) : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ### input: 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # dbc_f   : dbc file 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # signals : List of tuples (name, address, ival) where 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    #             - name is the signal name. 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    #             - address is the corresponding message address. 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    #             - ival is the initial value. 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # checks  : List of pairs (address, frequency) where 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    #             - address is the message address of a message for which health should be 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    #               monitored. 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    #             - frequency is the frequency at which health should be monitored. 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    checks  =  [ ]  if  checks  is  None  else  checks 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . msgs_ck  =  set ( [ check [ 0 ]  for  check  in  checks ] ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . frqs  =  dict ( checks ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . can_valid  =  False   # start with False CAN assumption 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # list of received msg we want to monitor counter and checksum for 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # read dbc file 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . can_dbc  =  dbc ( os . path . join ( opendbc . DBC_PATH ,  dbc_f ) ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # initialize variables to initial values 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . vl  =  { }     # signal values 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . ts  =  { }     # time stamp recorded in log 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . ct  =  { }     # current time stamp 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . ok  =  { }     # valid message? 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . cn  =  { }     # message counter 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . cn_vl  =  { }  # message counter mismatch value 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . ck  =  { }     # message checksum status 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  _ ,  addr ,  _  in  signals : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . vl [ addr ]  =  { } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . ts [ addr ]  =  { } 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . ct [ addr ]  =  sec_since_boot ( ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . ok [ addr ]  =  True 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . cn [ addr ]  =  0 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . cn_vl [ addr ]  =  0 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . ck [ addr ]  =  False 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  name ,  addr ,  ival  in  signals : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . vl [ addr ] [ name ]  =  ival 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . ts [ addr ] [ name ]  =  0 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . _msgs  =  [ s [ 1 ]  for  s  in  signals ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . _sgs  =  [ s [ 0 ]  for  s  in  signals ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . _message_indices  =  defaultdict ( list ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  i ,  x  in  enumerate ( self . _msgs ) : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . _message_indices [ x ] . append ( i ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  def  update_can ( self ,  can_recv ) : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    msgs_upd  =  [ ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    cn_vl_max  =  5    # no more than 5 wrong counter checks 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . sec_since_boot_cached  =  sec_since_boot ( ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # we are subscribing to PID_XXX, else data from USB 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  msg ,  ts ,  cdat ,  _  in  can_recv : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      idxs  =  self . _message_indices [ msg ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  idxs : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        msgs_upd . append ( msg ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # read the entire message 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        out  =  self . can_dbc . decode ( ( msg ,  0 ,  cdat ) ) [ 1 ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # checksum check 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        self . ck [ msg ]  =  True 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  " CHECKSUM "  in  out . keys ( )  and  msg  in  self . msgs_ck : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          # remove checksum (half byte) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          ck_portion  =  cdat [ : - 1 ]  +  chr ( ord ( cdat [ - 1 ] )  &  0xF0 ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          # recalculate checksum 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          msg_vl  =  fix ( ck_portion ,  msg ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          # compare recalculated vs received checksum 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          if  msg_vl  !=  cdat : 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            print ( " CHECKSUM FAIL:  {0} " . format ( hex ( msg ) ) ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            self . ck [ msg ]  =  False 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            self . ok [ msg ]  =  False 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # counter check 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        cn  =  0 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  " COUNTER "  in  out . keys ( ) : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          cn  =  out [ " COUNTER " ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # check counter validity if it's a relevant message 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  cn  !=  ( ( self . cn [ msg ]  +  1 )  %  4 )  and  msg  in  self . msgs_ck  and  " COUNTER "  in  out . keys ( ) : 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								          #print("FAILED COUNTER: {0}".format(hex(msg)() 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          self . cn_vl [ msg ]  + =  1    # counter check failed 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        else : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          self . cn_vl [ msg ]  - =  1    # counter check passed 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # message status is invalid if we received too many wrong counter values 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  self . cn_vl [ msg ]  > =  cn_vl_max : 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								          print ( " COUNTER WRONG:  {0} " . format ( hex ( msg ) ) ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          self . ok [ msg ]  =  False 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # update msg time stamps and counter value 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        self . ct [ msg ]  =  self . sec_since_boot_cached 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        self . cn [ msg ]  =  cn 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        self . cn_vl [ msg ]  =  min ( max ( self . cn_vl [ msg ] ,  0 ) ,  cn_vl_max ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # set msg valid status if checksum is good and wrong counter counter is zero 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  self . ck [ msg ]  and  self . cn_vl [ msg ]  ==  0 : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          self . ok [ msg ]  =  True 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        # update value of signals in the 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        for  ii  in  idxs : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          sg  =  self . _sgs [ ii ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          self . vl [ msg ] [ sg ]  =  out [ sg ] 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          self . ts [ msg ] [ sg ]  =  ts 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # for each message, check if it's too long since last time we received it 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . _check_dead_msgs ( ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # assess overall can validity: if there is one relevant message invalid, then set can validity flag to False 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    self . can_valid  =  True 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  False  in  self . ok . values ( ) : 
 
							 
						 
					
						
							
								
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								      #print("CAN INVALID!") 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      self . can_valid  =  False 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  msgs_upd 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  def  _check_dead_msgs ( self ) : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ### input: 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ## simple stuff for now: msg is not valid if a message isn't received for 10 consecutive steps 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for  msg  in  set ( self . _msgs ) : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  msg  in  self . msgs_ck  and  self . sec_since_boot_cached  -  self . ct [ msg ]  >  10. / self . frqs [ msg ] : 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        self . ok [ msg ]  =  False