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.
		
		
		
		
		
			
		
			
				
					
					
						
							131 lines
						
					
					
						
							4.7 KiB
						
					
					
				
			
		
		
	
	
							131 lines
						
					
					
						
							4.7 KiB
						
					
					
				| ### 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: " + 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 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:
 | |
|           print "COUNTER WRONG: " + 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
 | |
| 
 |