def fingerprint(logcan, timeout): if os.getenv("SIMULATOR") is not None or logcan is None: return ("simulator", None) elif os.getenv("SIMULATOR2") is not None: return ("simulator2", None) finger_st = sec_since_boot() cloudlog.warning("waiting for fingerprint...") candidate_cars = all_known_cars() finger = {} st = None while 1: for a in messaging.drain_sock(logcan, wait_for_one=True): if st is None: st = sec_since_boot() for can in a.can: if can.src == 0: finger[can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars( can, candidate_cars) ts = sec_since_boot() # if we only have one car choice and it's been 100ms since we got our first message, exit if len(candidate_cars) == 1 and st is not None and (ts - st) > 0.1: break # bail if no cars left or we've been waiting too long elif len(candidate_cars) == 0 or (timeout and ts - finger_st > timeout): return None, finger cloudlog.warning("fingerprinted %s", candidate_cars[0]) return (candidate_cars[0], finger)
def fingerprint(logcan, timeout): if os.getenv("SIMULATOR2") is not None: return ("simulator2", None) finger_st = sec_since_boot() cloudlog.warning("waiting for fingerprint...") candidate_cars = all_known_cars() finger = {} st = None while 1: for a in messaging.drain_sock(logcan, wait_for_one=True): if st is None: st = sec_since_boot() for can in a.can: if can.src == 0: finger[can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars(can, candidate_cars) ts = sec_since_boot() # if we only have one car choice and the time_fingerprint since we got our first # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not # broadcast immediately if len(candidate_cars) == 1 and st is not None: # TODO: better way to decide to wait more if Toyota time_fingerprint = 1.0 if ("TOYOTA" in candidate_cars[0] or "LEXUS" in candidate_cars[0]) else 0.1 if (ts-st) > time_fingerprint: break # bail if no cars left or we've been waiting too long elif len(candidate_cars) == 0 or (timeout and ts-finger_st > timeout): return None, finger cloudlog.warning("fingerprinted %s", candidate_cars[0]) return (candidate_cars[0], finger)
def fingerprint(logcan, timeout): if os.getenv("SIMULATOR2") is not None: return ("simulator2", None) elif os.getenv("SIMULATOR") is not None: return ("simulator", None) cloudlog.warning("waiting for fingerprint...") candidate_cars = all_known_cars() finger = {} st = None st_passive = sec_since_boot() # only relevant when passive can_seen = False while 1: for a in messaging.drain_sock(logcan): for can in a.can: can_seen = True # ignore everything not on bus 0 and with more than 11 bits, # which are ussually sporadic and hard to include in fingerprints if can.src == 0 and can.address < 0x800: finger[can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars( can, candidate_cars) if st is None and can_seen: st = sec_since_boot() # start time ts = sec_since_boot() # if we only have one car choice and the time_fingerprint since we got our first # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not # broadcast immediately if len(candidate_cars) == 1 and st is not None: # TODO: better way to decide to wait more if Toyota time_fingerprint = 1.0 if ("TOYOTA" in candidate_cars[0] or "LEXUS" in candidate_cars[0]) else 0.1 if (ts - st) > time_fingerprint: break # bail if no cars left or we've been waiting too long elif len(candidate_cars) == 0 or (timeout and (ts - st_passive) > timeout): #return None, finger print "Fingerprinting Failed: Returning Tesla (based on branch)" return "TESLA MODEL S", finger time.sleep(0.01) cloudlog.warning("fingerprinted %s", candidate_cars[0]) return (candidate_cars[0], finger)
def fingerprint(logcan, sendcan, is_panda_black): if os.getenv("SIMULATOR2") is not None: return ("simulator2", None, "") elif os.getenv("SIMULATOR") is not None: return ("simulator", None, "") params = Params() car_params = params.get("CarParams") if car_params is not None: # use already stored VIN: a new VIN query cannot be done, since panda isn't in ELM327 mode car_params = car.CarParams.from_bytes(car_params) vin = VIN_UNKNOWN if car_params.carVin == "" else car_params.carVin elif is_panda_black: # Vin query only reliably works thorugh OBDII vin = get_vin(logcan, sendcan, 1) else: vin = VIN_UNKNOWN cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) finger = {i: {} for i in range(0, 4)} # collect on all buses candidate_cars = {i: all_known_cars() for i in [0, 1] } # attempt fingerprint on both bus 0 and 1 frame = 0 frame_fingerprint = 10 # 0.1s car_fingerprint = None done = False while not done: a = messaging.recv_one(logcan) for can in a.can: # need to independently try to fingerprint both bus 0 and 1 to work # for the combo black_panda and honda_bosch. Ignore extended messages # and VIN query response. # Include bus 2 for toyotas to disambiguate cars using camera messages # (ideally should be done for all cars but we can't for Honda Bosch) for b in candidate_cars: if (can.src == b or (only_toyota_left(candidate_cars[b]) and can.src == 2)) and \ can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]: finger[can.src][can.address] = len(can.dat) candidate_cars[b] = eliminate_incompatible_cars( can, candidate_cars[b]) # if we only have one car choice and the time since we got our first # message has elapsed, exit for b in candidate_cars: # Toyota needs higher time to fingerprint, since DSU does not broadcast immediately if only_toyota_left(candidate_cars[b]): frame_fingerprint = 100 # 1s if len(candidate_cars[b]) == 1: if frame > frame_fingerprint: # fingerprint done car_fingerprint = candidate_cars[b][0] # bail if no cars left or we've been waiting for more than 2s failed = all(len(cc) == 0 for cc in candidate_cars.itervalues()) or frame > 200 succeeded = car_fingerprint is not None done = failed or succeeded frame += 1 cloudlog.warning("fingerprinted %s", car_fingerprint) return car_fingerprint, finger, vin
def fingerprint(logcan, sendcan): if os.getenv("SIMULATOR2") is not None: return ("simulator2", None, "") elif os.getenv("SIMULATOR") is not None: return ("simulator", None, "") finger = {} cloudlog.warning("waiting for fingerprint...") candidate_cars = all_known_cars() can_seen_ts = None can_seen = False # works on standard 11-bit addresses for diagnostic. Tested on Toyota and Subaru; # Honda uses the extended 29-bit addresses, and unfortunately only works from OBDII vin_query_msg = [[0x7df, 0, '\x02\x09\x02'.ljust(8, "\x00"), 0], [0x7e0, 0, '\x30'.ljust(8, "\x00"), 0]] vin_cnts = [1, 2] # number of messages to wait for at each iteration vin_step = 0 vin_cnt = 0 vin_responded = False vin_never_responded = True vin_dat = [] vin = "" while 1: for a in messaging.drain_sock(logcan): for can in a.can: can_seen = True # have we got a VIN query response? if can.src == 0 and can.address == 0x7e8: vin_never_responded = False # basic sanity checks on ISO-TP response if is_vin_response_valid(can.dat, vin_step, vin_cnt): vin_dat += can.dat[2:] if vin_step == 0 else can.dat[1:] vin_cnt += 1 if vin_cnt == vin_cnts[vin_step]: vin_responded = True vin_step += 1 # ignore everything not on bus 0 and with more than 11 bits, # which are ussually sporadic and hard to include in fingerprints. # also exclude VIN query response on 0x7e8 if can.src == 0 and can.address < 0x800 and can.address != 0x7e8: finger[can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars( can, candidate_cars) if can_seen_ts is None and can_seen: can_seen_ts = sec_since_boot() # start time ts = sec_since_boot() # if we only have one car choice and the time_fingerprint since we got our first # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not # broadcast immediately if len(candidate_cars) == 1 and can_seen_ts is not None: time_fingerprint = 1.0 if ("TOYOTA" in candidate_cars[0] or "LEXUS" in candidate_cars[0]) else 0.1 if (ts - can_seen_ts) > time_fingerprint: break # bail if no cars left or we've been waiting for more than 2s since can_seen elif len(candidate_cars) == 0 or (can_seen_ts is not None and (ts - can_seen_ts) > 2.): return None, finger, "" # keep sending VIN qury if ECU isn't responsing. # sendcan is probably not ready due to the zmq slow joiner syndrome if can_seen and (vin_never_responded or (vin_responded and vin_step < len(vin_cnts))): sendcan.send( can_list_to_can_capnp([vin_query_msg[vin_step]], msgtype='sendcan')) vin_responded = False vin_cnt = 0 time.sleep(0.01) # only report vin if procedure is finished if vin_step == len(vin_cnts) and vin_cnt == vin_cnts[-1]: vin = "".join(vin_dat[3:]) cloudlog.warning("fingerprinted %s", candidate_cars[0]) cloudlog.warning("VIN %s", vin) return candidate_cars[0], finger, vin
def fingerprint(logcan, sendcan): if os.getenv("SIMULATOR2") is not None: return ("simulator2", None, "") elif os.getenv("SIMULATOR") is not None: return ("simulator", None, "") finger = {0: {}, 2: {}} # collect on bus 0 or 2 cloudlog.warning("waiting for fingerprint...") candidate_cars = all_known_cars() can_seen_frame = None can_seen = False # works on standard 11-bit addresses for diagnostic. Tested on Toyota and Subaru; # Honda uses the extended 29-bit addresses, and unfortunately only works from OBDII vin_query_msg = [[0x7df, 0, '\x02\x09\x02'.ljust(8, "\x00"), 0], [0x7e0, 0, '\x30'.ljust(8, "\x00"), 0]] vin_cnts = [1, 2] # number of messages to wait for at each iteration vin_step = 0 vin_cnt = 0 vin_responded = False vin_never_responded = True vin_dat = [] vin = "" frame = 0 while True: a = messaging.recv_one(logcan) for can in a.can: can_seen = True # have we got a VIN query response? if can.src == 0 and can.address == 0x7e8: vin_never_responded = False # basic sanity checks on ISO-TP response if is_vin_response_valid(can.dat, vin_step, vin_cnt): vin_dat += can.dat[2:] if vin_step == 0 else can.dat[1:] vin_cnt += 1 if vin_cnt == vin_cnts[vin_step]: vin_responded = True vin_step += 1 # ignore everything not on bus 0 and with more than 11 bits, # which are ussually sporadic and hard to include in fingerprints. # also exclude VIN query response on 0x7e8. # Include bus 2 for toyotas to disambiguate cars using camera messages # (ideally should be done for all cars but we can't for Honda Bosch) if (can.src == 0 or (only_toyota_left(candidate_cars) and can.src == 2)) and \ can.address < 0x800 and can.address != 0x7e8: finger[can.src][can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars( can, candidate_cars) if can_seen_frame is None and can_seen: can_seen_frame = frame # if we only have one car choice and the time_fingerprint since we got our first # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not # broadcast immediately if len(candidate_cars) == 1 and can_seen_frame is not None: time_fingerprint = 1.0 if only_toyota_left(candidate_cars) else 0.1 if (frame - can_seen_frame) > (time_fingerprint * 100): break # bail if no cars left or we've been waiting for more than 2s since can_seen elif len(candidate_cars) == 0 or (can_seen_frame is not None and (frame - can_seen_frame) > 200): return None, finger, "" # keep sending VIN qury if ECU isn't responsing. # sendcan is probably not ready due to the zmq slow joiner syndrome # TODO: VIN query temporarily disabled until we have the harness if False and can_seen and (vin_never_responded or (vin_responded and vin_step < len(vin_cnts))): sendcan.send( can_list_to_can_capnp([vin_query_msg[vin_step]], msgtype='sendcan')) vin_responded = False vin_cnt = 0 frame += 1 # only report vin if procedure is finished if vin_step == len(vin_cnts) and vin_cnt == vin_cnts[-1]: vin = "".join(vin_dat[3:]) cloudlog.warning("fingerprinted %s", candidate_cars[0]) cloudlog.warning("VIN %s", vin) return candidate_cars[0], finger, vin
msgs = {} """"" while True: lc = messaging.recv_sock(logcan, True) for c in lc.can: # read also msgs sent by EON on CAN bus 0x80 and filter out the # addr with more than 11 bits if c.src%0x80 == 0 and c.address < 0x800: msgs[c.address] = len(c.dat) fingerprint = ', '.join("%d: %d" % v for v in sorted(msgs.items())) print "number of messages:", len(msgs) print "fingerprint", fingerprint """ "" candidate_cars = all_known_cars() finger = {} st = None st_passive = sec_since_boot() # only relevant when passive can_seen = False i = 100 while i: i = i - 1 for a in messaging.drain_sock(logcan): for can in a.can: can_seen = True # ignore everything not on bus 0 and with more than 11 bits, # which are ussually sporadic and hard to include in fingerprints if can.src == 0 and can.address < 0x800: finger[can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars(
def fingerprint(logcan, timeout): if os.getenv("SIMULATOR2") is not None: return ("simulator2", None) elif os.getenv("SIMULATOR") is not None: return ("simulator", None) params = Params() cached_fingerprint = params.get('CachedFingerprint') if cached_fingerprint is not None and kegman.get( "useCarCaching", True ): # if we previously identified a car and fingerprint and user hasn't disabled caching cached_fingerprint = json.loads(cached_fingerprint) try: with open("/data/kegman.json", "r") as f: cloudlog.warning(str(f.read())) except: pass try: with open("/data/params/d/ControlsParams", "r") as f: cloudlog.warning(f.read()) except: pass try: with open("/data/params/d/LiveParameters", "r") as f: cloudlog.warning(f.read()) except: pass return (str(cached_fingerprint[0]), { long(key): value for key, value in cached_fingerprint[1].items() }) # not sure if dict of longs is required cloudlog.warning("waiting for fingerprint...") candidate_cars = all_known_cars() finger = {} st = None st_passive = sec_since_boot() # only relevant when passive can_seen = False while 1: for a in messaging.drain_sock(logcan): for can in a.can: can_seen = True # ignore everything not on bus 0 and with more than 11 bits, # which are ussually sporadic and hard to include in fingerprints if can.src == 0 and can.address < 0x800: finger[can.address] = len(can.dat) candidate_cars = eliminate_incompatible_cars( can, candidate_cars) if st is None and can_seen: st = sec_since_boot() # start time ts = sec_since_boot() # if we only have one car choice and the time_fingerprint since we got our first # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not # broadcast immediately if len(candidate_cars) == 1 and st is not None: # TODO: better way to decide to wait more if Toyota time_fingerprint = 1.0 if ("TOYOTA" in candidate_cars[0] or "LEXUS" in candidate_cars[0]) else 0.1 if (ts - st) > time_fingerprint: break # bail if no cars left or we've been waiting too long elif len(candidate_cars) == 0 or (timeout and (ts - st_passive) > timeout): return None, finger time.sleep(0.01) try: with open("/data/kegman.json", "r") as f: cloudlog.warning(str(f.read())) except: pass try: with open("/data/params/d/ControlsParams", "r") as f: cloudlog.warning(f.read()) except: pass try: with open("/data/params/d/LiveParameters", "r") as f: cloudlog.warning(f.read()) except: pass cloudlog.warning("fingerprinted %s", candidate_cars[0]) params.put("CachedFingerprint", json.dumps([ candidate_cars[0], {int(key): value for key, value in finger.items()} ])) # probably can remove long to int conversion return (candidate_cars[0], finger)
"975b26878285314d|2018-12-25--14-42-13", # CHRYSLER PACIFICA HYBRID 2018 "8ae193ceb56a0efe|2018-06-18--20-07-32", # TOYOTA RAV4 HYBRID 2017 "a893a80e5c5f72c8|2019-01-14--20-02-59", # HYUNDAI GENESIS 2018 "49c73650e65ff465|2018-11-19--16-58-04", # HOLDEN ASTRA RS-V BK 2017 "d2d8152227f7cb82|2018-07-25--13-40-56", # TOYOTA CAMRY 2018 "07cb8a788c31f645|2018-06-17--18-50-29", # mock "c9d60e5e02c04c5c|2018-01-08--16-01-49", # HONDA CR-V 2016 TOURING "1632088eda5e6c4d|2018-06-07--08-03-18", # HONDA CIVIC HATCHBACK 2017 SEDAN/COUPE 2019 "fbd011384db5e669|2018-07-26--20-51-48", # TOYOTA CAMRY HYBRID 2018 ] if __name__ == "__main__": # TODO: add routes for untested cars and fail test if we have an untested car tested_cars = [keys["carFingerprint"] for route, keys in routes.items()] for car_model in all_known_cars(): if car_model not in tested_cars: print "***** WARNING: %s not tested *****" % car_model results = {} for route, checks in routes.items(): if route not in non_public_routes: get_route_logs(route) elif "UNLOGGER_PATH" not in os.environ: continue for _ in range(3): shutil.rmtree('/data/params') manager.gctx = {} params = Params() params.manager_start()