You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					132 lines
				
				4.7 KiB
			
		
		
			
		
	
	
					132 lines
				
				4.7 KiB
			| 
								 
											7 years ago
										 
									 | 
							
								### old can parser just used by plant.py for regression tests
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								import os
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								import opendbc
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								from collections import defaultdict
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								from selfdrive.car.honda.hondacan import fix
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								from common.realtime import sec_since_boot
							 | 
						||
| 
								 | 
							
								from common.dbc import dbc
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CANParser(object):
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								  def __init__(self, dbc_f, signals, checks=None):
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    ### 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.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								    checks = [] if checks is None else checks
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								    self.msgs_ck = set([check[0] for check in checks])
							 | 
						||
| 
								 | 
							
								    self.frqs = dict(checks)
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    self.can_valid = False  # start with False CAN assumption
							 | 
						||
| 
								 | 
							
								    # list of received msg we want to monitor counter and checksum for
							 | 
						||
| 
								 | 
							
								    # read dbc file
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								    self.can_dbc = dbc(os.path.join(opendbc.DBC_PATH, dbc_f))
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    # 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] = {}
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								      self.ts[addr] = {}
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								      self.ct[addr] = sec_since_boot()
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								      self.ok[addr] = True
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								      self.cn[addr] = 0
							 | 
						||
| 
								 | 
							
								      self.cn_vl[addr] = 0
							 | 
						||
| 
								 | 
							
								      self.ck[addr] = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for name, addr, ival in signals:
							 | 
						||
| 
								 | 
							
								      self.vl[addr][name] = ival
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								      self.ts[addr][name] = 0
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    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):
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    msgs_upd = []
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    cn_vl_max = 5   # no more than 5 wrong counter checks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								    self.sec_since_boot_cached = sec_since_boot()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    # we are subscribing to PID_XXX, else data from USB
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    for msg, ts, cdat, _ in can_recv:
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								      idxs = self._message_indices[msg]
							 | 
						||
| 
								 | 
							
								      if idxs:
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								        msgs_upd.append(msg)
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								        # read the entire message
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								        out = self.can_dbc.decode((msg, 0, cdat))[1]
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								        # checksum check
							 | 
						||
| 
								 | 
							
								        self.ck[msg] = True
							 | 
						||
| 
								 | 
							
								        if "CHECKSUM" in out.keys() and msg in self.msgs_ck:
							 | 
						||
| 
								 | 
							
								          # remove checksum (half byte)
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								          ck_portion = cdat[:-1] + chr(ord(cdat[-1]) & 0xF0)
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								          # recalculate checksum
							 | 
						||
| 
								 | 
							
								          msg_vl = fix(ck_portion, msg)
							 | 
						||
| 
								 | 
							
								          # compare recalculated vs received checksum
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								          if msg_vl != cdat:
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								            print "CHECKSUM FAIL: " + hex(msg)
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								            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 hex(msg), "FAILED COUNTER!"
							 | 
						||
| 
								 | 
							
								          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:
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								          print "COUNTER WRONG: " + hex(msg)
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								          self.ok[msg] = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # update msg time stamps and counter value
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								        self.ct[msg] = self.sec_since_boot_cached
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								        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]
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								          self.ts[msg][sg] = ts
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    # for each message, check if it's too long since last time we received it
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    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
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    if False in self.ok.values():
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								      #print "CAN INVALID!"
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								      self.can_valid = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								    return msgs_upd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								  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):
							 | 
						||
| 
								 
											8 years ago
										 
									 | 
							
								      if msg in self.msgs_ck and self.sec_since_boot_cached - self.ct[msg] > 10./self.frqs[msg]:
							 | 
						||
| 
								 
											9 years ago
										 
									 | 
							
								        self.ok[msg] = False
							 |